High-performance real-time game networking using Meteor

Hello! :wave:

I am working on first-person-shooter, an open source app using Meteor for the real-time communication, as well as LUME’s 3D HTML built on Solid.js templating and reactivity:

The first demo of first-person-shooter is up and running. Share the next link with someone to play multiplayer! However, expect the networking not to be so great at the moment, as I haven’t optimized it yet:

https://first-person-shooter.meteorapp.com/

It was my submission for SolidHack (a Solid.js hackathon). Go there and check out the awesome projects, and vote for your favorites in three categories!:

The Goal

I’d like to chat in this topic about how we might be able to use Meteor’s real-time full-stack-reactive networking in the most optimized way for the purpose of syncing game state as quickly as possible.

I thought that perhaps we want to sync game state to clients using a Meteor publication, but without it being tied to the database in the backend. That led me to these topics:

But thinking about it, I don’t think it matter to the client if the backend stores data in the database or not for the real-time game state that does not need to be persisted. Essentially it only needs to be a single object that gets updated over time. To the client, this would appear as a collection that always has a single item.

What I haven’t experimented with yet, is coming up with a binary TypedArray representation of game state, and sending the state as binary to the clients.

Right now, there are multiple objects in the backend players collection, one per player, and the game state is updated by updating each player, which means that the client receives multiple updates for multiple players, rather than one update at a time for a single game state object.

I think merging into a single object will be beneficial, even before converting to a binary format.

Another thing is EJSON: do the game messages always have to be in an EJSON wrapper? It seems that to avoid that, I would have to drop down to DDP, or maybe just to manual WebSockets.

But what I don’t want to lose is the automatic full-stack reactivity that Meteor is know for.

Without Meteor’s out-of-the-box full-stack reactivity, there’s no point in using Meteor, in my opinion. That’s what I’m here for in the first place.

So, maybe there are two main sub topics here on the full-stack system:

  1. how to make use of the current system as efficiently as possible for purposes of real-time games, and
  2. how may we be able to improve Meteor’s implementation to make it even more performant for this use case that is currently possible.

Another thing to explore is, would vertical scaling help? What about horizontal scaling?

Throttling updates is also something basic that probably needs to be employed regardless of any of the above. I linked to some ideas and methods for that here:

So let’s get the fun started :slight_smile:

What are your thoughts or ideas? Have you seen any Meteor apps solve similar problems? How did you overcome any networking bottlenecks you’ve encountered? Any existing code repos we can look at?

8 Likes

@rjdavid continuing from

That’s interesting! In context of an FPS game, the backend needs to hold the current state of the game in order to sync it to all users.

Would streamer be ok for that purpose? What’s a use case for streamer, and what wouldn’t be? In the FPS case, the game state doesn’t need to be in the database (I think?), and the server just needs one game state (not a collection). Maybe streamer is good, but just needs some additional code to handle reconnected clients. Wdyt? Streamer docs didn’t mention, but I assume emit() taks EJSON-able data?

It is perfect for broadcasting to many users without db persistence.

Reconnects will always get the most recent value emitted

have you tried Mongodb In-Memory Storage Engine?

This is awesome @trusktr! I’m a big fan of video games so you have my full support on this one. Looking forward to seeing the progression. :comet:

2 Likes

Awesome! I can try to give some feedback (already opened an issue) on ux and mechanics. I did a few games and know how hard things can be, especially the matrix work in 3d space can be a real pain.

1 Like

i tried to create an experimental egoshooter with meteor and threejs some eons ago: GitHub - macrozone/unechtquark

idea was to use DDP and pub/sub for player position and sync with local “simulations” (just using methods).

meteor is probably not the right tool to do something like that, but it was fun to do!

(you can walk width esdf (not “wasd” as I think esdf is far superior))

2 Likes

I think the main problem is how to sync mmo-style states. Because for turn based games meteor works great.

For example, for Shooter’s like games fps on server should be at least ~20 to calculate collisions and another systems.

There is a delta syncing concept for updating state for fast gameplay.

There are interpolation and extrapolation for smoothness update position, animation.

Another problem is WebSocket. Because it based on TCP you should expect some net problems.

So meteor works great anyway if you want to use websockets. But afaik there was webrtc which can emulate udp-like behavior

1 Like

https://github.com/RocketChat/meteor-streamer

1 Like

I’ve circled back to this again. What I’m wondering is, what would it take to make Meteor the right tool.

If not WebSocket, then what? https://krunker.io is great. It seems to be on WebSockets last time I checked, and I saw it sends a binary payload per message (makes sense, cram data in as small binary as possible). I’ll experiment with sending binary with Meteor at some point.

WebRTC can’t work for something like Krunker to avoid cheating, right? Game communication needs to be centralized on the server, to ensure state is not cheated. I wonder if HTTP/3 provides anything here.

You could use Meteor for this, however, for state control you would have to use something like Redis.

I believe most games use the UDP protocol for lower-latency.

TCP, UDP or QUIC? Read this before you choose. - DEV Community

Yeah, I know, but web apps cannot use UDP, and QUIC is not supported in Node.js, Bun, or Deno yet, let alone Meteor. So we have no choice by WebSockets (Meteor or not), as WebRTC can’t be controlled for anti-cheat.

In light of that, the focus of this question is specifically on how to do this in the best way with WebSockets in Meteor, because there simply is no other option right now.

UDP/datagram sockets | Node.js v20.7.0 Documentation (nodejs.org)

Web apps running in a browser cannot access UDP packets.