Shared Multiplayer Objects

I’m building a 3D board game and have some dice that I need players to be able to roll. It’s all working fine for single player but when I add multiplayer, I can’t seem to get the functionality I’m looking for. Whatever I try, only the “host” seems to be able to control the dice, any attempt by the “client” to pick up and roll the dice results in either an error (client doesn’t have authority) or the dice just reverting back to the initial position (as defined on the host) or the dice being completely independant on each client - NB the dice are scene objects if that’s relevant.

I’ve had a look at the multiplayer tutorial which seems to helpfully go through all the different scenarios but in the “Handling Non-player objects” section it mentions “For this example we will ignore environmental GameObjects” which I think is essentially what I’m looking for i.e. an object that sits in the environment and not owned by any player. There must be a way to accomplish this as there must be many cases where a non player object needs to sync e.g. opening a door on one client should open it on all clients but the door isn’t “owned” by the player right?

Hope someone can help!

Thanks

Edit: I’m using UNet

I’m assuming this is with UNet. In UNet only the client with authority can manipulate networked GameObjects (outside of local only changes). For something like this I’d go one of two directions. Either transfer authority of the GameObject to the client you want to roll the dice, or keep server authority over the dice objects and have the clients always issue a command to the server to roll the dice.

For the first one, use AssignClientAuthority
https://docs.unity3d.com/ScriptReference/Networking.NetworkIdentity.AssignClientAuthority.html

For the second one, you issue a Command, but a Command can only be issued by a client on a GameObject they either have authority over or is their Player GameObject. So you put your dice rolling Command on the Player GameObject, and you check on the server that it was that client’s turn to roll the dice, and if so you have the server roll the dice for the client.
https://docs.unity3d.com/Manual/UNetActions.html

2 Likes

Thanks for the reply.

I think the penny has yet to drop for me as I still can’t seem to get this working.

I’ve read the UNet docs and I’m aware of both of the suggested approaches but I can’t get either working - UNet is definitely one of the most frustrating frameworks I’ve ever come across.

I can’t get AssignClientAuthority to work as this apparently can only be called server side and when I put it in a command I (ironically) get the error “Trying to send command for object without authority” - seems like a catch 22 situation here!

The other way you suggest also results in the the same issue “Trying to send command for object without authority” so I’m unsure how to proceed.

I’m utterly confused as to where the commands need to be and how authority seems to work, every example I find shows how to move the player object, nothing about moving non-player objects.

As I previously mentioned, put your commands in scripts attached to your Player GameObject if that client doesn’t already have authority over that other object. A client can always send commands using their Player GameObject regardless of authority. That client’s Player GameObject is the one when that client checks isLocalPlayer it returns true.

I’d do something along these lines on a script on the Player GameObject. Have the server set thisPlayerTurnToRollDice when it is that player’s turn, etc.

public void TryToRollDice()
{
    if (isLocalPlayer)
    {
        CmdRollDice();
    }
}

[Command]
void CmdRollDice()
{
    if (thisPlayerTurnToRollDice)
    {
        DiceObject.GetComponent<DiceControl>().RollThemDice();
    }
}

you have a board game and its turn based.

  1. There will be in game objects like dice and other stuff which can be controlled by all participants, in that case in host do “NetworkServer.Spawn(_object)”, Please note that your “_object” here should be instantiated, PLUS if you are using NetworkManager then pls add _object to spawned object list.(I am assuming you have already done it)

  2. Now these “Spawned” objects have should be check it with “Local Player Authority”.

  3. Now if host has played turn and Player 2 has turn, then you should change Authority of those “Spawned” objects which should be controlled by client, need to change Authority by Host. So , on Host, on each shared network object, call “AssignClientAuthoirty” with proper argument.

  4. Now to sync the position and rotation to all connected devices , Your objects should have “NetworkTransform”.

  5. After this , all connected player will update respective object transforms to newly assigned authority Player’s transforms for those objects.

  6. Again When turn ends, assign authority to new player who has their turn.

I hope this may help you.

Thanks or all the suggestions but I seem to have resolved the problem - turns out my code was fine.

Initially I was using scene objects for the dice but I switched to using a spawner and spawned the dice using a server side script which seemed to then allow me to control them.