diff --git a/Assets/Mirror/Examples/Room/Prefabs/Prize.prefab b/Assets/Mirror/Examples/Room/Prefabs/Reward.prefab similarity index 99% rename from Assets/Mirror/Examples/Room/Prefabs/Prize.prefab rename to Assets/Mirror/Examples/Room/Prefabs/Reward.prefab index a84a4584cd5..86a1302ffd2 100644 --- a/Assets/Mirror/Examples/Room/Prefabs/Prize.prefab +++ b/Assets/Mirror/Examples/Room/Prefabs/Reward.prefab @@ -9,13 +9,13 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 4362442735993418} - - component: {fileID: 114251241889735402} - - component: {fileID: 114048121767222990} - - component: {fileID: 5119366209337690377} - component: {fileID: 135606878775227198} - component: {fileID: 1765969535664783447} + - component: {fileID: 114251241889735402} + - component: {fileID: 5119366209337690377} + - component: {fileID: 114048121767222990} m_Layer: 0 - m_Name: Prize + m_Name: Reward m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -36,6 +36,35 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &135606878775227198 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.3 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1765969535664783447 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 --- !u!114 &114251241889735402 MonoBehaviour: m_ObjectHideFlags: 0 @@ -53,23 +82,6 @@ MonoBehaviour: serverOnly: 0 visibility: 0 hasSpawned: 0 ---- !u!114 &114048121767222990 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1139254171913846} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a22f9eb8ebad79e47babf4c051a714ee, type: 3} - m_Name: - m_EditorClassIdentifier: - syncDirection: 0 - syncMode: 0 - syncInterval: 0.1 - randomColor: {fileID: 5119366209337690377} - available: 1 --- !u!114 &5119366209337690377 MonoBehaviour: m_ObjectHideFlags: 0 @@ -88,35 +100,23 @@ MonoBehaviour: color: serializedVersion: 2 rgba: 4278190080 ---- !u!135 &135606878775227198 -SphereCollider: +--- !u!114 &114048121767222990 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1139254171913846} - m_Material: {fileID: 0} - m_IsTrigger: 1 m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.3 - m_Center: {x: 0, y: 0, z: 0} ---- !u!54 &1765969535664783447 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1139254171913846} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 1 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a22f9eb8ebad79e47babf4c051a714ee, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + randomColor: {fileID: 5119366209337690377} + available: 1 --- !u!1 &5133204039361288107 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Mirror/Examples/Room/Prefabs/Prize.prefab.meta b/Assets/Mirror/Examples/Room/Prefabs/Reward.prefab.meta similarity index 100% rename from Assets/Mirror/Examples/Room/Prefabs/Prize.prefab.meta rename to Assets/Mirror/Examples/Room/Prefabs/Reward.prefab.meta diff --git a/Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity b/Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity index 1e2151ec917..31ddae2e644 100644 --- a/Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity +++ b/Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity @@ -261,8 +261,6 @@ MonoBehaviour: headlessStartMode: 1 editorAutoStart: 0 sendRate: 30 - autoStartServerBuild: 0 - autoConnectClientBuild: 0 offlineScene: Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity onlineScene: Assets/Mirror/Examples/Room/Scenes/MirrorRoomOnline.unity offlineSceneLoadDelay: 0 @@ -276,8 +274,7 @@ MonoBehaviour: type: 3} autoCreatePlayer: 1 playerSpawnMethod: 1 - spawnPrefabs: - - {fileID: 1139254171913846, guid: 52f1c9ea06cfd154cb68ff9d1b66fc13, type: 3} + spawnPrefabs: [] exceptionsDisconnect: 1 snapshotSettings: bufferTimeMultiplier: 2 diff --git a/Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs b/Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs index 15218c31e66..9d199cea955 100644 --- a/Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs +++ b/Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs @@ -13,6 +13,7 @@ public class NetworkRoomManagerExt : NetworkRoomManager [Header("Spawner Setup")] [Tooltip("Reward Prefab for the Spawner")] public GameObject rewardPrefab; + public byte poolSize = 10; public static new NetworkRoomManagerExt singleton => NetworkManager.singleton as NetworkRoomManagerExt; @@ -24,7 +25,20 @@ public override void OnRoomServerSceneChanged(string sceneName) { // spawn the initial batch of Rewards if (sceneName == GameplayScene) + { + Spawner.InitializePool(rewardPrefab, poolSize); Spawner.InitialSpawn(); + } + else + Spawner.ClearPool(); + } + + public override void OnRoomClientSceneChanged() + { + // Don't initialize the pool for host client because it's + // already initialized in OnRoomServerSceneChanged + if (!NetworkServer.active && networkSceneName == GameplayScene) + Spawner.InitializePool(rewardPrefab, 10); } /// diff --git a/Assets/Mirror/Examples/Room/Scripts/Reward.cs b/Assets/Mirror/Examples/Room/Scripts/Reward.cs index de715a7c331..5d01516fe12 100644 --- a/Assets/Mirror/Examples/Room/Scripts/Reward.cs +++ b/Assets/Mirror/Examples/Room/Scripts/Reward.cs @@ -11,7 +11,7 @@ public class Reward : NetworkBehaviour [Header("Diagnostics")] [ReadOnly, SerializeField] - bool available = true; + bool available; protected override void OnValidate() { @@ -21,6 +21,11 @@ protected override void OnValidate() randomColor = GetComponent(); } + public override void OnStartServer() + { + available = true; + } + [ServerCallback] void OnTriggerEnter(Collider other) { @@ -28,12 +33,12 @@ void OnTriggerEnter(Collider other) // and eliminate the need for a tag check here. if (!other.CompareTag("Player")) return; - // This is a fast switch to prevent two players claiming the prize in a bang-bang close contest for it. + // This is a fast switch to prevent two players claiming the reward in a bang-bang close contest for it. // First to trigger turns it off, pending the object being destroyed a few frames later. if (!available) return; - else - available = false; + + available = false; // Calculate the points from the color...lighter scores higher as the average approaches 255 // UnityEngine.Color RGB values are byte 0 to 255 @@ -42,11 +47,7 @@ void OnTriggerEnter(Collider other) // award the points via SyncVar on Player's PlayerScore other.GetComponent().score += points; - // spawn a replacement - Spawner.SpawnReward(); - - // destroy this one - NetworkServer.Destroy(gameObject); + Spawner.RecycleReward(gameObject); } } } diff --git a/Assets/Mirror/Examples/Room/Scripts/Spawner.cs b/Assets/Mirror/Examples/Room/Scripts/Spawner.cs index bfeab0c38b4..912db525c39 100644 --- a/Assets/Mirror/Examples/Room/Scripts/Spawner.cs +++ b/Assets/Mirror/Examples/Room/Scripts/Spawner.cs @@ -1,13 +1,81 @@ +using System.Threading.Tasks; using UnityEngine; namespace Mirror.Examples.NetworkRoom { internal class Spawner { + static GameObject prefab; + static byte poolSize = 10; + static Pool pool; + static ushort counter; + + internal static void InitializePool(GameObject poolPrefab, byte count) + { + prefab = poolPrefab; + poolSize = count; + + NetworkClient.RegisterPrefab(prefab, SpawnHandler, UnspawnHandler); + pool = new Pool(CreateNew, poolSize); + } + + internal static void ClearPool() + { + if (prefab == null) return; + + NetworkClient.UnregisterPrefab(prefab); + + if (pool == null) return; + + // destroy all objects in pool + while (pool.Count > 0) + Object.Destroy(pool.Get()); + + counter = 0; + pool = null; + } + + static GameObject SpawnHandler(SpawnMessage msg) => Get(msg.position, msg.rotation); + + static void UnspawnHandler(GameObject spawned) => Return(spawned); + + static GameObject CreateNew() + { + // use this object as parent so that objects dont crowd hierarchy + GameObject next = Object.Instantiate(prefab); + counter++; + next.name = $"{prefab.name}_pooled_{counter:00}"; + next.SetActive(false); + return next; + } + + public static GameObject Get(Vector3 position, Quaternion rotation) + { + GameObject next = pool.Get(); + + // set position/rotation and set active + next.transform.position = position; + next.transform.rotation = rotation; + next.SetActive(true); + return next; + } + + // Used to put object back into pool so they can b + // Should be used on server after unspawning an object + // Used on client by NetworkClient to unspawn objects + public static void Return(GameObject spawned) + { + // disable object + spawned.SetActive(false); + + // add back to pool + pool.Return(spawned); + } + [ServerCallback] internal static void InitialSpawn() { - for (int i = 0; i < 10; i++) + for (byte i = 0; i < poolSize; i++) SpawnReward(); } @@ -15,7 +83,21 @@ internal static void InitialSpawn() internal static void SpawnReward() { Vector3 spawnPosition = new Vector3(Random.Range(-19, 20), 1, Random.Range(-19, 20)); - NetworkServer.Spawn(Object.Instantiate(NetworkRoomManagerExt.singleton.rewardPrefab, spawnPosition, Quaternion.identity)); + NetworkServer.Spawn(Get(spawnPosition, Quaternion.identity)); + } + + [ServerCallback] + internal static async void RecycleReward(GameObject reward) + { + NetworkServer.UnSpawn(reward); + Return(reward); + await DelayedSpawn(); + } + + static async Task DelayedSpawn() + { + await Task.Delay(new System.TimeSpan(0, 0, 1)); + SpawnReward(); } } }