Skip to main content

News

Topic: Sphere v2 API discussion (Read 34557 times) previous topic - next topic

0 Members and 1 Guest are viewing this topic.
  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Sphere v2 API discussion
The release of minisphere 4.0 is imminent.  This version will introduce a brand-new API, dubbed "Sphere v2".  Sphere v2 is a complete reimagining of the Sphere API and I'd like to get some input on the different aspects of it before it's finalized in minisphere 5.0, locking us into backwards compatibility.

Note that Sphere v1 functions will still be available for the foreseeable future and can be freely used side-by-side with the new API, easing some of the pain of migration for existing large Sphere codebases.

I'll post more here in the coming days, but to kickstart the discussion, here is the API documentation for Sphere v2 as it currently exists in the minisphere Git repository:
https://github.com/fatcerberus/minisphere/blob/master/docs/sphere2-core-api.txt
  • Last Edit: August 24, 2017, 02:42:05 am by Fat Cerberus
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

Re: Sphere v2 API discussion
Reply #1
Just skimming, a few ideas:


  • Resolution should probably use actual numbers in JSON, like "resolution":{"w":320, "h":480}

  • Shouldn't time be a function? It's a little strange to have a monotonically increasing variable.

  • No kb.getString(key, shift)?

  • The argument order of Shape.draw() is a little strange. Maybe it would be better to have a shape.surfaceDraw() or shape.transformDraw() as well, since otherwise there are two default variables, either of which you may want to exclude? I would think it would be better to have two obvious functions than one weird one.

  • No support for vertex attributes in glsl?

  • You should probably add a caveat about socket.bytesPending()




  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #2
I agree re: resolution in JSON, I can change that before release.  I originally likes the elegance of representing resolution as a single string, but it's error prone this way, particularly if the json file is made by hand.

kb.getString() is there, except I named it kb.keyString() instead.  Not sure which name is better, probably getString.

I'm on the fence about engine.time.  On the one hand it saves some typing, but it is a little odd that if it occurs more than once on the same line of code it can end up representing different values (since it's usually sub-microsecond precision).  Ultimately you're probably right that it should be a function.

I'll look into vertex attributes, I didn't know that much about them so I left them out.

For Shape.draw(), it's worth noting that Node.js API is full of functions like this, where you can leave out one or more of the default arguments (even those in the middle) and it still works.  However in this case at least it is kind of awkward.  I'll see if I can come up with a better design.

What do you mean about a caveat for Socket.bytesPending?
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

Re: Sphere v2 API discussion
Reply #3

What do you mean about a caveat for Socket.bytesPending?


It isn't an API issue, but if you are writing documentation you should probably mention that this value can be stale by the time you actually perform a read. It's good to have people new to networking keep things like that in mind, and it's not bad to remind more experienced folks, too.


kb.getString() is there, except I named it kb.keyString() instead.  Not sure which name is better, probably getString.


Ah, I just didn't see it then.

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #4
Looking at Shape#draw() again, there is actually only one optional parameter--the transformation.  The surface is actually required; if you want to draw to the backbuffer, you just pass screen (which is a Surface).  So it should actually be okay the way it is.

One thing I want to highlight is the new RNG API.  I mentioned it in the minisphere thread, but didn't really go into detail on it.  Here's the API:
https://github.com/fatcerberus/minisphere/blob/master/docs/spherical-api.txt#L177-L221

It's based on the xoroshiro128+ generator and allows you to create multiple independently seeded random number generators.  Each RNG object exposes a state property which lets you save and restore the current position of that generator in its sequence.  This can be used to prevent save system abuse ("save scumming").  For example you could have an RNG which is used to determine the contents of random chests.  The state of this one would be stored in your save file so that you can't reload to get a different item.

Likewise, having independent generators is useful for preventing abuse.  A common exploit in older games is to generate a certain number of values before the action you wanted to manipulate in order to get a desired result.  By creating independent RNGs, this exploit can be mitigated, as the state of the RNG for item drops doesn't have to be affected by the one that determines, e.g. AI attacks.

For games which don't need this level of control over the RNG, the standard library provides the random module:
Code: (javascript) [Select]

const random = require('random');

// 25% chance this is true
console.log(random.chance(0.25));

// integer [1,10]
console.log(random.discrete(1, 10));

// expected value 1000, std. dev. 50
console.log(random.normal(1000, 50));

// 10 alphanumeric characters
console.log(random.string(10));

// one of: pig, cow, ape
var array = [ "pig", "cow", "ape" ];
console.log(random.sample(array));

  • Last Edit: August 05, 2016, 03:41:29 am by Lord English
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #5
A useful addition in Sphere v2 is the assert() function, which lets you add debug checks to your game that only have an effect under SSJ:

Code: (javascript) [Select]

maggie.eat(allOfEverything);
assert(maggie.weight >= 812, "maggie isn't fat enough");
maggie.sitOn(scott);


