Jump to content

Running Phaser on Node.js - How I did it and why you shouldn't do it


Crisu83
 Share

Recommended Posts

For years now we've been taking for granted the magical ability for increasingly complex and interactive games to play over the Internet with little or no noticeable hitches - the huge effort that's gone into this has been largely ignored because quite simply no-one wants to think about how genuinely difficult it is even to make two players bump into one another online without everything going nuts. I think if more people understand this and create their own implementations, it makes the ecosystem richer and the problem easier to tackle.

 

THIS.

Online games are composed of the essence of hacks; as if all games weren't already.

My sync is pretty stable at this point. I am looking at making it a Phaser Plugin soon.

Link to comment
Share on other sites

Here is a link to what I'm currently working on.

https://github.com/crisu83/dungeon-game/tree/feature/authorative-server

 

The sync isn't done yet but I'm getting to the point where I can implement it.

 

Good stuff, it is nice that you decided to use jsonwebtoken & require.js - they are yummy!  ;) Seems that you are getting to interesting point next.. the actual loops and networking madness.  :D Hence, I recommend Mongoose for db side (: 

 

Hmm. it also seems that you are making some sort of room structure... are you planning that the whole world is made of separate rooms and player can be only in one room at a time & see only one room at a time and it's environment ?

Link to comment
Share on other sites

Good stuff, it is nice that you decided to use jsonwebtoken & require.js - they are yummy!  ;) Seems that you are getting to interesting point next.. the actual loops and networking madness.  :D Hence, I recommend Mongoose for db side (: 

 

Hmm. it also seems that you are making some sort of room structure... are you planning that the whole world is made of separate rooms and player can be only in one room at a time & see only one room at a time and it's environment ?

 

I'm going to wait a bit with persistant storage, but once I do implement it I'm quite sure I'll go with Mongoose, because it's my favorite nosql library.

 

The idea is to have a world where each area is a separate "room" that the clients can connect to. Once the client joins a room it will start receiving data about entities in that room through that rooms socket stream. I will see if I need to optimize it by implementing an "area of interest", I doubt it - but we'll see.

 

I just now pushed entity prediction and server reconcilation together with a simple game loop for the rooms.

 

Next on my todo list is entity interpolation, but it requires a bit more research as I'm not yet sure how to implement it properly.

 

EDIT: I'm still working on simplifying the server reconcilation and preparing for entity interpolation.

Edited by Crisu83
Link to comment
Share on other sites

I'm going to wait a bit with persistant storage, but once I do implement it I'm quite sure I'll go with Mongoose, because it's my favorite nosql library.

 

The idea is to have a world where each area is a separate "room" that the clients can connect to. Once the client joins a room it will start receiving data about entities in that room through that rooms socket stream. I will see if I need to optimize it by implementing an "area of interest", I doubt it - but we'll see.

 

I just now pushed entity prediction and server reconcilation together with a simple game loop for the rooms.

 

Next on my todo list is entity interpolation, but it requires a bit more research as I'm not yet sure how to implement it properly.

 

EDIT: I'm still working on simplifying the server reconcilation and preparing for entity interpolation.

 

Ok, sounds fabulous.  :)

 

Entity interpolation seems legit if the game is fast-phased and rather unpredictable as using of dead-reckoning could result to high number of prediction errors(?) To my understanding entity interpolation means rendering of other entities around you in the past (just as 100ms) - using real values from the server, whereas client-side prediction is a technique which is applied to the character controlled by yourself (you predict your own movements, which server later corrects or agrees with.). Hence, if you dont apply area of interest - delta coding is another method to mitigate bandwidth usage. - only values which changes are sent to the player(s).

 

For instance, you sent full room snapshot to the player_2 when he joins to the room,

 

packet 1:

{players  {     player_1: {        x: 1,        y: 1,        name: "ExamplePlayer"     }     ... and other players ...  }}

..later on, you only send recent deltas to the same player which has received full world snapshot. e.g. when player_1 moves one step to right.. only x is sent to the player_2 within the same room.

 

packet X:

{players  {     player_1: {        x: 2     }  }}

Maybe something which you already knew, but anyways I think Quake uses same technique to mitigate bandwidth usage   :)

Link to comment
Share on other sites

Entity interpolation seems legit if the game is fast-phased and rather unpredictable as using of dead-reckoning could result to high number of prediction errors(?)

 

 

 By dead-reckoing I think you mean teleportation.

