How to manage networked collisions (babylon and colyseus)

Hi all,

I’m currently working on building a simple multiplayer 3d top down rpg (Multiplayer Top Down RPG - Babylon.js & Colyseus - #12 by oriongu), and I’m quite happy with the current progress, the next hurdle is a big one: collisions.

Collisions detection must be done on the server (else people can hack, ex: go through walls), however, I have node idea really on how to approach this and was wondering if anyone has tried to do something similar before.

I’m guessing I must load a mesh on the server ( a mesh that covers all the areas a player can walk on) , and then crosscheck current player position and see if he is allowed to be there and allow movement or not.

Can anyone give me any tips? Or had any similar challenge?

Cheers,
Orion

Have you checked this post from @renjianfeng : A simple network physical synchronization demo (based on ammojs + colyseus)

2 Likes

Yes, I saw that, and as stated on that post, there is no server validation of any kind, hence not really relevant to my question. (this said, maybe it could, but I faill to see it)

No offense, of course, I appreciate the help :slight_smile:

You are right. It performs check on the “host player” (first player).

For server side validation, you will need to run the physics engine (e.g. ammo.js) on server side. A very basic version:

  1. Move commands from players trigger velocity changes of agents.
  2. Instead of directly applying the change to the local physics engine, you send the velocity change over the network to the server.
  3. Apply the velocity changes to the ammo.js running on the server.
  4. ammo.js engine keeps ticking on the server side, so it will calculate new positions of agents. Send the updated state to the clients.
  5. Client updates agent positions.

Since there is network delay, the topic can become much more complex. I can think about these things:

  • Run physics engine also on client side to avoid agents running into each other
  • Predict agent movement locally based on the local velocity. Sync with server state later.
  • Or oause all players if a slow player doesn’t get update from server.

ammo.js API is quite complex. I find it very helpful to read babylon.js implementation of the ammo.js wrapper to understand how to directly call ammo.js.

The other choice could be running babylon.js NullEngine on the server. So you can benefit from babylon.js simplified API to use ammo.

1 Like

Hi @slin,

Thanks for that very detailled answer, it’ll take me a while to digest.

Sorry for my ignorance, but I was wondering if I needed to run a physics engine as I’m a bit worried it’ll bring too much complexity too quick as I’m still quite new at this stuff,

At this stage, I only need environment collisions. For all characters I could do a basic checks between players positions to check for collisions if need be.

To be honest, everyone I asked has suggested to use a physics engine on the server similar to what you are saying, however I think I need to try my own way with some sort of walkable navmesh and to unsure players stay withing those limits.

That’s part of the learning process, and I guess after failing miserably, I will have to dive into implementing a physics engine :slight_smile:

Now I see what you mean in your original question. Yes that should also work. I think the steps in my last reply is still valid for this appoach. Instead of validating with a physics engine, on the server side, you need to calculate the positions of agents at the next clock tick based on their velocities (speeds and facing directions), and validate the new positions with navmesh on the server side. And then broadcast the new world state (positions of agents) to all the clients.

Have fun!

@slin thanks, glad I make sense, and that you think it can work that way too,

So based on what your said, I can use the NullEngine on the server side to create my scene, load the navmesh & make sure the players are in a contact with that navmesh.

That lead to another issue, I have multiple rooms/zones on the server, so I’ll have to run multiple scenes at the time, and make sure my collision logic is running on each scenes independently: Another level of complexity, great :slight_smile:

I wouldn’t worry about it right now, because gameplay and controls will dictate which approach you take. I’d just structure it where your input commands do not directly set your scene state. This way, you can either have a local handler or a networked handler.

Also, i don’t think you need collision detection on server (for walls, maybe for players or something gameplay specific later, sure). You already have player positions on the server, so one approach could be to just start logging positions after they get reported and see if the movements are possible. Doesn’t really have to be in real time to keep cheaters out.

2 Likes

Thanks for your input @jeremy-coleman

How would I know if a movement is possible or not, if I dont have the world/navmesh loaded on the server to crosscheck what is allowed or not? Maybe I missunderstood you?

My understanding from @jeremy-coleman is: cheating is treated like using bad language etc in a game session. After the game this player will be reported by others. With log on the server admin can verify the report and punish this player in a way designed in your game platform.

1 Like

If you run collision detection and navmesh verification mostly by your own implementation, you might not need NullEngine. It is likely to have a larger memory footprint than necessary.

That lead to another issue, I have multiple rooms/zones on the server, so I’ll have to run multiple scenes at the time, and make sure my collision logic is running on each scenes independently: Another level of complexity, great

After your game became popular, you will also need to have multiple servers for hosting game sessions. Together with that you will need a service discovery service that registers all the available game servers. And you will start monitoring the load on these game servers to allocate players to the server with low workload…Finally the complexity will pay back and you start driving a Lamborghini. :grin:

1 Like

Haha I like your thinking! :slight_smile:

But I’m more trying to make a good open source base for a “simple” rpg multiplayer game using babylon.js.

Who knows, maybe in the future, I’ll make a game for myself out of it.

I think I have enough information to give it a try, I’ll be back! :grin:

1 Like

I’ve got the first iteration of my networked collisions sorted out. It involves using unity to generate a navmesh, but technically you could use any software to do that.

It only works on the X and Z axis at the moment, meaning the world must be flat, but that doesnt bother me yet and I can be easily adapt that if need be.

So what I did is:

  1. Create a navmesh with unity
  2. Export it with a C# Script as an OBJ mesh (I used a script I found on internet somewhere the other day).
  3. Import it on the server using “wavefront-obj-parser” && load it with GitHub - mikewesthad/navmesh: A plugin for path-finding in JS using navmeshes, with wrappers for Phaser 3 and Phaser 2
  4. for every movement update, check the calculated position can found on navmesh else just refuse movement an return player to previous valid position.
  5. Job done :slight_smile:

here is a video showing the results: T5c - Google Chrome 2022-11-26 17-46-08.mp4 - VEED

and demo can be found here: https://t5c.onrender.com/

As you can see, characters still ends up into the wall a bit (that’s due to the ping & my client side prediction movement, and by the time the server has checked everything, player is already in the wall slightly), but can be resolved by doing the same collision check as the server but on the client . Anyway, even if the player does manage to cross the wall, the server will eventually reset the player position back to where he should be.

I still need to do some tweeking to but I’m very happy with the initial result.

What do you guys think? Any suggestions?

1 Like

Cool!

Movement is by gizmo like mouse dragging in @oriongu’s demo. I was confused at the beginning since neither WASD nor arrow keys worked.