While minisphere is under SSJ control, a failing assert will trigger a warning message.  The user then has the option to either continue execution, or break into the debugger immediately.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #6
By the way, I should mention that Sphere v2 is kind of a two-pronged approach.  You have the low-level core API, and then the standard library ("miniRT"), which you pull in using require() includes versions of my Specs threader, Scenario, and even a prefab debug console:

https://github.com/fatcerberus/minisphere/blob/master/docs/miniRT-api.txt

The idea is that the standard library is guaranteed to exist on any Sphere v2 engine, so games are free to use its functionality the same as they would built-ins like Image, Color, etc.  Having Scenario as standard functionality will be very nice, I think. :)
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #7
This is kind of subjective thing, I'm mostly just curious which naming scheme you guys prefer for namespace-like "objects":

camelCase, initial lowercase
Code: (javascript) [Select]

ssj.trace("engine is " + system.name);
ssj.trace("mouse at x:" + mouse.x + ",y:" + mouse.y);
var start = system.now();
system.sleep(2.0);
var end = system.now();
ssj.trace("slept for " + (end - start) + " secs");


Pascal case, initial capital
Code: (javascript) [Select]

SSJ.trace("engine is " + System.name);
SSJ.trace("mouse at x:" + Mouse.x + ",y:" + Mouse.y);
var start = System.now();
System.sleep(2.0);
var end = System.now();
SSJ.trace("slept for " + (end - start) + " secs");


The latter seems less likely to cause naming conflicts, but the former feels more idiomatic for JS and looks cleaner.

For what it's worth, I prefer the first style.

Note: In both cases, singletons like screen would remain lowercase, since that's an actual built-in global variable (a Surface in the case of screen).
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Sphere v2 API discussion
Reply #8
I go with Crockford and Crockford says "Capitalize your classes". So constructors definitely Pascal case and everything else camelCase.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #9
Yeah, I already capitalize classes such as Image, Shape, etc.  I was specifically referring to namespace-like objects, such as system.  It's not really clear-cut because it can either be seen as a pure namespace (like the JS Math object), in which case it should be capitalized for consistency, or an actual singleton object representing the system/engine, in which case camelCase makes more sense.

Moving on, I figure Sphere 1.x API support shouldn't be mandated in the v2 specification, but rather should be up to the engine implementor whether to support it or not.  As such, I added an entry to system.extensions - "sphere_api_v1_compatible" - to reflect that it's an extension to the standard v2 API.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #10
Should assert() and trace() ("print to debugger") be global functions?  In minisphere 4.0 they are referenced as e.g. ssj.assert() (i.e. a minisphere extension), but I can change them to global if anyone thinks this should be standard functionality.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Sphere v2 API discussion
Reply #11

Should assert() and trace() ("print to debugger") be global functions?  In minisphere 4.0 they are referenced as e.g. ssj.assert() (i.e. a minisphere extension), but I can change them to global if anyone thinks this should be standard functionality.


I would think they are more 'system calls' and so I think it's okay if they are global functions. Do you still have to import their library though?
Code: (javascript) [Select]

require('assert');

assert();


Or does it not work like that for global calls? Must they always be namespaced? Because while I like the idea of making assert global, there might be a time I don't use it.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #12
Unlike Node, none of the core low-level API needs require().  What require() is for in Sphere is pulling in the standard library - Link, Scenario, Threads, etc.  The idea is that there's a core set of "system calls" which are provided by default and (eventually) standardized that all other modules and code are built on top of.  This is why a lot of the v2 API looks so barebones - games are meant to use the higher-level stuff like Scenario for the most part and only drop down to the low level when absolute full control is needed.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Sphere v2 API discussion
Reply #13
OK, that makes sense for a game engine then. Yeah, I'll accept having such system calls be global functions, for the sake of being "Sphere-y".

Edit:
That said, couldn't assert be a library? I think if system calls ought to be few, certainly assertions could be in a library with system logging/debugging calls being what the library would use anyways.
  • Last Edit: August 13, 2016, 04:54:47 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Sphere v2 API discussion
Reply #14

That said, couldn't assert be a library? I think if system calls ought to be few, certainly assertions could be in a library with system logging/debugging calls being what the library would use anyways.


The thing about assert() in minisphere is that it's already a pretty low-level call - if an assertion fails and SSJ is in use, then it displays an alert and triggers a breakpoint; without the debugger attached it does nothing at all.  This can only really be handled in native engine code, since the JS side has no way to tell if the debugger is in use (for good reason).  Likewise for trace - it doesn't have any effect if SSJ is not in use (as opposed to, say, console.log() which prints to the terminal).  There's not much a library can do to build on that, and would end up looking like this:

Code: (javascript) [Select]

exports.assert = function(test, msg) { system._assert(test, msg); }
exports.trace = function(msg) { system._trace(msg); }


Which of course doesn't gain us anything over just exposing the functions from the engine directly.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub