Distributed Authority Force Redistribution

Hello,

Is there a way within the new distributed authority framework to directly call a function that redistributes the ownership of distributable network objects?

Currently, my game session starts within the lobby screen when someone clicks on “CreateLobby”

Then, once everyone in the lobby clicks “ready”, the game is begun by the NetworkSceneManager loading the game scene.

The first player to load in spawns all the network objects and is assigned ownership, but since other clients are already in the session, objects with the “Distributable” flag assigned to it won’t get distributed, as I’m aware this only occurs when a client leaves/joins the session.

The code to handle the redistribution must be somewhere, is anyone able to point me in the right direction?

The better solution would be to wait for all clients (as indicated by the Lobby) to join the network session and THEN start the game, either by starting to spawn objects or by loading the actual network scene.

In all likelihood you want to implement this “wait for all players joining” feature anyway because players should start a game at the same time. If they don’t, you effectively create a join with late-joining capability (which is more challenging) when you may not even need late joining.

Note: loading a network scene after all players have joined isn’t actually solving the “start together” issue due to varying load times per client. You may still need a “start game” timer, and implement the spawning of the session network objects only after the timer elapsed.

1 Like

as an FYI, i am not using the lobby service provided by unity as it seems to have unintuitive interactions with the distributed authority setup. See here => Lobby System and Distributed Authority - #2 by Wataghwan

The better solution would be to wait for all clients (as indicated by the Lobby) to join the network session and THEN start the game, either by starting to spawn objects or by loading the actual network scene.

I’m pretty sure this is what I’m doing, all clients connect to the session and only once all players “ready up” then the game starts by the network scene loading. From my understanding however, distribution only takes place when a client joins/leaves the session.

It would be neat if there was a function you could call to redistribute the ownership of objects in the scene as I’m fairly certain there would be a genuine use case for it in most games using distributed authority.

Is there a way within the new distributed authority framework to directly call a function that redistributes the ownership of distributable network objects?

I’ve found an incredibly hacky way of doing this by adding the following line within the assemblyinfo.cs in the “com.unity.netcode.gameobjects” runtime folder

[assembly: InternalsVisibleTo(“Assembly-CSharp”)]

this exposes the internal methods from within the “NetworkSpawnManager”, one of which is the “DistributeNetworkObjects(ulong clientId)” which i call on all clients to distribute objects around the network.

obviously this isn’t a very nice solution and has seemed to causes problems elsewhere, but i think this is due to certain race conditions i am facing when clients joining the game which I think i can resolve.

In distributed authority the client spawning a NetworkObject has full control over that NetworkObject (just like a server would). There are two paths you can take:

  • On the SessionOwner instance, you can invoke the NetworkObject.SpawnWithOwnership method.
  • If you want each client to spawn a specific number of network prefabs, then you can have the session owner set a “spawn config” using an in-scene placed NetworkObject that contains a NetworkBehaviour component with a NetworkVariable that includes something like an INetworkSerializable implementation (struct) which defines the number of each network prefab type each client should spawn upon connecting.

The former path follows more of a “host” design pattern where the session owner dictates the object distribution while the later path any client who synchronizes(joins) for the current scene/level will spawn (x)(y)(z) number of various network prefab types that it owns.

Or you could do a combination of both.

Also, if a client (session owner or otherwise) owns a NetworkObject it can assign ownership of that NetworkObject to another client…so you can write your own form of load balancing when spawning a bunch of instances.

It might be easiest (as a first pass) to have the session owner just perform a “round robin” approach where it would look something like:

    public class DistributionSpawnHandler : NetworkBehaviour
    {
        public GameObject PrefabToSpawn;
        public int InitialSpawnCount;

        public void SpawnObjects()
        {
            if (!NetworkManager.LocalClient.IsSessionOwner)
            {
                return;
            }

            var connectedClientCount = NetworkManager.ConnectedClientsIds.Count;

            // Continually increment who owns each spawned instance with wrapping
            for (int i = 0; i < InitialSpawnCount; i++)
            {
                // Stay within the bounds of the number of clients connected
                var clientOwnerIndex = i % connectedClientCount;
                NetworkObject.InstantiateAndSpawn(NetworkManager, NetworkManager.ConnectedClientsIds[clientOwnerIndex]);
            }
        }
    }

Let me know if this helps?

It does somewhat, I just think the ability to call the same function that redistributes the ownership of objects among clients the same way it does when clients join would be very beneficial within a distributed authority framework.

Imagine this scenario, as in the tech demo for DA => https://www.youtube.com/watch?v=3jBOTk_qozA&t=994s&ab_channel=Unity

Within this demo, whenever a spaceship picks up a mine, it gains ownership of that mine. Even when it lets it go, it still has ownership of it.

What if 1 player picks up every single mine, now that player owns and simulates every mine among the network. Now imagine a more complex scenario where there were larger quantities of network objects that are setup this way to change ownership, 1 client could just interact with and then “own” every game object.

Having the ability to force redistribution the same way it does when players join/leave would be very handy.

That kind of functionality is being contemplated, but you also need to consider the code you are writing and whether you have the ability to limit something like that from happening too.

Since clients that own a NetworkObject can change the ownership of a NetworkObject to any other client, you can write script that limits the number of mines a client owns.

Calling the same code that redistributes all NetworkObjects when a new client joins is designed to load balance at that time but could start generating a lot of seemingly random ownership changes on things that you might not want re-distributed.

For the scenario you are describing, there are two types of ownership transition events:

  • When a new client joins or leaves.
  • When a player picks up a mine.

The former is “automatic” while the later you control that script and can prevent a client from picking up more than (n) mines which could be calculated by number of mines spawned vs number of connected clients or could handle redistributing it based on ownership of the mine.

The asteroids demo only allows a player to pick up one mine at a time. Which if you wanted to “load balance” when the player released the mine you would only need to make a minor adjustment to that script so that it:

  • Keep track of the NetworkObject of the last mine that was picked up.
    • If it is null then the player hasn’t picked up anything yet so just take ownership of the mine.
      • You could randomly pick one of that client’s owned mines and perform the same steps below.
    • If it is not null, then before taking ownership of the mine the client could check the distribution of owned mines, transfer ownership of the previous mine to the client with the least number of owned mines, and then take ownership of the new mine.
    • Of course, if the number of mines divided by the number of clients isn’t an even number and all other clients own the same number of mines you could do nothing and just let the player pick up the mine.

This would assure a constant even distribution of ownership.

The script to handle this is pretty minimal and leaves the control in your hands/scripts as you might want to have teams or you might have other factors to take into consideration that a generic re-distribution of all spawned objects might not take into account.

1 Like

That makes sense, thanks for the help