That looks awful and your users will hate it.

 

To my understanding entity interpolation means rendering of other entities around you in the past (just as 100ms)

 

Nah. there's no official name for that. entity interpolation is something you have to do to smooth between server packets.

 

whereas client-side prediction is a technique which is applied to the character controlled by yourself (you predict your own movements, which server later corrects or agrees with.).

Kinda. They go hand and hand. You don't need to pick one or the other, and you shouldn't.

Most games seem to have a mix of a couple things evening out to about 3-4 general ways that this stuff is done.

 

 

Hence, if you dont apply area of interest - delta coding is another method to mitigate bandwidth usage. - only values which changes are sent to the player(s).

 

 

Doesn't always seem necessary, imo.

Link to comment
Share on other sites

Cisu83, I'm going to try save you some trouble regarding timestamps and extrapolation on the server.

Not all computer clocks are properly synchronized.

Even in the era of the internet.

I had to write this plugin for primus so I could sync the time differences on my server:
https://github.com/Fishrock123/primus-spark-latency

 

 

Edit: Also, if you would like to see my implementation, come on irc and ping me about it.

Link to comment
Share on other sites

 By dead-reckoing I think you mean teleportation.

That looks awful and your users will hate it.

 

No i dont mean teleportation, because the path taken should be smoothed when corrected with real accepted server packets.. it should not look awful if its applied correctly and to correct games where objects are more predictable.. e.g. racing, tank games..

 

 

Nah. there's no official name for that. entity interpolation is something you have to do to smooth between server packets.

 

Yea, I realized that I left my explanation a bit short.. let me correct by saying that interpolating e.g. 100ms in the past between two valid positions from the server. Ofc. it requires that server sends updates as fast that at least two packets has time to arrive to the client. Hence, there is a chance that they wont arrive on time anyway, because of packet loss and a like. In those cases, client could use either extrapolation to predict future positions of other entities or let them rest still.. in both cases, it is possible that entities seems to suddenly snap to different position. (prediction error with extrapolation or packet finally arrived from the server which is accepted). Thus, I agree that terminology is rather confusing.. as dead-reckoning is basically same as extrapolation in the literature.

Link to comment
Share on other sites

nice topic, weirdly ive started with node and sockets too. Then read this;

I have started to build a server from scratch and have the client not even in node, but use socket.io standalone (FOR NOW)

The server.io ...i was about to attach phaser to...why?
I want phaser.maths and events, Actually less so the events, but an event system will be handy soon, im sure there is some lib.

 

The phaser.maths i want to be exactly the same on the client and the server. I was going to start ripping it out and leaving all of the display stuff behind. Physics will not exist on the server but checks if the position is possible will be.

 

Actually in about 2 hours i had a client and server smothly walking about with no real "predictions". It is too basic for needs of mine, in the future but the simple pemis woulld work well for  asimple game , people might be interested in.

 

All i do is send

{
x,y
direction
}

 


direction is simply 1 up, 2, down, 3 left, 4 right, 0 none.

 

i then check x,y is possible on the server, yes? leave it alone, and send it to the other clients; 
The physics then moves the client depending on the direction. 

-done.
 

Link to comment
Share on other sites

i would be very interested in anyone's thoughts for adding timed events,

for example.

 

1. I throw a grenade. Client A throws a nade.
Client A : Nade thrown, 

Server: Gets nade thrown event, sends to Client B
Client B: Makes Client A character throw a nade

The grenade counts to 3, and explodes.

Client A nade would start counting seconds before the Client B nade.

if i want the grenade to explode at exactly the same time on both clients , any thoughts?

the only ideas i have right now are to work out the time differences. Add this to the explosion time, as the server will start to count from when it gets it.

 

Now, how to add timings to the server properly? hm

or just left client a see the explosion first and only kill client B if the explosion after 3 seconds of the server, catches the player is it's position.

Link to comment
Share on other sites

Re: maunovaha

 

No i dont mean teleportation, because the path taken should be smoothed when corrected with real accepted server packets.. it should not look awful if its applied correctly and to correct games where objects are more predictable.. e.g. racing, tank games..

 

 

That is interpolation.
 

Thus, I agree that terminology is rather confusing.. as dead-reckoning is basically same as extrapolation in the literature.

 

 

