using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Pool; namespace DanieleMarotta.RiversongCodeShowcase { [UpdateAfter(typeof(EditingStateGameSystem))] public class GameObjectsHighlightingSystem : GameSystem, IInitializable, IDisposable { [InjectService] private GameConfig _gameConfig; [InjectService] private ISignalBus _signalBus; [InjectService] private EditingState _editingState; [InjectService] private UIState _uiState; [InjectService] private ITileSpace _tileSpace; [InjectService] private IEntityCache _entityCache; [InjectService] private IBuildingSpatialQuery _buildingSpatialQuery; [InjectService] private IProductStackVisualizationCollection _productStackVisualizationCollection; [InjectService] private IRawResourceVisualizationCollection _rawResourceVisualizationCollection; [InjectService] private IAgentVisualizationCollection _agentVisualizationCollection; [InjectService] private IBuildingVisualizationCollection _buildingVisualizationCollection; [InjectService] private World _world; public GameObjectsHighlightingSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public UniTask InitializeAsync() { _signalBus.Subscribe(OnCollectHighlightedGameObjects); return UniTask.CompletedTask; } public void Dispose() { _signalBus.Unsubscribe(OnCollectHighlightedGameObjects); } private bool TryGetSourceBuilding(out BuildingDefinition building, out TileRect sourceRect) { var tool = _editingState.ActiveTool; if (tool is BuildTool buildTool && buildTool.Preview.IsVisible) { building = buildTool.Building; sourceRect = buildTool.BuildingRect; return true; } var selectedBuilding = _uiState.SelectedBuilding; if (selectedBuilding != null) { building = selectedBuilding.Definition; sourceRect = selectedBuilding.Rect; return true; } building = null; sourceRect = TileRect.Empty; return false; } private void OnCollectHighlightedGameObjects(CollectHighlightedGameObjectsSignal signal) { if (!TryGetSourceBuilding(out var building, out var sourceRect)) return; CollectBuildings(signal.GameObjects, building, sourceRect); CollectProductStacks(signal.GameObjects, building, sourceRect); CollectResources(signal.GameObjects, building, sourceRect); CollectCritters(signal.GameObjects, building, sourceRect); } private void CollectBuildings(List gameObjects, BuildingDefinition sourceBuilding, TileRect sourceRect) { if (sourceBuilding.ProvidedProducts.Count > 0) { foreach (var house in _entityCache.GetHouses()) { if (TileMath.StepCount(sourceRect, house.Rect) > sourceBuilding.Range) continue; AddHighlightedBuilding(gameObjects, house); } if (sourceBuilding.FetchesProducts) foreach (var storage in _entityCache.GetStorageBuildings()) { if (TileMath.StepCount(sourceRect, storage.Rect) > sourceBuilding.Range) continue; AddHighlightedBuilding(gameObjects, storage); } } if (sourceBuilding.IsHouse) { using var providersScope = ListPool.Get(out var providers); _buildingSpatialQuery.FindProvidersForHouse(sourceRect, providers); foreach (var provider in providers) AddHighlightedBuilding(gameObjects, provider); } if (sourceBuilding.IsStorage) { using var providersScope = ListPool.Get(out var providers); _buildingSpatialQuery.FindProvidersForStorage(sourceRect, providers); foreach (var provider in providers) AddHighlightedBuilding(gameObjects, provider); } } private void AddHighlightedBuilding(List gameObjects, Building building) { if (_buildingVisualizationCollection.TryGetVisualization(building.Id, out var visualization)) gameObjects.Add(visualization.gameObject); } private void CollectProductStacks(List gameObjects, BuildingDefinition sourceBuilding, TileRect sourceRect) { if (!sourceBuilding.IsStorage) return; var rangeRect = sourceRect.Inflate(sourceBuilding.Range); using var productStacksScope = ListPool.Get(out var productStacks); _world.ProductStacks.Find(rangeRect, productStacks); foreach (var productStack in productStacks) { if (!_productStackVisualizationCollection.TryGetVisualization(productStack.Id, out var visualization)) continue; gameObjects.Add(visualization); } } private void CollectResources(List gameObjects, BuildingDefinition sourceBuilding, TileRect sourceRect) { if (!sourceBuilding.HarvestedResource) return; var rangeRect = sourceRect.Inflate(sourceBuilding.Range); using var resourceIdsScope = ListPool<(int, bool)>.Get(out var resourceIds); _world.RawResources.GetResourceNodes(rangeRect, _gameConfig.GeneralSettings.BaseElevation, resourceIds); foreach (var (id, _) in resourceIds) { _world.RawResources.TryGetResourceNode(id, out var resourceNode); if (resourceNode.DefinitionId != sourceBuilding.HarvestedResource.RuntimeId) continue; if (!_rawResourceVisualizationCollection.TryGetVisualization(resourceNode.Id, out var visualization)) continue; gameObjects.Add(visualization); } } private void CollectCritters(List gameObjects, BuildingDefinition sourceBuilding, TileRect sourceRect) { if (!sourceBuilding.TargetCritter) return; var rangeRect = sourceRect.Inflate(sourceBuilding.Range); foreach (var critter in _entityCache.GetCritterAgents()) { ref var critterState = ref critter.GetCritterStateRW(); if (critterState.CritterDefinitionId != sourceBuilding.TargetCritter.RuntimeId) continue; var critterTile = _tileSpace.WorldToTile(critter.Position); if (!rangeRect.Contains(critterTile)) continue; if (!_agentVisualizationCollection.TryGetVisualization(critter.Id, out var visualization)) continue; gameObjects.Add(visualization.gameObject); } } } }