diff --git a/Assets/PurrDiction/Runtime/Core/PredictedComponentIDExtensions.cs b/Assets/PurrDiction/Runtime/Core/PredictedComponentIDExtensions.cs index e6e68a73..9e974ea9 100644 --- a/Assets/PurrDiction/Runtime/Core/PredictedComponentIDExtensions.cs +++ b/Assets/PurrDiction/Runtime/Core/PredictedComponentIDExtensions.cs @@ -34,4 +34,4 @@ public static bool TryGetIdentity(this PredictedComponentID? id, PredictionManag return id?.TryGetIdentity(manager, out identity) ?? false; } } -} \ No newline at end of file +} diff --git a/Assets/PurrDiction/Runtime/Core/PredictionManager.cs b/Assets/PurrDiction/Runtime/Core/PredictionManager.cs index 612cdd6d..0f06bc2d 100644 --- a/Assets/PurrDiction/Runtime/Core/PredictionManager.cs +++ b/Assets/PurrDiction/Runtime/Core/PredictionManager.cs @@ -388,15 +388,22 @@ public void UnregisterPooledInstance(GameObject go) } readonly Dictionary _instanceMap = new (); + readonly Dictionary _deletingInstanceMap = new (); public bool TryGetIdentity(PredictedComponentID id, out PredictedIdentity instance) { - return _instanceMap.TryGetValue(id, out instance); + if (_instanceMap.TryGetValue(id, out instance)) + return true; + + return _deletingInstanceMap.TryGetValue(id, out instance); } public PredictedIdentity GetIdentity(PredictedComponentID id) { - return _instanceMap.GetValueOrDefault(id); + if (_instanceMap.TryGetValue(id, out var identity)) + return identity; + + return _deletingInstanceMap.GetValueOrDefault(id); } private void RegisterInstance(PredictedIdentity system, PredictedObjectID objectId, uint componentId, PlayerID? owner) @@ -679,8 +686,7 @@ private void OnPreTick() } } - for (var i = 0; i < _systemsCount; i++) - _systems[i].PostSimulate(); + PostSimulateAll(); if (cachedIsServer) FinalizeTickOnServer(cachedIsClient); @@ -1176,8 +1182,7 @@ private void SimulateFrameInPlace(ulong verifiedTick) lateSimulateMarker.Dispose(); } - for (var i = 0; i < _systemsCount; i++) - _systems[i].PostSimulate(); + PostSimulateAll(); for (var j = 0; j < _systemsCount; j++) _systems[j].GetLatestUnityState(); @@ -1258,8 +1263,7 @@ private void SimulateFrame(ulong verifiedTick, bool saveState) } } - for (var i = 0; i < _systemsCount; i++) - _systems[i].PostSimulate(); + PostSimulateAll(); for (var j = 0; j < _systemsCount; j++) _systems[j].GetLatestUnityState(); @@ -1502,34 +1506,84 @@ internal GameObject InternalCreate(GameObject prefab, Vector3 position, Quaterni internal void InternalDelete(PackedInt prefabId, GameObject instance) { - int pid = prefabId; - - if (!_predictedPrefabs || pid < 0 || pid >= _predictedPrefabs.prefabs.Count) + var deletingIds = BeginDeletingInstance(instance); + try { - UnregisterInstance(instance, false, true); - UnityProxy.DestroyImmediateDirectly(instance); - return; - } + int pid = prefabId; - var prefabsInfo = _predictedPrefabs.prefabs[pid]; + if (!_predictedPrefabs || pid < 0 || pid >= _predictedPrefabs.prefabs.Count) + { + UnregisterInstance(instance, false, true); + UnityProxy.DestroyImmediateDirectly(instance); + return; + } - if (!prefabsInfo.pooled) - { - UnregisterInstance(instance, false, true); - UnityProxy.DestroyImmediateDirectly(instance); - return; - } + var prefabsInfo = _predictedPrefabs.prefabs[pid]; + + if (!prefabsInfo.pooled) + { + UnregisterInstance(instance, false, true); + UnityProxy.DestroyImmediateDirectly(instance); + return; + } - if (_pools != null && _pools.TryGetPool(prefabsInfo.prefab, out var pool)) + if (_pools != null && _pools.TryGetPool(prefabsInfo.prefab, out var pool)) + { + UnregisterPooledInstance(instance); + pool.Delete(instance); + } + else + { + UnregisterInstance(instance, false, true); + UnityProxy.DestroyImmediateDirectly(instance); + } + } + finally { - UnregisterPooledInstance(instance); - pool.Delete(instance); + if (!isSimulating) + EndDeletingInstance(deletingIds); } - else + } + + private List BeginDeletingInstance(GameObject instance) + { + var deletingIds = new List(); + + if (!instance) + return deletingIds; + + var identities = ListPool.Instantiate(); + instance.GetComponentsInChildren(true, identities); + + for (int i = 0; i < identities.Count; i++) { - UnregisterInstance(instance, false, true); - UnityProxy.DestroyImmediateDirectly(instance); + var identity = identities[i]; + var id = identity.id; + _deletingInstanceMap[id] = identity; + deletingIds.Add(id); } + + ListPool.Destroy(identities); + return deletingIds; + } + + private void EndDeletingInstance(List deletingIds) + { + for (int i = 0; i < deletingIds.Count; i++) + _deletingInstanceMap.Remove(deletingIds[i]); + } + + private void ClearDeletingInstanceMap() + { + _deletingInstanceMap.Clear(); + } + + private void PostSimulateAll() + { + for (var i = 0; i < _systemsCount; i++) + _systems[i].PostSimulate(); + + ClearDeletingInstanceMap(); } public void SetOwnership(PredictedObjectID? root, PlayerID? player)