Yeeah :/

Re: Elgan
 

The phaser.maths i want to be exactly the same on the client and the server. I was going to start ripping it out and leaving all of the display stuff behind. Physics will not exist on the server but checks if the position is possible will be.

 

Actually in about 2 hours i had a client and server smothly walking about with no real "predictions". It is too basic for needs of mine, in the future but the simple pemis woulld work well for  asimple game , people might be interested in.

 

Quote

All i do is send

{
x,y
direction
}

 


direction is simply 1 up, 2, down, 3 left, 4 right, 0 none.

 

i then check x,y is possible on the server, yes? leave it alone, and send it to the other clients; 
The physics then moves the client depending on the direction. 

-done.

 

 

If you are sending position, you are doing it bad.

Unless of course you are perfectly fine with cheaters modifying their outgoing packets.

You should only send input (keyboard etc).

EDIT: Actually, this may be ok to do in some player-aim situations.
i.e. The exact angle the player was aiming at, or something.


 

or just left client a see the explosion first and only kill client B if the explosion after 3 seconds of the server, catches the player is it's position.

 

Not the end-all way of doing things, but this *is* the most sane.

Some extrapolation (essentially fast-forwarding) between remote clients also helps.

Link to comment
Share on other sites

as i wrote, i send 04-. which are directions. There is only positions on error corrections.
x,y are simply for position corrections on other dumb clients.

 

trying explosions but as i allow slight differences in the position of the players over the network, the explosion radius can vary and be different to what the player thinks, and might be upset, the explosions need to be in the exact same place./ Difficult because the player when creating the bomb, throwing it, is in the future compared to the other players. Then depending on the physics rate the player may be slightly in a different place or catching up. 
Weird to explain,

 

but the only way i can think of is to detect input, not spawn a grenade for the player A, but only spawn it after the server sends a spawn at "this point", but then a delay might occur between input like quake1.

The next solution is to send input to the server and position, check is it fine, then send the player on other clients to this position if that position was ok. I can not simulate the movement on the server as it's so physics based it's impossible.

 

 

The server is bare bones and including phaser for maths, its quite nice imo, and i will share it once it;s working well

Link to comment
Share on other sites

  • 2 months later...

Sorry for the semi-necro but I came across this post and decided to test running phaser on nodejs for a research-prototype-ish project of mine.

However, I ran into an issue where node says Phaser doesn't have some methods defined... They are defined in Phaser.Game.prototype after they're called in the Phaser.Game function so I'm guessing there's an issue with it not exporting them properly... Any ideas on how to fix that (other than moving all these functions around by hand)? I'm fairly uneducated in the javascript / nodejs ways of doing things...

Link to comment
Share on other sites

  • 1 year later...

Running Phaser as a serverside authoritative server is about the same logic as triple A game running their ENTIRE client as a server. Can you imagine the bandwidth and resource usage?

 

I'd say Phaser on the server is a bad idea because it ends up being highly wasteful and not efficiently targeted towards doing just what is needed. An authoritative server should complement but not replicate exactly the client code, and should in most cases also not run at 60hz - typically servers have a tick rate of 10-30hz and clients interpolate that information.

 

This is a fantastic article outlining the requirements and pitfalls associated with client/server architecture: https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

 

Agree, this is where client prediction comes into play for handling movement and other mechanics.

 

For example, in my game if you are shooting a skill like so:

 b56a0bda823c29f0c8fad1178bf91a1d.gif

 

The x and y positions need to be sent over the websocket pipe and there is no way to validate their positioning server-side UNLESS you literally send every single mouse movement to the node server and track everything, which is beyond wasteful and not intuitive whatsoever. (Well, I guess it's intuitive.. but not ideal) 

 

So, while sending the x and y positions over the pipe so other people in the game can know if a player is shooting balls or using a skill.. The server should take in these numbers, cast them as integers only, check for cooldowns, and other stuff and make sure the numbers are in a certain range. Because we can never trust the client and players can literally send commands through pressing F12. That's how easy it is really.

Link to comment
Share on other sites

I personally tried running Phaser.js inside Node.js and sending the game state once every 100ms or so and the game was running smooth and Node.js was only using like 10% CPU. The bandwidth is not affected by the things you do on the server as long as you send only the parts of the game state that matter (player positions, velocities, healthbars, etc...). And, as for server-checking a very fast paced game like the one above, it's almost impossible, this is why most multiplayer games have some sort of inertia to the player or cast times for spells and skills (eg: you use a fireball, but it takes like 0.5 second playing the cast animation of that spell). (I say it's impossible with basic algorithms, as you can check as valve does by setting the server state in a past state based on the timestamp received from the player, but still if there are multiplayer players they won't be able to see those fast-paced movements immediately so they can't react)

 

