What is the underlying purpose of multiplayer netcode? To update the position, rotation and state of all objects in the gameworld.
How many different ways can this be done? Does the sending and receiving of this information need to be native to Unity or is it possible to hand this off to say a custom written DLL? Is the authoritative source of this information the server, the client, or both? Is there a way to use flexible authoritative sourcing to address different networking situations and game object states?
âAAAâ game developers know how to address these questions in any game - and there is always custom code that needs to written to address specific issue that the game engine doesnât address. No matter how good an engine is perceived to be, there is only so much âout of the boxâ will do without customization. And either the game developer can address issues themselves, or they contact the engine developer to help address their issues, or they pay the engine developer to address their issue - or they take an issue that canât be addressed out of the equation.
Iâve read in the forums where people have given up on dealing with certain multiplayer issues they are having with their game. Is it because Unity or their plug-in doesnât âprovideâ for them - or is it because of their own limitation as a programmer? Itâs really a personal decision based on how much of their own time and effort, or money [ buying a solution/expertise] they want to spend on the problem. Because if itâs possible to put a bunch of âsmart peopleâ in one room and figure out a solution to that personâs issue, then itâs not really about Unity.
one limitation i found in my limited experience with unity is that the game update() function cannot be set a fixed rate independent of the frame rate because by it is called before rendering a frame. I think this makes it very hard to implement any sort of client-side prediction and/or latency compensation.
As iâm being right into netcoding a fighting game (which migh be the most unforgiving genre in term of lag management, as every milisecond counts), I can put my experience with unity here : nothing has been wrong so far.
I can connect two different OSes (been playing from my Mac against my Windows client)
Transfers are much faster than .NET udp
Network class is very reliable, Iâve yet to see a connection/disconnection not sent in time
as for lag predictability, itâs totally up to the coder to do that. Plus, it doesnât need a fancy engine implementation imo, as itâs really no big deal to manage.
Just create a coroutine WaitForSeconds(estimatedLag) each time you perform a local command that has to be sent on the network, so itâs synchronized. (this description is indeed vulgarized, in my case Iâm sending the player command, and will not trigger it locally until Iâve received a distant validation. The distant player will not replicate that command locally until [estimatedLag] amount of time is elapsed.)
Anyway, every move I send is perfectly synchronized right now on both clients, I really donât have any problem with Unity network features.
Also, the âfeelâ, whatever it is, is only up to the coder, not the engine. Plus it is imho a clear mistake to let the engine decide that feel, as it creates complete generic games (aka people saying âoh, one more Unreal Engine game ⌠they all look/feel the sameâ).
p.s : I canât see how any quite complex game netcode could not be homebrew. For optimization reasons, for starters. Or even for processing order management. For example, still in my case, Iâve put all the control processing right at the end of the visual update loop, so in case of lag, player wonât react on corrupted visual feedback. This custom cooking cannot be made with generic engine features.
As npsf wrote, FixedUpdate(). Even further : coroutines, so you can put on hold an update until âsomethingâ has finished.
Plus if Iâm not mistaken, Update can be set as a coroutine. And anyway, without coroutines, itâs quite easy to just stop a FixedUpdate process if a condition is not met (like myCustomNetworkSync == false).
Between Timers, Threading, and Native Plugins you have a lot of control about how your networking and game logic works - and can relegate Unity to a glorified renderer if needed.
For our newest project, we chose Unity as engine. Not because it looks nice, or has lots of nice features other engines do not have. No, most other engines are actually 1000 times better than Unity.
We chose Unity because it is the perfect solution for multiplayer games. Together with Ulink and some self written code, you can achieve greater results than in any other engine. We are seriously thinking of a 500 player FPS game. Our first tests have proven that 350 players work perfectly fine, and we are still working on our netcode. No other engine could have offered playernumbers that are even close to that.
I apologize for the necro, but I would like to add two cents to the argumentâŚ
Source Engine is fantastic for FPS games. Why is this? Because it was forked from an FPS game, then modified for another FPS game, then iterated over many years for more and more FPS games. In short, everything about the Source Engine was DESIGNED for FPS games. Thatâs not to say it canât do other games, but FPS are itâs specialty.
Itâs also the same with UE, although a bit different. UE was designed originally to power Unreal Tournament, a Quake-style multiplayer FPS. While UE3 may have abstracted a lot of functionality to the point where you can really write any game, you can still clearly tell it was originally designed for a first person shooter.
Unity, on the other hand, was built from the ground up as a diverse game engine designed for any idea you could possibly think of, completely unlike these other two engines.
That being said, a great FPS is not impossible in Unity. There are plenty of articles on how Valve does their netcode, why would it be impossible to replicate that in Unity YOURSELF? Itâs not impossible. It might take several FPS iterations to get to that perfect mix, but itâs not impossible. And this should be the responsibility of the developer, not Unity.
Which, again, is yet more evidence that Source was designed primarily for FPS games - where typically you only see up to 32 players running around in the same game, MAYBE up to 64 but thatâs pushing it.
Whereas Unity was designed to be flexible to do whatever the hell you want it to do. 1,000 player FPS? Sure, why not?
If youâre trying to do a good networked FPS in Unity (read: with proper rewind/replay networking that doesnât melt your processor or framerate), the less of Unityâs time / physics / APIs / component / event model you rely on the better. The closer you get to Unity being a off beat metronome that knows how to raycast and draw the better off youâll be.
Iâm not sure I agree with some of those. Iâm using plenty of Unity APIs just fine, and itâs actually turning out to be really easy.
If anybodyâs curious, hereâs my setup.
I have an EntityRewinder component. This component stores the transformâs position every frame up to a second. It has two functions: Rewind, and Restore. Rewind will store the entityâs position, and then rewind the entity to the given past timestamp. Restore does what it says on the tin: restores the stored position.
I then have each EntityRewinder register itself with a static List, and I have static versions of the two aforementioned functions that iterate over this list and call the corresponding function on the EntityRewinder. So basically I can call EntityRewinder.RewindAll and EntityRewinder.RestoreAll to perform entity rewinding on everything in the scene.
Now, I also have a HitscanManager. This manager has a networkView attached to it so that it can perform RPCs. From the client, when you want to shoot someone, it makes a call to HitscanManager to do a bullet raycast. The HitscanManager does an RPC on the server. The server performs the actual hitscan logic:
Find the difference between current network time and the timestamp of the message
Use the difference to rewind all entities
Perform the raycast (if it hits a player, send damage or whatever the raycast was for)
Restore all entities
And now I have entity rewinding. Easy as pie.
I would say itâs not about avoiding Unityâs API at all. Itâs more being smart about using them.
That works if all you care about is rewinding for hitscan. I rewind actual projectiles, pawns, items, and potentially the entire game state and âreplayâ it forward tick by tick back to the current time, resulting in potentially different player / item positions / collisions / state, not just restore with modified health values. And this happens on both the (fully authoritative) server and clients to varying degrees.