In a dedicated server game, it is almost always necessary for the client and server builds to exclude each other’s code for security and other reasons. If I wanted to do this with Unity Netcode for Gamobjects, what is the recommended way to do this?
I think I would personally want to create a separate project for the server and client but this breaks down NGO since the network object hashes would no longer match. I’ve tried this and while the client project build connects to the server successfully, I get an error upon connection stating that “NetworkPrefab hash was not found! In-Scene placed NetworkObject soft synchronization failure for Hash: 2856946884!” This is because that is the hash of the object on the server and the client object hash is different.
In particular, I’m working on a turn based game right now and only need to send messages between clients and the server. My idea was to use RPCs to send player intent to the server, have the server validate it and compute changes to the game state, and then send an RPC to let the client to know how to update the visuals to represent the change in game state. The server completely handles game state logic and the clients merely hold a visual representation of the state. It is critical that the game logic only exist in the server build in my project.
Is there a way to sync up network objects to use RPCs between 2 different projects (the client project and the server project) or should I look for an alternative solution? I read about Custom Messages in the documentation. Could this be a solution? Is there anyway at all to send information between separate unity projects? I would prefer not to put all server logic everywhere in my code inside a pre-processor directive to exclude it from the client.
The security issue is mainly because of the code exposing any weaknesses. The best defense against that is defensive programming on the server side regardless of whether the code is in the client or not. While separating the server code makes it hard to find a way to for example crash the server, it doesn‘t take much longer experimenting with tempered packets to find that same security hole for an experienced hacker. It is similar to copy protection: it only delays the inevitable, and often by ridiculously short amounts of time if at all.
Two projects is not a good solution, it probably won‘t even work with NGO and definitely will greatly increase friction during development. Instead, you simply need to have #ifdef around the ServerRPC messages and the crucial server side methods that you want to „hide“ from clients by supplying only an empty stub for the server method in the client build. It should suffice to do that for selected server methods or classes.
Thanks. I also realized I can use assembly definitions to exclude non-networked server code from the client build and vice versa without having to put #if UNITY_SERVER around every class. While putting a define around every RPC’s code is a bit annoying, I suppose it it may not be as bad as managing separate projects.
I’m still curious about if it is possible to send data between 2 different projects with NGO.
You can connect between different projects, you’ll just need to match these settings of the network manager:
// from the source code
writer.WriteValueSafe(TickRate);
writer.WriteValueSafe(ConnectionApproval);
writer.WriteValueSafe(ForceSamePrefabs);
writer.WriteValueSafe(EnableSceneManagement);
writer.WriteValueSafe(EnsureNetworkVariableLengthSafety);
This works fine if you avoid network objects and just communicate with custom messages.
To clarify regarding “network objects”, that means you cannot use NetworkBehaviour (and derived classes) and as far as I understand, no NetworkVariable compoments either, since both depend on project-specific hashes of the associated objects. RPC messages and low-level transport API work across projects.
I was not able to get custom messages to work between different projects since they too require a networkobject and network behaviour, at least, according the documentation examples. Skipping NGO and just using Unity Transport was the only way I could get it to work. Can custom messages be sent without being in a networkbehaviour?
While I still currently plan on having the client and server be the same program for the gameplay, I want to implement my own matchmaking queue and database relay for handling user data in the menus between logging into the game and joining the matchmaking queue. I feel that the best way to handle this to make it a separate program.
You don’t need to use network behaviours, in the examples I think they use them to simplify things as the custom messaging manager isn’t available until the network has started. The way I have it setup is to grab the NetworkManager.Singleton.CustomMessagingManager in OnServerStarted / OnClientConnectedCallback and put it in a message handling service.
If you choose to stick with Unity Transport let us know how you get on as I’ll likely be switching over to it at some point.