UNet networking
UNet multiplayer support is built-in, and can be used with minimal setup.
Warning
In order to use UNet you'll have to download the package from the devdog.io website. Optionally, a mirror package is also available.
Server authority
The server is authoritative, meaning that the server decides everything for the player. The player can request certain actions from the server (such as using an item), however, the server will always validate and decide if the action is permitted. This prevents cheating, but does add a roundtrip to the server for each networked action.
UNetItemFactory
The UNetItemFactory
adds bindings to the item factory for UNet specific item types. This makes sure that all items created through ItemFactory
are UNet compatible. You can add this component to any object in your scene. For consistency attaching it to a _Managers or _UNet object is recommended.
UNetActionsBridge
The UNetActionsBridge is the enter and exit point for all player actions.
UNetInitPlayer
The UNetInitPlayer
is a simple component that registers your player locally whenever the server gives permission (OnStartAuthority). Attach this component to your player and disable init on start
on your default Player component.
Naming convention
- Server_* Methods can only be invoked on the server.
- Client_* Methods can only be invoked on the clients.
- TargetRpc_* Methods can only be invoked on the server and relay their message to the client.
- Cmd_* Methods can only be invoked on the client and relay their message to the server.
Danger
The client requires authority over the object to call Cmd_* methods. (see NetworkIdentity).
Permission system
Collections and objects in the world can have permissions assigned to them in the UNetPermissionsRegistry
. By default the user has no permission to any object or collection; All permission have to be set explicitly.
var player = <ASSIGN YOUR PLAYER>;
// Create a server collection. This should only be created on the server side; The client has to receive a client collection with the same ID and name.
var collection = new UNetServerCollection<IItemInstance>(player.identity, 10);
collection.collectionName = "Inventory";
collection.ID = System.Guid.NewGuid();
UNetPermissionsRegistry.collections.SetPermission(collection, player.identity, ReadWritePermission.ReadWrite);
For simplicity there's built-in methods on the UNetActionsBridge that allow you to create collections easily on both the server and client with a single call.
using Devdog.InventoryPlus;
var player = <ASSIGN PLAYER>;
var bridge = player.GetComponent<UNetActionsBridge>();
var collectionGuid = System.Guid.NewGuid();
// This will create a collection of 10 slots on both the client and server.
// The server will create a UNetServerCollection<T> while the client will create a UNetClientCollection<T>.
// The UNetServerCollection<T> will auto. start replicating it's changes to the client collection.
bridge.Server_AddCollectionToServerAndClient(new AddCollectionMessage(){
owner = player.identity,
collectionName = "Inventory",
collectionGuid = collectionGuid,
slotCount = 10
});
// Don't forget to set the permission for this player.
// This will set the permission on the server and notify the client it received read permission on this collection.
// NOTE that the collection has to exist before setting permission.
bridge.Server_SetCollectionPermissionOnServerAndClient(new SetCollectionPermissionMessage(){
collectionGuid = collectionGuid,
permission = ReadWritePermission.Read
});
Input validation
The UNetActionsBridge
uses replicates and validators to sync data between server and client. To make sure the client doesn't send some information that could crash the server or allow the player to cheat all data has to be validated. This is done by the validators.
The validators make sure the GUID data is a consistent byte length, that indices are not out of range and that the player has permission to even perform the action in the first place.
Registries
Registries are used to index certain types. These are useful for the server to quickly find types it needs at an O(1) lookup speed. It's important to register your run-time types, otherwise the server won't be able to properly replicate actions.
Run-time items
Items can be created / generated at run-time. Item instances can contain run-time information, while the item definitions are persistent objects.
How run-time items are created
Item instances have to be registered on the client. This can be done through the UNetActionsBridge
. Note that items are also auto. registered on the client through collection replication.
Note
Registering items on clients manually is only needed if you want to pre-load it, the item is not in a collection, or need the item before it's replciated through a collection.
using Devdog.InventoryPlus;
var player = <ASSIGN PLAYER>;
var bridge = player.GetComponent<UNetActionsBridge>();
// Tell this client to register the item instance on their local client.
bridge.Server_TellClientToRegisterItemInstance(itemInstance);
Network serialization
TODO