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); private QuadtreeRoot> _quadtree; [SerializeReference, SubclassSelector] private ITicker ticker; [SerializeField, ReadOnly] private int count; [SerializeField, Range(0, 128)] private int[] lodDistances; [SerializeField] private Vector3 size; private Camera _camera; private readonly HashSet cacheList = new(); private void Awake() { Singleton = (T) this; } private void Start() { ticker.Add(OnTick); destroyCancellationToken.Register(Dispose); _quadtree = new QuadtreeRoot>(default, size); _camera = Camera.main; } private void Dispose() { ticker.Remove(OnTick); _registerQueue.Clear(); _unregisterQueue.Clear(); } private void OnTick(float deltaTime) { while (_unregisterQueue.TryDequeue(out var obj)) { _quadtree.Remove(obj); } while (_registerQueue.TryDequeue(out var obj)) { obj.Id = count++; _quadtree.Insert(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, size); } } }