NullEngine Multiplayer tutorial

Hi everyone,

is there an example or tutorial for building a multiplayer game server with state (and physics) sync using NullEngine running on a server? On a documentation site i only found a brief example of how to instantiate a NullEngine but my current knowledge requires a little bit more of hand holding… :slight_smile:

1 Like

Hey!
did you have a look to that?
https://doc.babylonjs.com/features/nullengine

Hello,

There is no specific tutorial on how to make a multiplayer game with BabylonJS. That’s because BabylonJS is a game engine, it does rendering and game specific stuff the best of ways, networking physics and game states is out of its scope.

However, building multiplayer games requires having some deep understanding on how networked games work. If that’s already the case then it should be very easy to implement it using Babylon, just build a network layer which transmits data between the client and the server ( running Null Engine ). Of course, doing so it not as easy as it sounds, developing network specific functionalities like prediction, reconciliation, server tick is not the easiest of tasks. Please refer to this tutorial for more in-depth view of multiplayer Client-Server Game Architecture - Gabriel Gambetta if you do not know where to start.

Probably it would be nice to provide some boilerplate for network development using websockets, BabylonJS and NodeJS. If I can find some time next year I might be able to push something in github.

Hope it helps!

3 Likes

I’m doing exactly this. I’m taking a more hybrid approach though. My primary server-side game loop is in PHP7, with world/physical validation done by the null engine in Node of course. This allows me to put the physical validation code on any other system (with dedicated hardware/resources), away from the main game loop process so neither drag each other down. It works pretty well, but I haven’t done a high degree of stress testing yet.

From the client perspective, it needs to know the ip/port of the game server as well as the ip/port of the mesh server (I call it the mesh server, even though I stopped using mesh and went to node based / dijkstra’s). When a player connects to a zone server (each area in the game world is broken up into zones, with zone/loading boundaries) the zone server informs the client where it needs to send certain opcodes for validation - because the zone server will not accept the opcodes that involve distance checking directly from the client). When the player performs any of those operations, the opcode is sent to the mesh server for validation, then (if validated) the opcode is forwarded to the game server (implicit trust between mesh <-> zone server). If the effect requires some kind of feedback (ie. click on a knob to open a door), then game server will send that info up to the client. Ultimately it’s a round-robin trip for the opcode. The mesh server and game server are usually right next to each other from a network perspective so any added latency is negligible. The thought way back when I started this was to use a bunch of low-power raspberry pi’s, each one hosting a few zones of their own, with higher population zones maybe on some stronger hardware.

I agree though, you’re going to need to understand how to use networking/sockets to do any of this. To save you some time (and IMHO), websockets is NOT the way to go. Node based projects can use the dgram package for udp/tcp, but if you’re writing a more traditional “site” based project (apache hosting files, etc) and not using Node, it’s basically not feasible to write a game of any real multiplayer magnitude. This is why I went to the Electron framework.

1 Like

I don’t know why you went with PHP but if it suits you that sounds great. I have read this kind of approach somewhere, seems kinda tricky to setup, putting the validation into specific resources / hardware would add latency in the communication between the main game loop and the validation instances, even 5 milliseconds matter in networked games, if its fast paced at least. There is no silver bullet into tackling such architectures.

Regarding web sockets, I do agree they are not perfect but they work. The main issue with them is the fact that they operate under HTTP which by itself uses TCP. In networked games we usually use UDP so that we can avoid the TCP overhead. Other than that it works quite fine in my experience.

2 Likes

Not a tutorial, but I thought I would share what I recently discussed elsewhere regarding my engine layout and setup:

The application “shell” is mainly used as a kind of router to link websocket client connections to worker_thread instances, using MessagePort as the communication medium between websocket connection and worker_thread.

Each worker_thread instance acts as a sort of mini “game loop” which encapsulates all the logic required to manage a collection of spatially-related websocket clients. For this part I use a fork of “ecsy”, an Entity-Component-System engine, to manage interactions between game objects and Babylon.js NullEngine for game object physics.

Each individual Entity which is used for its player counterpart has a custom Machina.js-inspired “server-side” client FSM, whose transitions link directly to websocket clients, controlling their state.

And finally, on the client side, websocket clients have their own copy of the client FSM which contains more client-specific things like managing actual Babylon.js visuals, player input, media asset management, and the client game loop.

This setup is done for a number of reasons, mainly a) reuse of containerized resources during deployment, b) spatially segregating websocket connections, and c) separation-of-concerns for what actually constitutes the portion of the game engine referred to as the “game loop” from the rest of the web-app-based engine (database connectivity, logging, authN and authZ, hot-reloading the UI during development, etc).

Regarding Websockets performance, I don’t think this would be an issue once connection is established, as message frames lack HTTP overhead. However, they are typically JSON or plaintext, so it would behoove the developer to eventually commit to byte-packing message-frames sent over the wire, similar to gRPC or old-school wsock32 if you coded in the previous century :slight_smile:, and sending them as binary websockets.

Plainly - I went with PHP because I knew it. My entire project started out as an experiment with PHP traits, a way to modularly import blocks of code (typically just functions) into classes. I thought it would make a good fit for designing mmo/rpg classes - and it has worked well. I’m sure something like C/CPP would be faster just natively, but I think you’d be pretty surprised with the performance I’ve been able to squeeze out of PHP. PHP7 introduced some really powerful run-time features that dynamically compile certain portions of code down to lower level stuff (over my head, TBH) but I think the PHP devs boasted performance gains of 50% on some things. I spent literally weeks performance-tuning the main game loop and internal scheduler system for absolute throughput and I’m pretty happy with it for now. Sooner or later my project will make it to alpha and I’ll be able to demo things like load capacity.

I agree that access to UDP is a must-have for any seriously scaleable game. I was actually a little stubborn on that front but my brother talked me out of relying on purely websockets. That notwithstanding, I also noticed some mysterious (but significant) latency that I could never pinpoint. Round trip messages could be several hundred milliseconds despite machines being on the same wired network. Moving to electron and actual network sockets got rid of that problem of course.

Regarding the added latency - you’re not wrong, there will of course be some extra latency. The actual act of validating a request should be <1ms for any respectable engine, then add the latency to send it to the game process, let’s say worse case 5ms for LAN distance, even though most of the time, small packet communications between neighboring IPs is <1ms. Being an MMORPG and not a shooter, adding 5, 10, or even 25ms latency is a fair trade-off if separating the two processing loops avoids slowdown - which may be greater than 5-20ms if a singular game loop gets bogged down from over-activity.