The last time I reviewed Unity multiplayer I observed that it requires a server build of the Unity player. The alternative would be a platform agnostic set of APIs that handle transport and state synchronization, which works inside and outside the Unity runtime. Where did you guys end up with architecture?
Full disclosure – while waiting for Unity multiplayer to release, I built a server-authoritative solution that runs in Azure and doesn’t require creation and deployment of Unity players. I like it very much, but I am always interested using the best solution available.
Today, Unity offers a range of solutions for building multiplayer experiences that don’t require game servers running the Unity engine:
client-hosted games with either Netcode for Game Objects or Netcode for Entities
distributed authority with Netcode for Game Objects
managed Cloud Code functions and Cloud Save persistence (for turn-based games)
The larger ecosystem of multiplayer solutions for Unity include additional frameworks and middleware that also don’t run Unity on the server side. To name a few:
DarkRift2
Nakama
Beamable
AccelByte
This is an area that Unity is actively exploring.
Stay tuned for announcements in this space!
It appears to me that all of the official Unity managed solutions capable of updating game object positions require Unity running as a game server. Maybe I misunderstood your answer?
It’s exciting to learn about someone on a similar path. Would you be willing to share more about the architecture you settled on?
I’m using WebSockets hosted within a C# host that runs locally for player managed servers and in Azure for a mesh of game servers.
Each player session creates two socket streams. One stream is for spatial updates and another stream is for controlling game state.
I recreated Unity’s position and rotation structs for server-side computation and fidelity. The structs are read and written to pooled span buffers, which are delivered to players based on proximity.
The game client has the ability to change client-side and server-side delivery rates.
I learned a few interesting lessons. In my scenario, packet coalescence isn’t helpful because client-side movement is interpolated. I also found that I can get away with sending fewer packets per second than I thought – an update rate of 10x per second is generous with interpolation enabled.
I don’t believe I’m allocating server-side or client-side, but it has been a while since I last tested.
The game server exposes a diagnostics screen so that I use to gauge network traffic for active connections.
I’m a little confused. It seems like your server is only relaying messages? If it is, why not just make it a relay server and have client<->client connections?
The server supports a large number of concurrent players (~128 clients) and does not require session migration.
NPC state, persistence, and ephemeris is maintained server-side
Actions are executed server-side in combination with perquisite state, i.e. you can’t unlock a door unless the server knows you are near the door, and you must have the key in your inventory.
The server persists locations of players and objects. i.e. a player may leave an item on a planet and return later – it will still be there.
Only one endpoint (the server) needs to configure firewall punch through (i.e. NAT).
Other benefits
Cross-platform server hosting. Players may run their own game server on Windows via Steam, while official servers are hosted on inexpensive Azure Linux App Service containers. Azure hosting is attractively priced.
It compiles to .NET 8. The procedural generation logic is 10x faster in .NET instead of Unity IL2CPP.
The memory footprint is smaller than a Unity server instance.
As a lightweight process, it is easy to launch from Unity (second screenshot).
There are many ways to tackle the problem. This is just the approach I took. I learned quite bit a long the way. It fits for my use case, and I understand it may not work for others.
The server supports a large number of concurrent players (~128 clients) and does not require session migration.
NPC state, persistence, and ephemeris is maintained server-side
Actions are executed server-side in combination with perquisite state, i.e. you can’t unlock a door unless the server knows you are near the door, and you must have the key in your inventory.
The server persists locations of players and objects. i.e. a player may leave an item on a planet and return later – it will still be there.
These are some good reasons to have a server-authoritative architecture if your game needs it. There’s a really good use case for using a lightweight non-unity server if your state doesn’t involve complicated physics calculations. I wish it was well documented the interfaces of a working Unity server, or at least, the interfaces of the client. You’d have to reverse engineer it unfortunately .
I know this is a little old but I went down this rabbit hole a few years ago and decided to roll my own system for an authoritative server. I didn’t like mixing Server/Client code in Unity and because I was going for a 2D game recreating the movements/physics was much easier. Overall it’s been working really well and any roadblocks I have hit I have solved them. This also give me the added benefit of switching engine if needed (like to Godot if Unity changes the pay structure) since most of the core logic all sits server side.
How has your implantation been working?
If your interested I started a thread a few years back that I post my progress on it as I find time to work on it.