using System; using Unity.Collections; namespace SepCore.Simulation { public sealed partial class SimulationWorld { #region Job Data Lifecycle private void InitializeJobDataChannels() { if (AreJobDataChannelsUsable()) { return; } DisposeJobDataChannels(); _enemies.Initialize(64); _projectiles.Initialize(64); _pickups.Initialize(32); _enemySeparationTransforms = new NativeList(64, Allocator.Persistent); _collectedPickups = new NativeList(64, Allocator.Persistent); _enemySeparationBuckets = new NativeParallelMultiHashMap(256, Allocator.Persistent); _collisionQueryInputs = new NativeList(64, Allocator.Persistent); _collisionCandidates = new NativeList(128, Allocator.Persistent); _enemyCollisionBuckets = new NativeParallelMultiHashMap(256, Allocator.Persistent); InitializeEnemyTargetSpatialIndex(); } private void DisposeJobDataChannels() { _enemies.Dispose(); _projectiles.Dispose(); _pickups.Dispose(); if (_enemySeparationTransforms.IsCreated) { _enemySeparationTransforms.Dispose(); } _enemySeparationTransforms = default; if (_collectedPickups.IsCreated) { _collectedPickups.Dispose(); } _collectedPickups = default; if (_enemySeparationBuckets.IsCreated) { _enemySeparationBuckets.Dispose(); } _enemySeparationBuckets = default; if (_collisionQueryInputs.IsCreated) { _collisionQueryInputs.Dispose(); } _collisionQueryInputs = default; if (_collisionCandidates.IsCreated) { _collisionCandidates.Dispose(); } _collisionCandidates = default; if (_enemyCollisionBuckets.IsCreated) { _enemyCollisionBuckets.Dispose(); } _enemyCollisionBuckets = default; DisposeEnemyTargetSpatialIndex(); _areaCollisionRequests.Clear(); _areaCollisionHitEvents.Clear(); _areaCollisionHitDedupKeys.Clear(); ResetCollisionRuntimeStats(); } private void ClearJobDataChannels() { if (!AreJobDataChannelsUsable()) { _areaCollisionRequests.Clear(); _areaCollisionHitEvents.Clear(); _areaCollisionHitDedupKeys.Clear(); ResetCollisionRuntimeStats(); return; } if (_enemySeparationTransforms.IsCreated) { _enemySeparationTransforms.Clear(); } if (_collectedPickups.IsCreated) { _collectedPickups.Clear(); } if (_collisionQueryInputs.IsCreated) { _collisionQueryInputs.Clear(); } if (_collisionCandidates.IsCreated) { _collisionCandidates.Clear(); } if (_enemySeparationBuckets.IsCreated) { _enemySeparationBuckets.Clear(); } if (_enemyCollisionBuckets.IsCreated) { _enemyCollisionBuckets.Clear(); } ClearEnemyTargetSpatialIndex(); _areaCollisionRequests.Clear(); _areaCollisionHitEvents.Clear(); _areaCollisionHitDedupKeys.Clear(); ResetCollisionRuntimeStats(); } private bool AreJobDataChannelsUsable() { return _enemies.IsCreated && _projectiles.IsCreated && _pickups.IsCreated && IsNativeListUsable(_enemySeparationTransforms) && IsNativeListUsable(_collectedPickups) && IsNativeListUsable(_collisionQueryInputs) && IsNativeListUsable(_collisionCandidates) && IsNativeMultiHashMapUsable(_enemySeparationBuckets) && IsNativeMultiHashMapUsable(_enemyCollisionBuckets); } private static void EnsureCapacity(ref NativeList nativeList, int targetCount) where T : unmanaged { if (!nativeList.IsCreated || targetCount <= 0) { return; } if (nativeList.Capacity < targetCount) { nativeList.Capacity = targetCount; } } private static void EnsureCapacity(ref NativeParallelMultiHashMap hashMap, int targetCount) { if (!hashMap.IsCreated || targetCount <= 0) { return; } if (hashMap.Capacity < targetCount) { hashMap.Capacity = targetCount; } } private static bool IsNativeListUsable(NativeList nativeList) where T : unmanaged { if (!nativeList.IsCreated) { return false; } try { _ = nativeList.Length; return true; } catch (ObjectDisposedException) { return false; } } private static bool IsNativeMultiHashMapUsable(NativeParallelMultiHashMap hashMap) { if (!hashMap.IsCreated) { return false; } try { _ = hashMap.Count(); return true; } catch (ObjectDisposedException) { return false; } } #endregion } }