refactor: Simplify spawn message (#1195)

* refactor: Simplify spawn message

* Update Assets/Mirror/Runtime/Messages.cs

* fix brainfart

* consolidate spawning logic

* simpler find

* remove unnecesary private keyword

* Remove redundant else
This commit is contained in:
Paul Pacheco 2019-10-31 02:07:37 -07:00 committed by vis2k
parent 6765da2387
commit f70a2ac702
4 changed files with 61 additions and 116 deletions

View File

@ -438,28 +438,32 @@ public static GameObject FindLocalObject(uint netId)
return null; return null;
} }
static void ApplySpawnPayload(NetworkIdentity identity, Vector3 position, Quaternion rotation, Vector3 scale, ArraySegment<byte> payload, uint netId) static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage msg)
{ {
identity.Reset();
identity.pendingLocalPlayer = msg.isLocalPlayer;
identity.assetId = msg.assetId;
if (!identity.gameObject.activeSelf) if (!identity.gameObject.activeSelf)
{ {
identity.gameObject.SetActive(true); identity.gameObject.SetActive(true);
} }
// apply local values for VR support // apply local values for VR support
identity.transform.localPosition = position; identity.transform.localPosition = msg.position;
identity.transform.localRotation = rotation; identity.transform.localRotation = msg.rotation;
identity.transform.localScale = scale; identity.transform.localScale = msg.scale;
// deserialize components if any payload // deserialize components if any payload
// (Count is 0 if there were no components) // (Count is 0 if there were no components)
if (payload.Count > 0) if (msg.payload.Count > 0)
{ {
NetworkReader payloadReader = new NetworkReader(payload); NetworkReader payloadReader = new NetworkReader(msg.payload);
identity.OnUpdateVars(payloadReader, true); identity.OnUpdateVars(payloadReader, true);
} }
identity.netId = netId; identity.netId = msg.netId;
NetworkIdentity.spawned[netId] = identity; NetworkIdentity.spawned[msg.netId] = identity;
// objects spawned as part of initial state are started on a second pass // objects spawned as part of initial state are started on a second pass
if (isSpawnFinished) if (isSpawnFinished)
@ -469,14 +473,14 @@ static void ApplySpawnPayload(NetworkIdentity identity, Vector3 position, Quater
} }
} }
internal static void OnSpawnPrefab(NetworkConnection _, SpawnPrefabMessage msg) internal static void OnSpawn(NetworkConnection _, SpawnMessage msg)
{ {
if (msg.assetId == Guid.Empty) if (msg.assetId == Guid.Empty && msg.sceneId == 0)
{ {
Debug.LogError("OnObjSpawn netId: " + msg.netId + " has invalid asset Id"); Debug.LogError("OnObjSpawn netId: " + msg.netId + " has invalid asset Id");
return; return;
} }
if (LogFilter.Debug) Debug.Log("Client spawn handler instantiating [netId:" + msg.netId + " asset ID:" + msg.assetId + " pos:" + msg.position + "]"); if (LogFilter.Debug) Debug.Log($"Client spawn handler instantiating netId={msg.netId} assetID={msg.assetId} sceneId={msg.sceneId} pos={msg.position}");
// is this supposed to be the local player? // is this supposed to be the local player?
if (msg.isLocalPlayer) if (msg.isLocalPlayer)
@ -484,14 +488,31 @@ internal static void OnSpawnPrefab(NetworkConnection _, SpawnPrefabMessage msg)
OnSpawnMessageForLocalPlayer(msg.netId); OnSpawnMessageForLocalPlayer(msg.netId);
} }
if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) // was the object already spawned?
NetworkIdentity identity = GetExistingObject(msg.netId);
if (identity == null)
{ {
// this object already exists (was in the scene), just apply the update to existing object identity = msg.sceneId == 0 ? SpawnPrefab(msg) : SpawnSceneObject(msg);
localObject.Reset(); }
ApplySpawnPayload(localObject, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId);
if (identity == null)
{
Debug.LogError($"Could not spawn assetId={msg.assetId} scene={msg.sceneId} netId={msg.netId}");
return; return;
} }
ApplySpawnPayload(identity, msg);
}
static NetworkIdentity GetExistingObject(uint netid)
{
NetworkIdentity.spawned.TryGetValue(netid, out NetworkIdentity localObject);
return localObject;
}
static NetworkIdentity SpawnPrefab(SpawnMessage msg)
{
if (GetPrefab(msg.assetId, out GameObject prefab)) if (GetPrefab(msg.assetId, out GameObject prefab))
{ {
GameObject obj = Object.Instantiate(prefab, msg.position, msg.rotation); GameObject obj = Object.Instantiate(prefab, msg.position, msg.rotation);
@ -500,60 +521,24 @@ internal static void OnSpawnPrefab(NetworkConnection _, SpawnPrefabMessage msg)
Debug.Log("Client spawn handler instantiating [netId:" + msg.netId + " asset ID:" + msg.assetId + " pos:" + msg.position + " rotation: " + msg.rotation + "]"); Debug.Log("Client spawn handler instantiating [netId:" + msg.netId + " asset ID:" + msg.assetId + " pos:" + msg.position + " rotation: " + msg.rotation + "]");
} }
localObject = obj.GetComponent<NetworkIdentity>(); return obj.GetComponent<NetworkIdentity>();
if (localObject == null)
{
Debug.LogError("Client object spawned for " + msg.assetId + " does not have a NetworkIdentity");
return;
}
localObject.Reset();
localObject.pendingLocalPlayer = msg.isLocalPlayer;
ApplySpawnPayload(localObject, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId);
} }
// lookup registered factory for type: if (spawnHandlers.TryGetValue(msg.assetId, out SpawnDelegate handler))
else if (spawnHandlers.TryGetValue(msg.assetId, out SpawnDelegate handler))
{ {
GameObject obj = handler(msg.position, msg.assetId); GameObject obj = handler(msg.position, msg.assetId);
if (obj == null) if (obj == null)
{ {
Debug.LogWarning("Client spawn handler for " + msg.assetId + " returned null"); Debug.LogWarning("Client spawn handler for " + msg.assetId + " returned null");
return; return null;
} }
localObject = obj.GetComponent<NetworkIdentity>(); return obj.GetComponent<NetworkIdentity>();
if (localObject == null)
{
Debug.LogError("Client object spawned for " + msg.assetId + " does not have a network identity");
return;
}
localObject.Reset();
localObject.pendingLocalPlayer = msg.isLocalPlayer;
localObject.assetId = msg.assetId;
ApplySpawnPayload(localObject, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId);
}
else
{
Debug.LogError("Failed to spawn server object, did you forget to add it to the NetworkManager? assetId=" + msg.assetId + " netId=" + msg.netId);
} }
Debug.LogError("Failed to spawn server object, did you forget to add it to the NetworkManager? assetId=" + msg.assetId + " netId=" + msg.netId);
return null;
} }
internal static void OnSpawnSceneObject(NetworkConnection _, SpawnSceneObjectMessage msg) static NetworkIdentity SpawnSceneObject(SpawnMessage msg)
{ {
if (LogFilter.Debug) Debug.Log("Client spawn scene handler instantiating [netId:" + msg.netId + " sceneId:" + msg.sceneId + " pos:" + msg.position);
// is this supposed to be the local player?
if (msg.isLocalPlayer)
{
OnSpawnMessageForLocalPlayer(msg.netId);
}
if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null)
{
// this object already exists (was in the scene)
localObject.Reset();
ApplySpawnPayload(localObject, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId);
return;
}
NetworkIdentity spawnedId = SpawnSceneObject(msg.sceneId); NetworkIdentity spawnedId = SpawnSceneObject(msg.sceneId);
if (spawnedId == null) if (spawnedId == null)
{ {
@ -565,14 +550,10 @@ internal static void OnSpawnSceneObject(NetworkConnection _, SpawnSceneObjectMes
foreach (KeyValuePair<ulong, NetworkIdentity> kvp in spawnableObjects) foreach (KeyValuePair<ulong, NetworkIdentity> kvp in spawnableObjects)
Debug.Log("Spawnable: SceneId=" + kvp.Key + " name=" + kvp.Value.name); Debug.Log("Spawnable: SceneId=" + kvp.Key + " name=" + kvp.Value.name);
} }
return;
} }
if (LogFilter.Debug) Debug.Log("Client spawn for [netId:" + msg.netId + "] [sceneId:" + msg.sceneId + "] obj:" + spawnedId.gameObject.name); if (LogFilter.Debug) Debug.Log("Client spawn for [netId:" + msg.netId + "] [sceneId:" + msg.sceneId + "] obj:" + spawnedId.gameObject.name);
spawnedId.Reset(); return spawnedId;
spawnedId.pendingLocalPlayer = msg.isLocalPlayer;
ApplySpawnPayload(spawnedId, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId);
} }
internal static void OnObjectSpawnStarted(NetworkConnection _, ObjectSpawnStartedMessage msg) internal static void OnObjectSpawnStarted(NetworkConnection _, ObjectSpawnStartedMessage msg)
@ -659,15 +640,7 @@ internal static void OnLocalClientObjectHide(NetworkConnection _, ObjectHideMess
} }
} }
internal static void OnLocalClientSpawnPrefab(NetworkConnection _, SpawnPrefabMessage msg) internal static void OnLocalClientSpawn(NetworkConnection _, SpawnMessage msg)
{
if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null)
{
localObject.OnSetLocalVisibility(true);
}
}
internal static void OnLocalClientSpawnSceneObject(NetworkConnection _, SpawnSceneObjectMessage msg)
{ {
if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null)
{ {

View File

@ -312,10 +312,11 @@ public void Serialize(NetworkWriter writer)
#endregion #endregion
#region Internal System Messages #region Internal System Messages
public struct SpawnPrefabMessage : IMessageBase public struct SpawnMessage : IMessageBase
{ {
public uint netId; public uint netId;
public bool isLocalPlayer; public bool isLocalPlayer;
public ulong sceneId;
public Guid assetId; public Guid assetId;
public Vector3 position; public Vector3 position;
public Quaternion rotation; public Quaternion rotation;
@ -328,7 +329,11 @@ public void Deserialize(NetworkReader reader)
{ {
netId = reader.ReadPackedUInt32(); netId = reader.ReadPackedUInt32();
isLocalPlayer = reader.ReadBoolean(); isLocalPlayer = reader.ReadBoolean();
assetId = reader.ReadGuid(); sceneId = reader.ReadPackedUInt64();
if (sceneId == 0)
{
assetId = reader.ReadGuid();
}
position = reader.ReadVector3(); position = reader.ReadVector3();
rotation = reader.ReadQuaternion(); rotation = reader.ReadQuaternion();
scale = reader.ReadVector3(); scale = reader.ReadVector3();
@ -339,42 +344,11 @@ public void Serialize(NetworkWriter writer)
{ {
writer.WritePackedUInt32(netId); writer.WritePackedUInt32(netId);
writer.WriteBoolean(isLocalPlayer); writer.WriteBoolean(isLocalPlayer);
writer.WriteGuid(assetId); writer.WritePackedUInt64(sceneId);
writer.WriteVector3(position); if (sceneId == 0)
writer.WriteQuaternion(rotation); {
writer.WriteVector3(scale); writer.WriteGuid(assetId);
writer.WriteBytesAndSizeSegment(payload); }
}
}
public struct SpawnSceneObjectMessage : IMessageBase
{
public uint netId;
public bool isLocalPlayer;
public ulong sceneId;
public Vector3 position;
public Quaternion rotation;
public Vector3 scale;
// the serialized component data
// -> ArraySegment to avoid unnecessary allocations
public ArraySegment<byte> payload;
public void Deserialize(NetworkReader reader)
{
netId = reader.ReadPackedUInt32();
isLocalPlayer = reader.ReadBoolean();
sceneId = reader.ReadUInt64();
position = reader.ReadVector3();
rotation = reader.ReadQuaternion();
scale = reader.ReadVector3();
payload = reader.ReadBytesAndSizeSegment();
}
public void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32(netId);
writer.WriteBoolean(isLocalPlayer);
writer.WriteUInt64(sceneId);
writer.WriteVector3(position); writer.WriteVector3(position);
writer.WriteQuaternion(rotation); writer.WriteQuaternion(rotation);
writer.WriteVector3(scale); writer.WriteVector3(scale);

View File

@ -344,8 +344,7 @@ internal static void RegisterSystemHandlers(bool localClient)
RegisterHandler<ObjectDestroyMessage>(ClientScene.OnLocalClientObjectDestroy); RegisterHandler<ObjectDestroyMessage>(ClientScene.OnLocalClientObjectDestroy);
RegisterHandler<ObjectHideMessage>(ClientScene.OnLocalClientObjectHide); RegisterHandler<ObjectHideMessage>(ClientScene.OnLocalClientObjectHide);
RegisterHandler<NetworkPongMessage>((conn, msg) => { }, false); RegisterHandler<NetworkPongMessage>((conn, msg) => { }, false);
RegisterHandler<SpawnPrefabMessage>(ClientScene.OnLocalClientSpawnPrefab); RegisterHandler<SpawnMessage>(ClientScene.OnLocalClientSpawn);
RegisterHandler<SpawnSceneObjectMessage>(ClientScene.OnLocalClientSpawnSceneObject);
RegisterHandler<ObjectSpawnStartedMessage>((conn, msg) => { }); // host mode doesn't need spawning RegisterHandler<ObjectSpawnStartedMessage>((conn, msg) => { }); // host mode doesn't need spawning
RegisterHandler<ObjectSpawnFinishedMessage>((conn, msg) => { }); // host mode doesn't need spawning RegisterHandler<ObjectSpawnFinishedMessage>((conn, msg) => { }); // host mode doesn't need spawning
RegisterHandler<UpdateVarsMessage>((conn, msg) => { }); RegisterHandler<UpdateVarsMessage>((conn, msg) => { });
@ -355,8 +354,7 @@ internal static void RegisterSystemHandlers(bool localClient)
RegisterHandler<ObjectDestroyMessage>(ClientScene.OnObjectDestroy); RegisterHandler<ObjectDestroyMessage>(ClientScene.OnObjectDestroy);
RegisterHandler<ObjectHideMessage>(ClientScene.OnObjectHide); RegisterHandler<ObjectHideMessage>(ClientScene.OnObjectHide);
RegisterHandler<NetworkPongMessage>(NetworkTime.OnClientPong, false); RegisterHandler<NetworkPongMessage>(NetworkTime.OnClientPong, false);
RegisterHandler<SpawnPrefabMessage>(ClientScene.OnSpawnPrefab); RegisterHandler<SpawnMessage>(ClientScene.OnSpawn);
RegisterHandler<SpawnSceneObjectMessage>(ClientScene.OnSpawnSceneObject);
RegisterHandler<ObjectSpawnStartedMessage>(ClientScene.OnObjectSpawnStarted); RegisterHandler<ObjectSpawnStartedMessage>(ClientScene.OnObjectSpawnStarted);
RegisterHandler<ObjectSpawnFinishedMessage>(ClientScene.OnObjectSpawnFinished); RegisterHandler<ObjectSpawnFinishedMessage>(ClientScene.OnObjectSpawnFinished);
RegisterHandler<UpdateVarsMessage>(ClientScene.OnUpdateVarsMessage); RegisterHandler<UpdateVarsMessage>(ClientScene.OnUpdateVarsMessage);

View File

@ -1077,7 +1077,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio
// 'identity' is a prefab that should be spawned // 'identity' is a prefab that should be spawned
if (identity.sceneId == 0) if (identity.sceneId == 0)
{ {
SpawnPrefabMessage msg = new SpawnPrefabMessage SpawnMessage msg = new SpawnMessage
{ {
netId = identity.netId, netId = identity.netId,
isLocalPlayer = conn?.identity == identity, isLocalPlayer = conn?.identity == identity,
@ -1119,7 +1119,7 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio
// 'identity' is a scene object that should be spawned again // 'identity' is a scene object that should be spawned again
else else
{ {
SpawnSceneObjectMessage msg = new SpawnSceneObjectMessage SpawnMessage msg = new SpawnMessage
{ {
netId = identity.netId, netId = identity.netId,
isLocalPlayer = conn?.identity == identity, isLocalPlayer = conn?.identity == identity,