So, as long as your game is not a very fast paced one and you don't need hundreds of servers, I think running Phaser inside Node.js is a good idea, the best reason to do this: you can simply copy-paste the code from the client side without any modifications and the game will run on the server.

Link to comment
Share on other sites

  • 4 months later...

Really interesting thread I found just now. 

I don't think putting too much of a load on node.js by running Phaser on the server-side is a valid concern. The resource-intensive stuff in Phaser is all tied to rendering. Performance-wise, it's not going to make any difference by including Phaser's classes on the server-side... just as long as you strip out all the rendering logic. 

I am right now in the process of writing the networking layer for a fast-paced multiplayer game (not Feudal Wars) with socket.io. I was looking to implement Phaser on the SS to validate data sent from the clients but I'm beginning to think it's not a good idea. Not because of the performance thing, but because it may be unnecessary and over-complicates things. After all, the only things I need on the server-side are a few things out of Phaser.Math and my physics class, to validate client input. Perhaps I'll just rip that stuff out and make it available on the server. 

The functions you need to run on the server are purely mathematical. The client should perform the actual collision detection - the server should validate it. e.g. if an object started with a certain x/y velocity, is it possible or likely it could collide with another object in this time frame? If server answers yes and client says there was a collision, continue, do nothing. If server answers no and clients says there was a collision, force the client to make a correction (if it was a reasonable mistake) or kick the client if it's an obvious hack. That's how I'm approaching it for now. 

I've had great success by simply sending rotation and x/y velocity. I send the positions as well, but the positions are ignored UNLESS there is a large enough discrepancy. This gives the appearance of very smooth and very fast movement. Only rarely are my positions far off enough to affect gameplay. When that happens, I make a correction on the client side. Works like a charm! 

 

Link to comment
Share on other sites

  • 1 month later...

From what I have read, some people have done it. You can extract the physic calculation code and send the correct variables to get the correct calculation. I run phaser with node.js as a server backend, but use mostly client side calculations.

Link to comment
Share on other sites

  • 11 months later...

I love it and thanks for showing what you did via GitHub!

I'm teaching my kids programming by helping them to build a robot combat style game with Phaser.

While they are learning the basics of Javascript I've been digging into Phaser and working on getting the client - server setup going.

My kids were all worried about cheats/hacks (and rightly so) and I explained that most hacks are just client hacks (e.g. the user hacks their own client) and that they only work because the server does little or no sanity checking on actions that the clients take.

To avoid these problems we are going to start with a client server model where clients make requests and the server validates everything and tells the clients what happened. The game play will be such that if we can get 3-4 ticks per second for 4-5 players we will be solid.

The server:

  • Game States: World Initialization, World Running, World Shutting Down
  • Validates all in game client actions that could potentially be abused.
  • Sends game state frame updates via socket io to clients that should know about them
  • Saves the game state when the server goes down (if possible)
  • Won't bother with tweens, particles, etc... just object states and collisions.

The clients:

  • Various Game States: Waiting to Connect, Loading, Waiting to Join, Entering Game, Robot War Mode, You Died, etc.
  • Makes request to the server in response to player actions
  • Reads responses from the server to update the players display via tweens

No potentially game breaking action will take place on the client side.

Doing things this way will let me introduce my kids to a few topics that I don't see talked about a lot:

  • Client Trust
  • Server / Client messaging and optimization
  • Database storage of game states and objects
  • Deciding where to make trade offs between potential hacks and performance

We will be starting simple (in good part to show where performance issues are and what is needed to address them) and once we have things running we will then start worrying about how to improve performance.

Anywise, thanks for the great thread. Lots of food for thought and some solid information that will likely save me a lot of headaches.

Hopefully by the end of this coming weekend we will have a very simple client / server set up and within a couple of weeks have a basic online multi-player game running for them and their friends that includes robot combat, junk scavenging, inventory, energy management, repairs, etc.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...