Let's talk about netcode

Recently I've started playing around with Godot. So far I got a basic "walker" type of game logic, so I decided to go for adding multiplayer support. And that got me thinking: what is really the best way to do exactly that? Most multiplayer solutions just update entities' positions across multiple clients. Older ones such as Doom just sends player commands, so the client does the simulation and updates positions based on commands. And there is probably something else that I left out. I thought I'd open this topic up for discussion.
89 Replies
KeithBrown7526
I dont know if im explaining this well enough, but im going to go ahead and try. This is probably very inefficient, but i would go along the lines of something like the game is stored as an object (im going to visualize it with JSON) say you have the following game
const game = {
player1: {
position: {
x: 546,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
}
const game = {
player1: {
position: {
x: 546,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
}
this needs to be kept up to date between all players now saw player one moves in a direction 3 units in this example, on the x axis
const game = {
player1: {
position: {
x: 549,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
const game = {
player1: {
position: {
x: 549,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
instead of resending the new object in full, check what changed and only send what changed so instead of sending
const game = {
player1: {
position: {
x: 549,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
}
const game = {
player1: {
position: {
x: 549,
y: -86
}
},
player2:
position: {
x: 546,
y: -86
}
}
}
this to all the players, send this
const update = {
player1: {
position: {
x: 549
}
}
}
const update = {
player1: {
position: {
x: 549
}
}
}
and then merge game (the data the players currently have on their local device) with update (the new data the server just sent) this is bound to have its issues, but for someone who has never actually looked into how online gaming data sending works, id say this is a pretty good idea @polyzium
polyzium
polyzium2y ago
Quake 3 uses the same pattern here I mean that would make total sense to only update what has changed but for compiled languages this may pose a problem if you unmarshal the data into a struct. position.x is the only value updated, then what's position.y? Zero? That's UB right here
KeithBrown7526
can you not merge objects in go? for example
const $1 = {
x: 1,
y: 2
}

const $2 = {
x: 2
}

// This becomes
const $3 = {
x: 2,
y: 2
}
const $1 = {
x: 1,
y: 2
}

const $2 = {
x: 2
}

// This becomes
const $3 = {
x: 2,
y: 2
}
polyzium
polyzium2y ago
Nah it's not in Go
KeithBrown7526
oh wait i misunderstood you said godot i thought go
polyzium
polyzium2y ago
In JS this could be done nicely with things like Object.assign, dunno about other languages, never did C# Currently using GDScript for prototyping, which is loosely based on Python But I'm sure I'll figure something out Anyways, another problem to tackle is: does the server do the gamesim and send the player positions, or should that be relied on clients? The latter would take some load off, but would introduce vulnerability to hacks. I believe that's what Minecraft does.
Dumb Bird
Dumb Bird2y ago
Like you said this makes hacking really easy. Though this is what most people do, though it does (like you said) make your code vulnerable. I’m not sure how powerful your server is going to be. So I’m not sure dealing with everything on the server will work good. There will probably be quite a bit of latency
polyzium
polyzium2y ago
There will always be latency but can be mitigated with interpolation, sort of
Dumb Bird
Dumb Bird2y ago
Of course latency is always a problem but doing all player movement and physics on the server will be worse
polyzium
polyzium2y ago
Worse in what sense? Latency?
Dumb Bird
Dumb Bird2y ago
Yes. Doing all physics on the server would result in more latency for the players.
polyzium
polyzium2y ago
Well GMod multiplayer somehow does work with all of that, I haven't looked how exactly does it work but it somehow does
Dumb Bird
Dumb Bird2y ago
It may work, I’m pretty sure games do this. Though most of the time for this to succeed you need a good powerful server Calculating basic movement and physics isn’t very hard to do. When you start adding more physics based things (wether that be a prop or similar) to your game your only adding more work for the server
polyzium
polyzium2y ago
That is a call for stress testing
Dumb Bird
Dumb Bird2y ago
Yes. I do think this method is best for avoiding cheaters to some degree. It should stop any movement based cheats Though I think doing the physics for 10 or so players at the same time may cause latency issues. More so if you were just to do movement on the client side
polyzium
polyzium2y ago
How more if it's on client?
Dumb Bird
Dumb Bird2y ago
Not more latency on the client. When I said that I was referring to the “doing physics on the server” method. When I said “more so” I was just trying to shorten saying. “you’ll end up having more latency dealing with physics on the server, more so then if you were just to do physics on the client.” If that makes any more sense
polyzium
polyzium2y ago
Oh I get what you mean now < fluent in Broken English
Dumb Bird
Dumb Bird2y ago
That’s fine lol I understand as English isn’t your first language I presume
polyzium
polyzium2y ago
I thought you already knew that?
Dumb Bird
Dumb Bird2y ago
Well I know your Russian though I wasn’t fully sure, 90% sure English wasn’t your first language
polyzium
polyzium2y ago
I mean that's true but surprisingly you got confident in this fact only now lol anyways Doing clientside physics may introduce desync issues between players so one player sees another player in a totally different place than where they should be
Dumb Bird
Dumb Bird2y ago
How so? If done right I don’t see how it could. Unless the player has a bad pc and can’t do physics
polyzium
polyzium2y ago
GUess what, that's the same scheme GZDoom follows If the player has a low spec machine it will lag the crap out of you and others because opthers have to wait til the other player unlags
Dumb Bird
Dumb Bird2y ago
I don’t think desync will be that huge of an issue. I mean in games when people are lagging the jump all over the place That’s just life using this method I’m games where this method is used when people lag they teleport and such Not sure how good of an option this is but, I guess you could just do physics on the client for the player. Then send their position to the server, and forward that data to all players So even when lagging this shouldn’t be hard on other users And it may create that “teleporting” effect when people are lagging
polyzium
polyzium2y ago
Like I said, this can be mitigated with interpolation.
Dumb Bird
Dumb Bird2y ago
Interpolation of what?
polyzium
polyzium2y ago
The player's position.
Dumb Bird
Dumb Bird2y ago
Interpolation to me is that wacky string that lets you have placeholders. Please elaborate
polyzium
polyzium2y ago
So instead of teleporting 0.5m-1m away from their previous point, they will move smoothly between them, and the travel time is their ping. So if their ping is 200ms Instead of teleporting several centimetres away from their previous position to a new one after 200ms
Dumb Bird
Dumb Bird2y ago
Ah
polyzium
polyzium2y ago
The player will move smoothly between them during these 200ms
polyzium
polyzium2y ago
Linear interpolation
In mathematics, linear interpolation is a method of curve fitting using linear polynomials to construct new data points within the range of a discrete set of known data points.
Dumb Bird
Dumb Bird2y ago
I see. Well try it out I guess. I still don’t think dealing physics on the server is a bad idea. Though I think latency will only grow and exponentially quick depending on the number of players I think this method is ok but I don’t do server stuff with games Have you tried searching up what most games do for multiplayer?
polyzium
polyzium2y ago
If you're making a competitive game, this is critical, but for anything else it'll do Actually I think most games use it so the server does not get loaded it's a performance saving measure after all
Dumb Bird
Dumb Bird2y ago
Yeah
polyzium
polyzium2y ago
Godot has something called rpc_unreliable which sends player commands over UDP if I'm not mistaken. Most tutorials use that but I want to go for a different approach
Dumb Bird
Dumb Bird2y ago
lol “unreliable”
polyzium
polyzium2y ago
If you think about it, it makes sense because UDP is an unreliable protocol. Not unreliable in sense "it crashes/it performs like shit" etc In sense that the packets don't have to reach the end destination
Dumb Bird
Dumb Bird2y ago
Oh, that’s not good
polyzium
polyzium2y ago
If you're updating player positions, UDP is good If you get a temporary packet loss in TCP, you'll receive a big batch of player position updates (when the connection comes back up obviously) that become redundant after, and only the latest packet is accounted If you get the same with UDP, you'll receive only the last packet. only that and everything that comes after obviously
Dumb Bird
Dumb Bird2y ago
Ah, so UDP is much better for player movement and physics
polyzium
polyzium2y ago
My explanation might be oversimplified, but in general, yes. For stuffs like data transfer, player commands, anything that HAS to be received by the client, go for TCP instead.
polyzium
polyzium2y ago
GitHub
GitHub - ValveSoftware/GameNetworkingSockets: Reliable & unreliable...
Reliable &amp; unreliable messages over UDP. Robust message fragmentation &amp; reassembly. P2P networking / NAT traversal. Encryption. - GitHub - ValveSoftware/GameNetworkingSockets: Re...
polyzium
polyzium2y ago
This is just a wrapper around TCP/UDP with both reliable and unreliable messaging features. It can also exceed the regular TCP/UDP packet size.
Dumb Bird
Dumb Bird2y ago
Valve devs got some big brain people down there
polyzium
polyzium2y ago
I'm struggling with English today pls help Anyway, there is also the C# bindings, which could integrate well with Godot's C# language support.
Dumb Bird
Dumb Bird2y ago
I’ve never played with anything but GDScript. Using libraries is possible with C# and Godot?
polyzium
polyzium2y ago
I guess so, if Godot allows C# and GDNative with it as well. There are also bindings for Lua, Python, Rust, etc. for Godot, so go wild. @earth's bird I'll try implementing multiplayer right now
Dumb Bird
Dumb Bird2y ago
Alright, best of luck
polyzium
polyzium2y ago
Well well well first problem I encountered is that my player controller is entirely hardcoded to be interacted with a keyboard and a mouse I could go two ways. First one is to create one player class for everything and then "posess" it using a keyboard and a mouse Or create a special networked player class for network players only Ugh Godot networking is so confusing
Dumb Bird
Dumb Bird2y ago
Making multiplayer in general is
polyzium
polyzium2y ago
Why is RPC for multiplayer even a freaking thing
Dumb Bird
Dumb Bird2y ago
¯\_(ツ)_/¯
polyzium
polyzium2y ago
That is a security vulnerability
Dumb Bird
Dumb Bird2y ago
Why don't you just watch a tutorial? It's probably the easier route
polyzium
polyzium2y ago
Also, the rpc() function does what? Sends? To who? Everyone? This is the reason I'd prefer to use raw sockets or a mid-level abstraction thereof so I have full flexibility
Dumb Bird
Dumb Bird2y ago
I see I'm pretty sure Godot has mid-level abstraction Does it not?
Dumb Bird
Dumb Bird2y ago
Godot Engine documentation
High-level multiplayer
High-level vs low-level API: The following explains the differences of high- and low-level networking in Godot as well as some fundamentals. If you want to jump in head-first and add networking to ...
polyzium
polyzium2y ago
GitHub
GitHub - perdugames/gdnet3: An ENet wrapper for Godot 3.
An ENet wrapper for Godot 3. Contribute to perdugames/gdnet3 development by creating an account on GitHub.
polyzium
polyzium2y ago
Does exactly what I need OK wtf is wrong with me If I'm going to use JSON then how would Godot serialize stuff like Vector3?? Why am I getting my theoretical knowledge fully ready before doing it in practice PSA: Godot cannot serialize classes
Dumb Bird
Dumb Bird2y ago
I'm pretty sure it can actually
polyzium
polyzium2y ago
Until I realized I was trying to replicate the Go's messaging workflow in GDScript which totally won't work as GDScript classes have no "tags" compared to Go structs so the marshaler does not understand how to name that class field and instead returns a generic object think of it as an JS [object Object]
Dumb Bird
Dumb Bird2y ago
So I assumed you've already resolved this issue?
polyzium
polyzium2y ago
No Still searching for an elegant netcode solution
Dumb Bird
Dumb Bird2y ago
Not 100% sure if this helps in any shape or form, but here you go
Dumb Bird
Dumb Bird2y ago
Godot Engine documentation
Saving games
Introduction: Save games can be complicated. For example, it may be desirable to store information from multiple objects across multiple levels. Advanced save game systems should allow for addition...
polyzium
polyzium2y ago
I have so many questions in regards to futureproofing what if I wanted to do delta compression, or VoIP
Dumb Bird
Dumb Bird2y ago
I don't see how (if you are) saving the state of a player relates to VoIP; a voice transmission protocol. For delta compression I'd have to look into, as to be quite frank I've never heard of it
polyzium
polyzium2y ago
Delta compression is basically sending only what has changed against a previous game state previous game state that a player has received, that is That's the same pattern Quake 3 uses As for VoIP, this might pose a big problem cuz if I were to do communications over one connection then uhh jeez this is so confusing
Dumb Bird
Dumb Bird2y ago
Then I'm not sure what would be the issue? With Godot's example they say you can use functions like to_json() and parse_json(). Instead just return a JSON of what has changed against a previous game state
polyzium
polyzium2y ago
Problem is Godot cannot serialize classes in the same way Go serializes structs
Dumb Bird
Dumb Bird2y ago
Well they're two different things
polyzium
polyzium2y ago
both to_json() and JSON.print() return the same value And instead you have to make some sort of a dict wrapper like described in docs
Dumb Bird
Dumb Bird2y ago
Yes
polyzium
polyzium2y ago
So that's a major issue foir productivity define. everything. manually.
Dumb Bird
Dumb Bird2y ago
You may benefit from joining the Godot Discord server. I can send you an invite if you'd like
polyzium
polyzium2y ago
I spoke with them, TLDR in GDScript it requires generating a dict, and doing that requires some half-assed ways of doing that Honestly I'm better off going the C# or Go bindings route
Dumb Bird
Dumb Bird2y ago
I see You may be.
KeithBrown7526
@polyzium is there no equivalant of JSON.stringify?
polyzium
polyzium2y ago
JSON.print but the classes in GDScript are half assed when it comes to serialization
KeithBrown7526
thats stupid
polyzium
polyzium2y ago
Indeed it is, that's why you'd better resort to C# or Go. I might even pick up Rust some day just hope that it doesn't melt my brains again C# still leaves me with a feeling of disgust, because, first of all, it's Java but worse, and second, Microsoft
Dumb Bird
Dumb Bird2y ago
Not everything Microsoft tends to be bad but I agree C# is bad
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
polyzium
polyzium2y ago
Still, Microsoft
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
polyzium
polyzium2y ago
Even if it is you'd still be dependent on nuget At least java is more open Both have classes Both use bytecodes
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View