ClientScene: prefab spawning and spawn handlers obsoleted and moved to NetworkClient

This commit is contained in:
vis2k 2021-03-07 18:39:35 +08:00
parent 13c5a409e5
commit f20d30d4bb
6 changed files with 464 additions and 416 deletions

View File

@ -451,7 +451,7 @@ public override void OnStartClient()
if (roomPlayerPrefab == null || roomPlayerPrefab.gameObject == null)
Debug.LogError("NetworkRoomManager no RoomPlayer prefab is registered. Please add a RoomPlayer prefab.");
else
ClientScene.RegisterPrefab(roomPlayerPrefab.gameObject);
NetworkClient.RegisterPrefab(roomPlayerPrefab.gameObject);
if (playerPrefab == null)
Debug.LogError("NetworkRoomManager no GamePlayer prefab is registered. Please add a GamePlayer prefab.");

View File

@ -32,19 +32,13 @@ public static class ClientScene
public static NetworkConnection readyConnection { get; private set; }
/// <summary>Registered spawnable prefabs by assetId.</summary>
public static readonly Dictionary<Guid, GameObject> prefabs =
new Dictionary<Guid, GameObject>();
[Obsolete("ClientScene.prefabs was moved to NetworkClient.prefabs")]
public static Dictionary<Guid, GameObject> prefabs => NetworkClient.prefabs;
/// <summary>Disabled scene objects that can be spawned again, by sceneId.</summary>
internal static readonly Dictionary<ulong, NetworkIdentity> spawnableObjects =
new Dictionary<ulong, NetworkIdentity>();
// spawn handlers
internal static readonly Dictionary<Guid, SpawnHandlerDelegate> spawnHandlers =
new Dictionary<Guid, SpawnHandlerDelegate>();
internal static readonly Dictionary<Guid, UnSpawnDelegate> unspawnHandlers =
new Dictionary<Guid, UnSpawnDelegate>();
// add player //////////////////////////////////////////////////////////
// called from message handler for Owner message
internal static void InternalAddPlayer(NetworkIdentity identity)
@ -171,416 +165,48 @@ public static void PrepareToSpawnSceneObjects()
}
// spawnable prefabs ///////////////////////////////////////////////////
/// <summary>Find the registered prefab for this asset id.</summary>
// Useful for debuggers
public static bool GetPrefab(Guid assetId, out GameObject prefab)
{
prefab = null;
return assetId != Guid.Empty &&
prefabs.TryGetValue(assetId, out prefab) && prefab != null;
}
[Obsolete("ClientScene.GetPrefab was moved to NetworkClient.GetPrefab")]
public static bool GetPrefab(Guid assetId, out GameObject prefab) => NetworkClient.GetPrefab(assetId, out prefab);
/// <summary>Validates Prefab then adds it to prefabs dictionary.</summary>
static void RegisterPrefabIdentity(NetworkIdentity prefab)
{
if (prefab.assetId == Guid.Empty)
{
Debug.LogError($"Can not Register '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab, Guid newAssetId) => NetworkClient.RegisterPrefab(prefab, newAssetId);
if (prefab.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab) => NetworkClient.RegisterPrefab(prefab);
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterPrefab(prefab, newAssetId, spawnHandler, unspawnHandler);
if (prefabs.ContainsKey(prefab.assetId))
{
GameObject existingPrefab = prefabs[prefab.assetId];
Debug.LogWarning($"Replacing existing prefab with assetId '{prefab.assetId}'. Old prefab '{existingPrefab.name}', New prefab '{prefab.name}'");
}
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
if (spawnHandlers.ContainsKey(prefab.assetId) || unspawnHandlers.ContainsKey(prefab.assetId))
{
Debug.LogWarning($"Adding prefab '{prefab.name}' with assetId '{prefab.assetId}' when spawnHandlers with same assetId already exists.");
}
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterPrefab(prefab, newAssetId, spawnHandler, unspawnHandler);
// Debug.Log($"Registering prefab '{prefab.name}' as asset:{prefab.assetId}");
[Obsolete("ClientScene.RegisterPrefab was moved to NetworkClient.RegisterPrefab")]
public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
prefabs[prefab.assetId] = prefab.gameObject;
}
/// <summary>Register spawnable prefab with custom assetId.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
public static void RegisterPrefab(GameObject prefab, Guid newAssetId)
{
if (prefab == null)
{
Debug.LogError("Could not register prefab because it was null");
return;
}
if (newAssetId == Guid.Empty)
{
Debug.LogError($"Could not register '{prefab.name}' with new assetId because the new assetId was empty");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return;
}
if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
{
Debug.LogError($"Could not register '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
return;
}
identity.assetId = newAssetId;
RegisterPrefabIdentity(identity);
}
/// <summary>Register spawnable prefab.</summary>
public static void RegisterPrefab(GameObject prefab)
{
if (prefab == null)
{
Debug.LogError("Could not register prefab because it was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return;
}
RegisterPrefabIdentity(identity);
}
/// <summary>Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {newAssetId}");
return;
}
RegisterPrefab(prefab, newAssetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
/// <summary>Register a spawnable prefab with custom spawn/unspawn handlers.</summary>
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
Guid assetId = identity.assetId;
if (assetId == Guid.Empty)
{
Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
RegisterPrefab(prefab, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
/// <summary>Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (newAssetId == Guid.Empty)
{
Debug.LogError($"Could not register handler for '{prefab.name}' with new assetId because the new assetId was empty");
return;
}
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
{
Debug.LogError($"Could not register Handler for '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
identity.assetId = newAssetId;
Guid assetId = identity.assetId;
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
}
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
// Debug.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary>Register a spawnable prefab with custom spawn/unspawn handlers.</summary>
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
Guid assetId = identity.assetId;
if (assetId == Guid.Empty)
{
Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
}
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
// Debug.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary>Removes a registered spawn prefab that was setup with ClientScene.RegisterPrefab.</summary>
public static void UnregisterPrefab(GameObject prefab)
{
if (prefab == null)
{
Debug.LogError("Could not unregister prefab because it was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not unregister '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
Guid assetId = identity.assetId;
prefabs.Remove(assetId);
spawnHandlers.Remove(assetId);
unspawnHandlers.Remove(assetId);
}
[Obsolete("ClientScene.UnregisterPrefab was moved to NetworkClient.UnregisterPrefab")]
public static void UnregisterPrefab(GameObject prefab) => NetworkClient.UnregisterPrefab(prefab);
// spawn handlers //////////////////////////////////////////////////////
/// <summary>This is an advanced spawning function that registers a custom assetId with the spawning system.</summary>
// This can be used to register custom spawning methods for an assetId -
// instead of the usual method of registering spawning methods for a
// prefab. This should be used when no prefab exists for the spawned
// objects - such as when they are constructed dynamically at runtime
// from configuration data.
public static void RegisterSpawnHandler(Guid assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
[Obsolete("ClientScene.RegisterSpawnHandler was moved to NetworkClient.RegisterSpawnHandler")]
public static void RegisterSpawnHandler(Guid assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterSpawnHandler(assetId, spawnHandler, unspawnHandler);
RegisterSpawnHandler(assetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
[Obsolete("ClientScene.RegisterSpawnHandler was moved to NetworkClient.RegisterSpawnHandler")]
public static void RegisterSpawnHandler(Guid assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) =>
NetworkClient.RegisterSpawnHandler(assetId, spawnHandler, unspawnHandler);
/// <summary>This is an advanced spawning function that registers a custom assetId with the spawning system.</summary>
// This can be used to register custom spawning methods for an assetId -
// instead of the usual method of registering spawning methods for a
// prefab. This should be used when no prefab exists for the spawned
// objects - such as when they are constructed dynamically at runtime
// from configuration data.
public static void RegisterSpawnHandler(Guid assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
[Obsolete("ClientScene.UnregisterSpawnHandler was moved to NetworkClient.UnregisterSpawnHandler")]
public static void UnregisterSpawnHandler(Guid assetId) => NetworkClient.UnregisterSpawnHandler(assetId);
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (assetId == Guid.Empty)
{
Debug.LogError("Can not Register SpawnHandler for empty Guid");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for {assetId}");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}'");
}
// Debug.Log("RegisterSpawnHandler asset '" + assetId + "' " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary> Removes a registered spawn handler function that was registered with ClientScene.RegisterHandler().</summary>
public static void UnregisterSpawnHandler(Guid assetId)
{
spawnHandlers.Remove(assetId);
unspawnHandlers.Remove(assetId);
}
/// <summary>This clears the registered spawn prefabs and spawn handler functions for this client.</summary>
public static void ClearSpawners()
{
prefabs.Clear();
spawnHandlers.Clear();
unspawnHandlers.Clear();
}
static bool InvokeUnSpawnHandler(Guid assetId, GameObject obj)
{
if (unspawnHandlers.TryGetValue(assetId, out UnSpawnDelegate handler) && handler != null)
{
handler(obj);
return true;
}
return false;
}
[Obsolete("ClientScene.ClearSpawners was moved to NetworkClient.ClearSpawners")]
public static void ClearSpawners() => NetworkClient.ClearSpawners();
// spawning ////////////////////////////////////////////////////////////
internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage message)
@ -676,7 +302,7 @@ static NetworkIdentity SpawnPrefab(SpawnMessage msg)
//Debug.Log("Client spawn handler instantiating [netId:" + msg.netId + " asset ID:" + msg.assetId + " pos:" + msg.position + " rotation: " + msg.rotation + "]");
return obj.GetComponent<NetworkIdentity>();
}
if (spawnHandlers.TryGetValue(msg.assetId, out SpawnHandlerDelegate handler))
if (NetworkClient.spawnHandlers.TryGetValue(msg.assetId, out SpawnHandlerDelegate handler))
{
GameObject obj = handler(msg);
if (obj == null)
@ -782,7 +408,7 @@ static void DestroyObject(uint netId)
localObject.OnStopClient();
// user handling
if (InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject))
if (NetworkClient.InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject))
{
// reset object after user's handler
localObject.Reset();
@ -822,7 +448,7 @@ public static void DestroyAllClientObjects()
if (identity != null && identity.gameObject != null)
{
identity.OnStopClient();
bool wasUnspawned = InvokeUnSpawnHandler(identity.assetId, identity.gameObject);
bool wasUnspawned = NetworkClient.InvokeUnSpawnHandler(identity.assetId, identity.gameObject);
if (!wasUnspawned)
{
// scene objects are reset and disabled.

View File

@ -50,6 +50,16 @@ public static class NetworkClient
internal static Action<NetworkConnection> OnConnectedEvent;
internal static Action<NetworkConnection> OnDisconnectedEvent;
/// <summary>Registered spawnable prefabs by assetId.</summary>
public static readonly Dictionary<Guid, GameObject> prefabs =
new Dictionary<Guid, GameObject>();
// spawn handlers
internal static readonly Dictionary<Guid, SpawnHandlerDelegate> spawnHandlers =
new Dictionary<Guid, SpawnHandlerDelegate>();
internal static readonly Dictionary<Guid, UnSpawnDelegate> unspawnHandlers =
new Dictionary<Guid, UnSpawnDelegate>();
// initialization //////////////////////////////////////////////////////
static void AddTransportHandlers()
{
@ -311,6 +321,418 @@ public static bool UnregisterHandler<T>()
return handlers.Remove(msgType);
}
// spawnable prefabs ///////////////////////////////////////////////////
/// <summary>Find the registered prefab for this asset id.</summary>
// Useful for debuggers
public static bool GetPrefab(Guid assetId, out GameObject prefab)
{
prefab = null;
return assetId != Guid.Empty &&
prefabs.TryGetValue(assetId, out prefab) && prefab != null;
}
/// <summary>Validates Prefab then adds it to prefabs dictionary.</summary>
static void RegisterPrefabIdentity(NetworkIdentity prefab)
{
if (prefab.assetId == Guid.Empty)
{
Debug.LogError($"Can not Register '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
if (prefab.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
if (prefabs.ContainsKey(prefab.assetId))
{
GameObject existingPrefab = prefabs[prefab.assetId];
Debug.LogWarning($"Replacing existing prefab with assetId '{prefab.assetId}'. Old prefab '{existingPrefab.name}', New prefab '{prefab.name}'");
}
if (spawnHandlers.ContainsKey(prefab.assetId) || unspawnHandlers.ContainsKey(prefab.assetId))
{
Debug.LogWarning($"Adding prefab '{prefab.name}' with assetId '{prefab.assetId}' when spawnHandlers with same assetId already exists.");
}
// Debug.Log($"Registering prefab '{prefab.name}' as asset:{prefab.assetId}");
prefabs[prefab.assetId] = prefab.gameObject;
}
/// <summary>Register spawnable prefab with custom assetId.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
public static void RegisterPrefab(GameObject prefab, Guid newAssetId)
{
if (prefab == null)
{
Debug.LogError("Could not register prefab because it was null");
return;
}
if (newAssetId == Guid.Empty)
{
Debug.LogError($"Could not register '{prefab.name}' with new assetId because the new assetId was empty");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return;
}
if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
{
Debug.LogError($"Could not register '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
return;
}
identity.assetId = newAssetId;
RegisterPrefabIdentity(identity);
}
/// <summary>Register spawnable prefab.</summary>
public static void RegisterPrefab(GameObject prefab)
{
if (prefab == null)
{
Debug.LogError("Could not register prefab because it was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return;
}
RegisterPrefabIdentity(identity);
}
/// <summary>Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {newAssetId}");
return;
}
RegisterPrefab(prefab, newAssetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
/// <summary>Register a spawnable prefab with custom spawn/unspawn handlers.</summary>
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
Guid assetId = identity.assetId;
if (assetId == Guid.Empty)
{
Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
RegisterPrefab(prefab, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
/// <summary>Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers.</summary>
// Note: newAssetId can not be set on GameObjects that already have an assetId
// Note: registering with assetId is useful for assetbundles etc. a lot
// of people use this.
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (newAssetId == Guid.Empty)
{
Debug.LogError($"Could not register handler for '{prefab.name}' with new assetId because the new assetId was empty");
return;
}
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
{
Debug.LogError($"Could not register Handler for '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
identity.assetId = newAssetId;
Guid assetId = identity.assetId;
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
}
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
// Debug.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary>Register a spawnable prefab with custom spawn/unspawn handlers.</summary>
// TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate?
public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (prefab == null)
{
Debug.LogError("Could not register handler for prefab because the prefab was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
if (identity.sceneId != 0)
{
Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
return;
}
Guid assetId = identity.assetId;
if (assetId == Guid.Empty)
{
Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
return;
}
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
}
NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1)
{
Debug.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
// Debug.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary>Removes a registered spawn prefab that was setup with ClientScene.RegisterPrefab.</summary>
public static void UnregisterPrefab(GameObject prefab)
{
if (prefab == null)
{
Debug.LogError("Could not unregister prefab because it was null");
return;
}
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
Debug.LogError("Could not unregister '" + prefab.name + "' since it contains no NetworkIdentity component");
return;
}
Guid assetId = identity.assetId;
prefabs.Remove(assetId);
spawnHandlers.Remove(assetId);
unspawnHandlers.Remove(assetId);
}
// spawn handlers //////////////////////////////////////////////////////
/// <summary>This is an advanced spawning function that registers a custom assetId with the spawning system.</summary>
// This can be used to register custom spawning methods for an assetId -
// instead of the usual method of registering spawning methods for a
// prefab. This should be used when no prefab exists for the spawned
// objects - such as when they are constructed dynamically at runtime
// from configuration data.
public static void RegisterSpawnHandler(Guid assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
// We need this check here because we don't want a null handler in the lambda expression below
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
RegisterSpawnHandler(assetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
}
/// <summary>This is an advanced spawning function that registers a custom assetId with the spawning system.</summary>
// This can be used to register custom spawning methods for an assetId -
// instead of the usual method of registering spawning methods for a
// prefab. This should be used when no prefab exists for the spawned
// objects - such as when they are constructed dynamically at runtime
// from configuration data.
public static void RegisterSpawnHandler(Guid assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (spawnHandler == null)
{
Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
return;
}
if (unspawnHandler == null)
{
Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
return;
}
if (assetId == Guid.Empty)
{
Debug.LogError("Can not Register SpawnHandler for empty Guid");
return;
}
if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
{
Debug.LogWarning($"Replacing existing spawnHandlers for {assetId}");
}
if (prefabs.ContainsKey(assetId))
{
// this is error because SpawnPrefab checks prefabs before handler
Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}'");
}
// Debug.Log("RegisterSpawnHandler asset '" + assetId + "' " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName());
spawnHandlers[assetId] = spawnHandler;
unspawnHandlers[assetId] = unspawnHandler;
}
/// <summary> Removes a registered spawn handler function that was registered with ClientScene.RegisterHandler().</summary>
public static void UnregisterSpawnHandler(Guid assetId)
{
spawnHandlers.Remove(assetId);
unspawnHandlers.Remove(assetId);
}
/// <summary>This clears the registered spawn prefabs and spawn handler functions for this client.</summary>
public static void ClearSpawners()
{
prefabs.Clear();
spawnHandlers.Clear();
unspawnHandlers.Clear();
}
internal static bool InvokeUnSpawnHandler(Guid assetId, GameObject obj)
{
if (unspawnHandlers.TryGetValue(assetId, out UnSpawnDelegate handler) && handler != null)
{
handler(obj);
return true;
}
return false;
}
// update //////////////////////////////////////////////////////////////
// NetworkEarlyUpdate called before any Update/FixedUpdate
// (we add this to the UnityEngine in NetworkLoop)

View File

@ -807,10 +807,10 @@ void RegisterClientMessages()
NetworkClient.RegisterHandler<SceneMessage>(OnClientSceneInternal, false);
if (playerPrefab != null)
ClientScene.RegisterPrefab(playerPrefab);
NetworkClient.RegisterPrefab(playerPrefab);
foreach (GameObject prefab in spawnPrefabs.Where(t => t != null))
ClientScene.RegisterPrefab(prefab);
NetworkClient.RegisterPrefab(prefab);
}
/// <summary>

View File

@ -29,9 +29,9 @@ public abstract class ClientSceneTestsBase
protected readonly List<GameObject> _createdObjects = new List<GameObject>();
protected Dictionary<Guid, GameObject> prefabs => ClientScene.prefabs;
protected Dictionary<Guid, SpawnHandlerDelegate> spawnHandlers => ClientScene.spawnHandlers;
protected Dictionary<Guid, UnSpawnDelegate> unspawnHandlers => ClientScene.unspawnHandlers;
protected Dictionary<Guid, GameObject> prefabs => NetworkClient.prefabs;
protected Dictionary<Guid, SpawnHandlerDelegate> spawnHandlers => NetworkClient.spawnHandlers;
protected Dictionary<Guid, UnSpawnDelegate> unspawnHandlers => NetworkClient.unspawnHandlers;
protected Dictionary<ulong, NetworkIdentity> spawnableObjects => ClientScene.spawnableObjects;

View File

@ -49,7 +49,7 @@ public class ClientSceneTests_DestroyAllClientObjects
{
public static readonly List<GameObject> _createdObjects = new List<GameObject>();
Dictionary<uint, NetworkIdentity> spawned => NetworkIdentity.spawned;
Dictionary<Guid, UnSpawnDelegate> unspawnHandlers => ClientScene.unspawnHandlers;
Dictionary<Guid, UnSpawnDelegate> unspawnHandlers => NetworkClient.unspawnHandlers;
[TearDown]
public void TearDown()