#nengi.js
Explore tagged Tumblr posts
Text
Plans for nengi.js 2.0
Hi, this is Alex, the people’s network programmer and developer of nengi.js. Let’s talk about the future.
I consider nengi 1.x to be complete. Of course there are always unfinished items of work -- I wish I had a comprehensive tutorial series on prediction for example -- but really things have been stable and good for a long time.
So as I look towards 2.0, there are no fundamental changes to the library in mind. Instead the future is about improvement, making things easier, and staying open to deeper integrations with other libraries and possibly even with other languages.
One area of intended improvement is the whole process around forming connections both on the client and the server.
On the clientside, client.readNetwork() or equivalent is invoked every frame as the mechanism that pumps the network data into the application. However, this pump also controls the network data related to the connection -- meaning that without spinning the game loop one cannot finish trading the data back and forth that completes the handshake. I’d like to redo this such that we end up with a more normal api, e.g. client.connect(address, successCb, failCb) or equivalent. This presents a clean flow with no ambiguity as to when a connection is open. It’ll also let the clientside of games be a bit tidier as they don’t need to spin the network in anticipation of a connection opening.
On the serverside the whole .on(‘connect’, () =>{}) warrants a redo. I have in mind a simpler api where a ‘connectionAttempt’ occurs, and then the user code gets to invoke instance.acceptConnection(client, greeting) or instance.denyConnection(client, reason) thus again providing a nice and clean exact line after which we know what state the connection is in (attempted => connected, or attempted => denied).
Another area is Typescript support and some positive side-effects thereof. Nengi has minimal typescript definitions, but I think the actual surface of each api class/function should be rewritten in actual typescript. This will be limited, as the actual inner workings of nengi are truly untyped -- it has its own crazy typesystem and fancy optimization of high speed iteration based on object shapes that I should stop talking about now before I accidentally write a dissertation.
Per adding Typescript support there will be a major benefit to Typescript and JavaScript developers alike which is the opportunity for some top tier intellisense. The nengi api is small and having some modest documentation pop up right as you type things like .addEntity would be awesome.
The other benefit (ish..) of formally supporting Typescript is that a few of the processes around how to integrate game logic and nengi could finally be strictly addressed. I used to favor a very laissez-faire approach to integration as I didn’t want to stifle anyone’s style… but as time has gone by it seems that the level at which nengi can be decoupled is not seen as powerful, and instead it just confuses people. I want a better newbie experience, and presenting things like “well you can kinda do anything” isn’t helpful. I wouldn’t necessarily limit nengi itself, and instead may supply this functionality as a layer, but I would like to suggest a much stricter boilerplate for topics such as associating game data with a connected client and any other spot where game and network get glued together.
On that note of making things less open ended, I am *considering* whether nengi should offer an Entity and Message etc as part of the api. Currently entity is a concept or an implied interface -- really it is any object. Too decoupled? Maybe something more explicit would be nice. We’ll see.
More advanced protocols/schemas are also needed in the future. There are a bunch of features that can easily come from having more options on the protocols, but initially I plan to skip over all of these features and just change the api in a hopefully future-proof manner. The plan here is to change things from protocol = { x: Int, y: Int, name: String } to something more like context.defineSchema({ x: Int, y: Int, name: String }). Initially these will do the same thing, but in the future more arguments will be added to defineSchema.
The eventual removal of types from nengiConfig is another dream feature that may or may not make 2.0 but is worth a bit of discussion. NengiConfig.js is that file where every entity, message, command etc is listed out. Removing this would require nengi to be able to explain *in binary* how to *read future binary* and is non-trivial. The benefit however is that the parallel building of client and server code would no longer be a strict requirement. In the end of course a client and server need to be built for one another, but if the relationship were less strict than it is now it may pave the way for eventual nengi clients that aren’t even JavaScript. To me this has always been a bad joke -- who would want such a thing??? But as the years have passed it has become clear that nengi is not just special for being JavaScript, but that it is actually competitive in performance and functionality with the type of technology coming out of AAA multiplayer gaming companies (send money!!). So this may not be a bad direction (though it is worth noting there are at least two other major changes needed on this path).
There would also need to be changes to the current ‘semver’-ish release cycle. As it stands currently nengi version numbers follow the rules of breaking changes on major release (1.0.0) non-breaking changes on minor release(0.1.0) and small patches on patch release (0.0.1). As the current version of nengi is 1.18.0 that means that I’ve managed to add all functionality since release without a single breaking change (send money?!). This is not easy. These new changes described above are deliberately breaking api changes. Given the work cycle that I’m on and the lack of funding, the most efficient way for me to work would be with breaking changes allowed and perhaps a changelog to help the users out. So 2.0.0+ may shift to this type of development, where the ‘2’ is just my arbitrary name for the functionality, and 2.1.0 is a potentially breaking change. Obviously no one has to join me over in the land of nengi 2 until it becomes more stable, but letting me do *whatever* will get everything done faster, which is more important than ever given my limited time.
In the category of “maybe 2.0 things” here are a bunch of other things I’d like to talk about too, but they’re too involved (and experimental) of topics to go into detail. Here’s a vague summary of things I’ve put R&D time into:
Experimentally rewrites of sections of nengi in Rust, C, C++ with integrations via n-API, wasm transpilation, and some in-memory efforts. Crossing the boundary between JavaScript and anything else has been problematic as a means of solving most obvious problems, but some less-than-obvious problems may yet warrant this approach. I would say that n-API is a dead end for most nengi functionality but has some merit for spreading sockets across threads. WASM, or specifically working on a continuous block of memory may have some promise but requires further R&D.
An advanced rewrite of the nengi culler based on spatial chunking (promising!).
A middle api between serving up interpolated snapshots and the nengi client hooks api. This would become a generic replacement for the entire nengi clientside api. Until further typescript support I’m going to leave this one alone as it is very likely that a naturally elegant solution will show itself in the near future.
Multithreaded nengi, specifically the spreading of open connections across threads and the computation of snapshots. True optimal CPU use is opening multiple instances, not giving more threads to an instance, but there are some uses nonetheless.
Multi-area servers that use spatial queries instead of instances or channels (for example creating multiple zones, but not making an instance or channel per zone, instead the client.view just goes to a different space with some spatial math).
So yeah, that’s the plan! Thanks for your support (send money)
https://github.com/sponsors/timetocode
https://www.patreon.com/timetocode
2 notes
·
View notes
Photo
Development of server seams for nengi.js. In the gifs above the edge of the grid is the border between two separate game servers. Each gif is progressively getting closer to the goal. It begins with just seeing across a server boundary, to seeing both ways, to interacting across lines, and finally efforts to make things feel more and more seamless. Still not done is the player or npcs crossing the server boundary smoothly.
This is different than the instancing in most AAA mmos where instances don’t share true borders -- they merely pretend to, and players can see everything phase into existence as they cross one of these server boundaries. A dozen players can walk out the front gate of a town and they won’t necessarily end up together. That form of instancing (which is really easy in nengi) is great for having 500x instances of the main town b/c there just too many players to all be in the same spot at the same time. But this experiment is about treating a world as one big place. I miss UO.
For those wondering about the performance, I gotta say I have yet to get it working well enough to make a legitimate grid of servers but it is looking pretty light. Having a server border so far is about as intense as having a player (a border and a player are both just a rectangle that can see stuff), and this thing can have a lot of players (100-400 depending). I guess if the border were hugeeee that might change.
#devlog#game development#mmorpg programming#nengi.js#multiplayer programming#high performance JavaScript#node.js#html5
4 notes
·
View notes
Photo
Workin’ on a stats api, server, and ui. Am I a web developer again...?
I’ve also gone back to a fast TTK (time to kill) on the order of 330 - 600 ms. The current alpha test has twice that TTK. I’m not sure what I’m going to settle on.
4 notes
·
View notes
Photo
Multiplayer jigsaw puzzles ... coming soon :D
5 notes
·
View notes
Video
youtube
Latest state of nengi.js prediction features and integration with Babylon.js
2 notes
·
View notes
Photo
A networked cube via nengi.js and babylon.js. The upcoming version of nengi (v0.3.0) finally has some decent client-side prediction, which was my prerequisite to opening nengi up to integration with 3D libraries. This is the beginning!
This particular simulation has the server running at 20 fps, and randomly rotating/moving an entity. The client renders this entity as a cube, and goes through nengi’s interpolation layer which converts the 20 tick server data to 144 fps! (It converts it to refresh rate of the client’s screen, not that the gif can show that...)
3 notes
·
View notes
Photo
(GIF) battle royale shrinking arena algo
What’s special about this one? It doesn’t suffer from the bias that causes an overwhelming number of games to end at central locations (literally locations that are near the center). This one gives every little shore and obscure area an equal chance of being the stage for the finale.
This algo and our new giant map will be appearing in Bruh 2.0 (release 2nd or 3rd week of Feb 2018).
https://bruh.io/
3 notes
·
View notes
Photo
Three days of binge coding later... bruh.io gets its infrastructure upgrade. We now have quite a few servers, and a nice server select. GL HF :D timetosleep
8 notes
·
View notes
Photo
The guns of Bruh.io: pistol, shotgun, sniper rifle, assault rifle, and machine gun.
Play this 2D battle-royale shooter in your browser on November 30, 2017 (in 5 days!! Rut roh better get to coding..). I’ll be posting moar bruh gameplay and art over the new few weeks.
Developed with and published by Sam Stiles (@SamuelDev) of Bitfox games. You can find his blog here: http://www.lerpblog.com/.
This going to be the first game to showcase the lag compensation and input prediction features of nengi.js.
3 notes
·
View notes
Photo
Working on a game w/ my friend Nate. Cats eat mice. Mice eat cheese. Gameplay is a hybrid of tag with rescues and survival (gotta keep eating!).
#devlog#gamedev#nengi.js#io games#mutliplayer#mmo#browser games#html5#javascript#node#pixel art#cat#mouse
7 notes
·
View notes
Photo
200 player test of nengi beta v0.2.0, with players flooding from the overworld instance to the underworld instance (through that cave). Also wrote some view-scaling code that can handle anything between a phone and a 4k screen without distorting pixel art (a mixture of zooming and adding/removing more tiles around the edges). These screenshots are 2560x1440. This is all getting baked into a nengi demo and released soon.
Edit: looks like tumblr distorts these :/
8 notes
·
View notes
Photo
I’ve got it so that extremely large maps can now be loaded from Tiled Map Editor into a game rendered with Pixi.js. I had to write my own loader that converted Tiled maps into spatial grids. Then I used the same culling/rendering logic that I use for all tile-based games on this blog. So it was a big improvement overall.. for the 1000x1000 maps the rendering is like 200,000% faster than it was with the other loaders (apples and oranges, I guess). The other cool thing that comes from exposing the map data in-game is that I can now make a layer that stores the collision logic, shown in blue on the second screen capture. This is pretty handy as it allows me to quickly just draw the collisions right on the map instead of writing some tedious logic about which tile types are collidable. The same thing could be used for all kinds of things, like a layer containing the locations of monster spawners... though if there were too many things like that I would trim them from the clientside version of the maps.
After I finish this demo and nengi beta 2, I hope to bring some of this workflow over to the battle royale game. Tiled is very handy, though it stores information quite verbosely. I’ve noticed that gzip can compress the maps by 90-99%. For the battle royale game it isn’t an easy fit. I’m using a procedural island generator and have destructible buildings as well as working under a tighter performance window. I’ll have to write some sort of converter... But I think writing a converter will be less work than maintaining my map editor.
#devlog#Tiled Map Editor#PIXI.js#nengi.js#game development#multiplayer programming#pixel art#browserquest#performance
12 notes
·
View notes
Photo
Client predicted projectile @ 300 ms of latency, followed by the server side shot (white is client prediction, black is server-confirmed reality, though seeing it is subject to the latency as well).
Out of the 7 projectiles, the first 4 have been created on the server as far as this client knows. The 4th projectile has a line demonstrating its relationship with its counterpart. The last 3 white dots are projectiles that have also been fired on the client but due to simulated lag have yet to be created on the server and confirmed again on the client (which is the point at which the black dots appear).
Getting these things really deterministic (and therefore consistent) with date/time related math seemed inherently flawed, so I’ve favored a fixed timestep + deterministic simulation approach instead.
Example/process:
When the client is determining if it can fire a projectile, it does so by comparing the weapon cooldown with an accumulator variable. e.g. is our accumulator greater or equal to our cooldown of 0.500 seconds? Each frame it adds 1/60 of a second to the accumulator.
The server also uses the same logic to determine if it should created a projectile -- at a rate of 1/60 being accumulated for each frame it receives from the client.
The result being that the number of frames experienced by the client is the number of frames processed on the server... and the small aggregate of 1/60s being added up will pass 0.500 on the identical frame for both computers (deterministic).
The server can also decide if the frames it receives from the client are valid... did they contain actions that are feasible for that player? Are they coming in at a believable framerate?
From there each computer (client and server) can simulate their own highly-similar result for the projectile. The server might determine that the projectile hit another player, and deduct hitpoints. Meanwhile the client, which for cheating reasons does not get to say anything about anyone’s hitpoints, might instead determine that the projectile hit another player and draw a purely aesthetic blood effect.
After some polish and lag compensation, I’ll publish a nengi-demo of a client+server combo that can predict and compensate high speed shots at a variety of different latencies while maintaining very reactive controls (16 ms input delay). An early prototype of this demo already exists for hitscan weapons, but has some bugs with its timers (Date.now() math...).
#nengi.js#devlog#network programming#multiplayer programming#clientside prediction#lag compensation#authoritative server design#physics simulation
3 notes
·
View notes
Photo
Some visual tools for continuous collision detection, broadphase sweeps, and a raycaster. In this case the green rectangles are showing areas where a spatial structure was accessed in the recent past.
There’s something naturally unintuitive about a game which takes into account both the immutable past (for lag compensation) and the hypothetical future (for clientside prediction). Each tick of the engine occurs in the present... but the state of the present depends on a past of the server as well as the newly discovered pasts of players (things players allegedly did a while ago, but the server hears about just now). The state of the present for the client depends on the past of the server, plus a hypothetical future that the client simulates just ahead of confirmation from the server. So nothing is simple, nor particularly relate-able to the physical world (some overlap w/ astronomy and looking at distant objects, maybe).
While I’ve been tinkering with these things for quite a long time, I’m near the point where prediction and compensation become part of nengi’s formal api. The challenge isn't in getting them to work, nengi has thought in these terms since its inception -- the challenge comes in writing the actual game code in a way that these various temporal states become valuable tools and not an overwhelming mess. (We’ll see about that...) After all people are often looking to translate game ideas from singleplayer that exist in a single temporal state to multiplayer and then they want the bells and whistles of CSP and lag comp... which exist by constantly reconciling multiple temporal states.
2 notes
·
View notes
Text
nengi instance transfers are doneee
Oh and there’s a hook for player authentication as well. It is up to the dev how/if they want to authenticate though. I need another day to clean/up test before release.
There is no formal TLS / SSH / WSS support, but it is easily added if desired.
It came out pretty interesting in the end. An instance can transfer a player to another address and transfer some data along with the player. The instances actually speak to each other before the player gets transferred. The instances do this via the same websockets that the players use, they just identify themselves with a password. The source instance generates a transferRequest, and the target instance responds with a transferResponse (or fails under a variety of circumstances). If the transfer is accepted, then the source instance sends a transfer message to the client which goes ahead and connects to the target instance, bearing a code that identifies the client. The target instance recognizes the client upon arrival, and gains access to the data that was initially transferred from the other server. Thus nothing from the client is ever trusted -- its the servers who have a conversation with each other, and they merely give the client a receipt (a reference to the conversation) which does not divulge any details to the client. This follows the security model in nengi of making the servers the authority on the game state.
Transfers are pretty quick, taking slightly longer than the round-trip latency between the machines. Transfers are asynchronous.
This enables some really basic but scalable functionality -- such as having a entrance to a dungeon, building, city, portal, etc. where the end point may reside on another server... be that another physical machine or just another instance running in another thread on the same machine. It also offers a way to secure instances, because the game logic can define and enforce rules about who can enter which instance. Lots of features rely on controlling player access (pvp arenas, party-based instances, games that require membership, etc.)
I’d like to keep adding to this demo over time... perhaps it can become a full-featured nengi example eventually. For now the demo just shows a Tiled Map Editor map, an animated character, and inter-instance travel which involves the game client resetting itself and loading up a new map. It hits a lot of the features which were requested, but isn’t much of a game...all you can do is walk around.
4 notes
·
View notes