using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using Quadtree; using UnityEngine; namespace BITKit.OpenWorld { public class WorldChunkService : MonoBehaviour where T : WorldChunkService { public static T Singleton { get; private set; } private readonly ConcurrentQueue _registerQueue = new(); private readonly ConcurrentQueue _unregisterQueue = new(); public void Register(IWorldChunkObject obj) => _registerQueue.Enqueue(obj); public void Unregister(IWorldChunkObject obj) => _unregisterQueue.Enqueue(obj); protected QuadtreeRoot> _quadtree; private readonly ConcurrentDictionary dictionary=new(); [SerializeReference, SubclassSelector] private ITicker ticker; [SerializeField, ReadOnly] private int count; [SerializeField] private bool drawBounds; [SerializeField, Range(0, 1024)] private int[] lodDistances; [SerializeField] private Vector3 size; private Camera _camera; private readonly HashSet cacheList = new(); protected virtual void Awake() { Singleton = (T) this; } protected virtual void Start() { ticker.Add(OnTick); destroyCancellationToken.Register(Dispose); _quadtree = new QuadtreeRoot>(transform.position, size); _camera = Camera.main; } private void Dispose() { ticker.Remove(OnTick); _registerQueue.Clear(); _unregisterQueue.Clear(); } protected virtual void OnTick(float deltaTime) { while (_unregisterQueue.TryDequeue(out var obj)) { _quadtree.Remove(obj); dictionary.Remove(obj.Id, out _); } while (_registerQueue.TryDequeue(out var obj)) { obj.Id = count++; _quadtree.Insert(obj); dictionary.TryAdd(obj.Id, obj); } var cameraPosition = _camera.transform.position; for (var index = 0; index < lodDistances.Length; index++) { var distance = lodDistances[index]; foreach (var chunkObject in _quadtree.Find(new Bounds(cameraPosition, Vector3.one * distance))) { if (cacheList.Contains(chunkObject.Id)) continue; cacheList.Add(chunkObject.Id); var lod = chunkObject.Lod; if (lod == index) continue; try { chunkObject.Lod = index; } catch (Exception e) { BIT4Log.LogException(e); } } } cacheList.Clear(); } private void OnDrawGizmosSelected() { var pos = transform.position; Gizmos.DrawWireCube(pos,transform.rotation * size); if(drawBounds) _quadtree.CurrentRootNode.DrawBounds(true); if(!_camera)return; var cameraPosition = _camera.transform.position; foreach (var VARIABLE in lodDistances) { Gizmos.DrawWireSphere(cameraPosition, VARIABLE); } } } }