using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using Unity.Mathematics; using UnityEngine; using UnityEngine.Pool; namespace DanieleMarotta.RiversongCodeShowcase { [Service(typeof(IRoadFactory))] public class RoadManagerSystem : GameSystem, IInitializable, IDisposable, IUpdatable, IRoadFactory { [InjectService] protected GameConfig _config; [InjectService] private World _world; [InjectService] private ISignalBus _signalBus; private readonly List> _pendingTiles = new(); private float _placeTileTimer; public RoadManagerSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public UniTask InitializeAsync() { _signalBus.Subscribe(OnDoDeleteToolSignal); return UniTask.CompletedTask; } public void Dispose() { _signalBus.Unsubscribe(OnDoDeleteToolSignal); } public void Update() { PlaceTiles(); } private void PlaceTiles() { if (_pendingTiles.Count == 0) { _placeTileTimer = 0; return; } _placeTileTimer += Time.unscaledDeltaTime; if (_placeTileTimer < _config.Roads.PlaceTileInterval) return; for (var i = _pendingTiles.Count - 1; i >= 0; i--) { var tileQueue = _pendingTiles[i]; while (tileQueue.Count > 0) { var tile = tileQueue[0]; tileQueue.RemoveAt(0); if (_world.RoadNetwork.IsRoadTile(tile)) continue; _world.RoadNetwork.AddRoadTile(tile); UpdateTilesAround(tile); _signalBus.Raise(new RoadTileUpdatedSignal(tile, true)); _placeTileTimer = 0; break; } if (tileQueue.Count == 0) { _pendingTiles.RemoveAt(i); ListPool.Release(tileQueue); } } } private void OnDoDeleteToolSignal(DoDeleteToolSignal signal) { using var deletedTilesScope = ListPool.Get(out var deletedTiles); foreach (var tile in TileRange.From(signal.Rect)) { if (!_world.RoadNetwork.IsRoadTile(tile)) continue; _world.RoadNetwork.RemoveRoadTile(tile); UpdateTilesAround(tile); deletedTiles.Add(tile); } foreach (var tile in deletedTiles) _signalBus.Raise(new RoadTileUpdatedSignal(tile, false)); } private void UpdateTilesAround(int2 tile) { if (tile.x > 0) _world.RoadNetwork.UpdateRoadTile(tile + new int2(-1, 0)); if (tile.y < _world.Size.x - 1) _world.RoadNetwork.UpdateRoadTile(tile + new int2(1, 0)); if (tile.y > 0) _world.RoadNetwork.UpdateRoadTile(tile + new int2(0, -1)); if (tile.y < _world.Size.y - 1) _world.RoadNetwork.UpdateRoadTile(tile + new int2(0, 1)); } public void CreateRoad(int2 startTile, int2 endTile) { var tileQueue = ListPool.Get(); _pendingTiles.Add(tileQueue); TileMath.WalkLine(startTile, endTile, tileQueue.Add); } } }