Unity-Technologies / com.unity.netcode.gameobjects

Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.
MIT License
2.14k stars 434 forks source link

Specify GlobalObjectIdHash at runtime (for procedurally generated prefabs) #1360

Open ghost opened 2 years ago

ghost commented 2 years ago

Is your feature request related to a problem? Please describe. I would like to generate prefabs procedurally at runtime. I can easily register them with NetworkManager.PrefabHandler.AddHandler. The only missing part is that I can't set NetworkObject.GlobalObjectIdHash because it's internal.

Describe the solution you'd like I understand exposing NetworkObject.GlobalObjectIdHash might be a problem (it's advanced use case and if public on NetworkObject, user might think it's OK to edit it in typical scenario). Maybe adding it in a more specific location such as a method in NetworkPrefabHandler would be very helpful.

Describe alternatives you've considered Currently I use reflection to set it...

will-mearns commented 2 years ago

Added into product backlog for consideration, MTTH-124

ghost commented 1 year ago

After seeing #2565, I wanted to add two more details to my use case:

Would it be possible to simply add a function like NetworkObject.SetRuntimeGlobalObjectIdHash() (I understand the GlobalObjectIdHash itself is probably better as non-public to not encourage user to edit it, and rather use a function name with Runtime to show it only make sense when creating runtime prefab). If that approach sounds OK, I would be happy to submit a PR.

What I do is something like this:

// Note: I make sure prefab handler and IDs match on both client and server
var handler = new VehicleNetworkPrefabInstanceHandler(prefabHandlerId++);
networkGame.NetworkManager.PrefabHandler.AddHandler(handler.Id, handler);

internal class VehicleNetworkPrefabInstanceHandler : INetworkPrefabInstanceHandler
{
    public VehicleNetworkPrefabInstanceHandler(uint id)
    {
        Id = id;
    }
    public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
    {
        // Create NetworkObject
        var networkObject = vehicleInstance.AddComponent<NetworkObject>();
        // NOT POSSIBLE (I currently use reflection)
        networkObject.GlobalObjectIdHash = Id;
        return networkObject;
    }
    public void Destroy(NetworkObject networkObject) {}
}
AnriiAndrushko commented 9 months ago

@virgile-wp, you saved my day with your code, thanks!