From 92d0df7b399027ccd8f5983fc4bc4fea4530badc Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Tue, 5 Nov 2019 06:55:32 -0600 Subject: [PATCH] feat: SyncToOwner now works with authority (#1204) * WIP redoing authority * Local client also handles authority * Remove unused callback * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: MrGadget * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: vis2k * Rename pendingOwner * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: vis2k * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: vis2k * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: vis2k * Update Assets/Mirror/Runtime/NetworkIdentity.cs Co-Authored-By: vis2k --- Assets/Mirror/Runtime/ClientScene.cs | 13 +-- Assets/Mirror/Runtime/Messages.cs | 21 +---- Assets/Mirror/Runtime/NetworkClient.cs | 1 - Assets/Mirror/Runtime/NetworkIdentity.cs | 105 ++++++++--------------- Assets/Mirror/Runtime/NetworkServer.cs | 6 +- 5 files changed, 47 insertions(+), 99 deletions(-) diff --git a/Assets/Mirror/Runtime/ClientScene.cs b/Assets/Mirror/Runtime/ClientScene.cs index 27c0d0161..99c9a29db 100644 --- a/Assets/Mirror/Runtime/ClientScene.cs +++ b/Assets/Mirror/Runtime/ClientScene.cs @@ -490,12 +490,14 @@ static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage msg) identity.netId = msg.netId; NetworkIdentity.spawned[msg.netId] = identity; + identity.pendingAuthority = msg.isOwner; // objects spawned as part of initial state are started on a second pass if (isSpawnFinished) { identity.OnStartClient(); CheckForLocalPlayer(identity); + identity.hasAuthority = identity.pendingAuthority; } } @@ -599,6 +601,7 @@ internal static void OnObjectSpawnFinished(ObjectSpawnFinishedMessage _) // use data from scene objects foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values.OrderBy(uv => uv.netId)) { + identity.hasAuthority = identity.pendingAuthority; if (!identity.isClient) { identity.OnStartClient(); @@ -712,16 +715,6 @@ internal static void OnSyncEventMessage(SyncEventMessage msg) } } - internal static void OnClientAuthority(ClientAuthorityMessage msg) - { - if (LogFilter.Debug) Debug.Log("ClientScene.OnClientAuthority for netId: " + msg.netId); - - if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) - { - identity.ForceAuthority(msg.authority); - } - } - // called for the one object in the spawn message which is the local player! internal static void OnSpawnMessageForLocalPlayer(uint netId) { diff --git a/Assets/Mirror/Runtime/Messages.cs b/Assets/Mirror/Runtime/Messages.cs index 7330aa8f5..7381438f3 100644 --- a/Assets/Mirror/Runtime/Messages.cs +++ b/Assets/Mirror/Runtime/Messages.cs @@ -340,6 +340,7 @@ public struct SpawnMessage : IMessageBase { public uint netId; public bool isLocalPlayer; + public bool isOwner; public ulong sceneId; public Guid assetId; public Vector3 position; @@ -353,6 +354,7 @@ public void Deserialize(NetworkReader reader) { netId = reader.ReadPackedUInt32(); isLocalPlayer = reader.ReadBoolean(); + isOwner = reader.ReadBoolean(); sceneId = reader.ReadPackedUInt64(); if (sceneId == 0) { @@ -368,6 +370,7 @@ public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(netId); writer.WriteBoolean(isLocalPlayer); + writer.WriteBoolean(isOwner); writer.WritePackedUInt64(sceneId); if (sceneId == 0) { @@ -424,24 +427,6 @@ public void Serialize(NetworkWriter writer) } } - public struct ClientAuthorityMessage : IMessageBase - { - public uint netId; - public bool authority; - - public void Deserialize(NetworkReader reader) - { - netId = reader.ReadPackedUInt32(); - authority = reader.ReadBoolean(); - } - - public void Serialize(NetworkWriter writer) - { - writer.WritePackedUInt32(netId); - writer.WriteBoolean(authority); - } - } - public struct UpdateVarsMessage : IMessageBase { public uint netId; diff --git a/Assets/Mirror/Runtime/NetworkClient.cs b/Assets/Mirror/Runtime/NetworkClient.cs index a2498ea56..1ba8ddfe6 100644 --- a/Assets/Mirror/Runtime/NetworkClient.cs +++ b/Assets/Mirror/Runtime/NetworkClient.cs @@ -359,7 +359,6 @@ internal static void RegisterSystemHandlers(bool hostMode) RegisterHandler(ClientScene.OnObjectSpawnFinished); RegisterHandler(ClientScene.OnUpdateVarsMessage); } - RegisterHandler(ClientScene.OnClientAuthority); RegisterHandler(ClientScene.OnRPCMessage); RegisterHandler(ClientScene.OnSyncEventMessage); } diff --git a/Assets/Mirror/Runtime/NetworkIdentity.cs b/Assets/Mirror/Runtime/NetworkIdentity.cs index 4aa2c7e11..caa80d654 100644 --- a/Assets/Mirror/Runtime/NetworkIdentity.cs +++ b/Assets/Mirror/Runtime/NetworkIdentity.cs @@ -82,7 +82,31 @@ public bool isServer /// This value is determined at runtime. For most objects, authority is held by the server. /// For objects that had their authority set by AssignClientAuthority on the server, this will be true on the client that owns the object. NOT on other clients. /// - public bool hasAuthority { get; private set; } + bool isOwner; + + public bool hasAuthority + { + get => isOwner; + set + { + bool previous = isOwner; + isOwner = value; + + if (previous && !isOwner) + { + OnStopAuthority(); + } + if (!previous && isOwner) + { + OnStartAuthority(); + } + } + } + + // whether this object has been spawned with authority + // we need hasAuthority and pendingOwner because + // we need to wait until all of them spawn before updating hasAuthority + internal bool pendingAuthority { get; set; } /// /// The set of network connections (players) that can see this object. @@ -194,24 +218,6 @@ internal void SetClientOwner(NetworkConnection conn) connectionToClient.AddOwnedObject(this); } - internal void ForceAuthority(bool authority) - { - if (hasAuthority == authority) - { - return; - } - - hasAuthority = authority; - if (authority) - { - OnStartAuthority(); - } - else - { - OnStopAuthority(); - } - } - static uint nextNetworkId = 1; internal static uint GetNextNetworkId() => nextNetworkId++; @@ -220,23 +226,6 @@ internal void ForceAuthority(bool authority) /// public static void ResetNextNetworkId() => nextNetworkId = 1; - /// - /// Obsolete: Host Migration was removed - /// - /// The network connection that is gaining or losing authority. - /// The object whose client authority status is being changed. - /// The new state of client authority of the object for the connection. - [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Host Migration was removed")] - public delegate void ClientAuthorityCallback(NetworkConnection conn, NetworkIdentity identity, bool authorityState); - - /// - /// Obsolete: Host Migration was removed - /// Whenever an object is spawned using SpawnWithClientAuthority, or the client authority status of an object is changed with AssignClientAuthority or RemoveClientAuthority, then this callback will be invoked. - /// This callback is used by the NetworkMigrationManager to distribute client authority state to peers for host migration. If the NetworkMigrationManager is not being used, this callback does not need to be populated. - /// - [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Host Migration was removed")] - public static ClientAuthorityCallback clientAuthorityCallback; - // used when the player object for a connection changes internal void SetNotLocalPlayer() { @@ -901,17 +890,11 @@ internal void SetLocalPlayer() // OnStartAuthority should only be called if hasAuthority was false when this function began, // or it will be called twice for this object, but that state is lost by the time OnStartAuthority // is called below, so the original value is cached here to be checked below. - bool originAuthority = hasAuthority; hasAuthority = true; foreach (NetworkBehaviour comp in networkBehavioursCache) { comp.OnStartLocalPlayer(); - - if (!originAuthority) - { - comp.OnStartAuthority(); - } } } @@ -1096,24 +1079,19 @@ public void RemoveClientAuthority() if (connectionToClient != null) { - // send msg to that client - ClientAuthorityMessage msg = new ClientAuthorityMessage - { - netId = netId, - authority = false - }; - - connectionToClient.Send(msg); -#pragma warning disable CS0618 // Type or member is obsolete - clientAuthorityCallback?.Invoke(connectionToClient, this, false); -#pragma warning restore CS0618 // Type or member is obsolete + NetworkConnectionToClient previousOwner = connectionToClient; connectionToClient.RemoveOwnedObject(this); connectionToClient = null; - } - // server now has authority (this is only called on server) - ForceAuthority(false); + // we need to resynchronize the entire object + // so just spawn it again, + // the client will not create a new instance, it will simply + // reset all variables and remove authority + NetworkServer.SendSpawnMessage(this, previousOwner); + + connectionToClient = null; + } } /// @@ -1145,17 +1123,9 @@ public bool AssignClientAuthority(NetworkConnection conn) SetClientOwner(conn); - // send msg to that client - ClientAuthorityMessage msg = new ClientAuthorityMessage - { - netId = netId, - authority = true - }; - conn.Send(msg); - -#pragma warning disable CS0618 // Type or member is obsolete - clientAuthorityCallback?.Invoke(conn, this, true); -#pragma warning restore CS0618 // Type or member is obsolete + // The client will match to the existing object + // update all variables and assign authority + NetworkServer.SendSpawnMessage(this, conn); return true; } @@ -1173,7 +1143,6 @@ internal void Reset() m_Reset = false; m_IsServer = false; isClient = false; - hasAuthority = false; netId = 0; isLocalPlayer = false; diff --git a/Assets/Mirror/Runtime/NetworkServer.cs b/Assets/Mirror/Runtime/NetworkServer.cs index 4f93e35b6..1afea3663 100644 --- a/Assets/Mirror/Runtime/NetworkServer.cs +++ b/Assets/Mirror/Runtime/NetworkServer.cs @@ -1090,6 +1090,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio { netId = identity.netId, isLocalPlayer = conn?.identity == identity, + isOwner = identity.connectionToClient == conn && conn != null, sceneId = identity.sceneId, assetId = identity.assetId, // use local values for VR support @@ -1103,8 +1104,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio { // use owner segment if 'conn' owns this identity, otherwise // use observers segment - bool isOwner = identity.connectionToClient == conn; - msg.payload = isOwner ? ownerSegment : observersSegment; + msg.payload = msg.isOwner ? ownerSegment : observersSegment; conn.Send(msg); } @@ -1116,6 +1116,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio // serialized because the spawn message contains more data. // components might still be updated later on.) msg.payload = ownerSegment; + msg.isOwner = true; SendToClientOfPlayer(identity, msg); // send observersWriter to everyone but owner @@ -1123,6 +1124,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio // serialized because the spawn message contains more data. // components might still be updated later on.) msg.payload = observersSegment; + msg.isOwner = false; SendToReady(identity, msg, false); }