Files
riversong-code-showcase/Source/Riversong/Game/World/Buildings/Visualizations/BuildingVisualizationManager.cs
2026-05-21 16:04:49 +02:00

164 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[Service(typeof(IBuildingVisualizationCollection))]
public class BuildingVisualizationManager : GameSystem, IInitializable, IDisposable, IBuildingVisualizationCollection
{
private const int SpatialLookupCellSize = 5;
[InjectService]
private ISignalBus _signalBus;
[InjectService]
private IScene _scene;
[InjectService]
private ITileSpace _tileSpace;
[InjectService]
private IEntityCollection _entityCollection;
[InjectService]
private World _world;
private HashSet<int> _pendingVisualizations = new();
private Dictionary<int, BuildingVisualization> _visualizations = new();
private SpatialLookup<GameObject> _allVisualizationsSpatialLookup = new(SpatialLookupCellSize);
private SpatialLookup<GameObject> _canBeDeletedSpatialLookup = new(SpatialLookupCellSize);
public BuildingVisualizationManager(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public UniTask InitializeAsync()
{
_signalBus.Subscribe<BuildingCreatedSignal>(OnBuildingCreated);
_signalBus.Subscribe<CollectDeletedGameObjectsSignal>(OnCollectDeletedGameObjects);
_signalBus.Subscribe<BuildingDeletedSignal>(OnBuildingDeleted);
_signalBus.Subscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
return UniTask.CompletedTask;
}
public void Dispose()
{
_signalBus.Unsubscribe<BuildingCreatedSignal>(OnBuildingCreated);
_signalBus.Unsubscribe<CollectDeletedGameObjectsSignal>(OnCollectDeletedGameObjects);
_signalBus.Unsubscribe<BuildingDeletedSignal>(OnBuildingDeleted);
_signalBus.Unsubscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
}
private void OnBuildingCreated(BuildingCreatedSignal signal)
{
var building = signal.Building;
_pendingVisualizations.Add(building.Id);
_ = CreateVisualizationAsync(building);
}
private async UniTask CreateVisualizationAsync(Building building)
{
var folder = _scene.SceneFolders.Buildings;
var visualizationGameObject = await building.Definition.Visualization.InstantiateAsync(folder);
if (!_pendingVisualizations.Remove(building.Id))
{
building.Definition.Visualization.ReleaseInstance(visualizationGameObject);
return;
}
var visualization = visualizationGameObject.GetComponent<BuildingVisualization>();
if (!visualization)
{
Debug.LogError($"Building visualization '{visualizationGameObject.name}' has no {nameof(BuildingVisualization)} component");
return;
}
visualization.SetTier(0);
var position = _tileSpace.GetRectWorldCenter(building.Rect);
var rotation = building.Orientation.ToQuaternion();
visualization.transform.SetPositionAndRotation(position, rotation);
_visualizations.Add(building.Id, visualization);
_signalBus.Raise(new BuildingVisualizationCreatedSignal(building, visualization));
_allVisualizationsSpatialLookup.Add(visualization.gameObject, building.Rect, building.Id);
if (building.Definition.CanBeDeleted) _canBeDeletedSpatialLookup.Add(visualization.gameObject, building.Rect, building.Id);
}
private void OnCollectDeletedGameObjects(CollectDeletedGameObjectsSignal signal)
{
if ((signal.Filter & DeletedGameObjectsFilter.Buildings) == 0) return;
_canBeDeletedSpatialLookup.Find(signal.Rect, signal.GameObjects);
}
private void OnBuildingDeleted(BuildingDeletedSignal signal)
{
var building = signal.Building;
if (_pendingVisualizations.Remove(building.Id))
{
_signalBus.Raise(new BuildingDeleteAnimationCompletedSignal(building));
return;
}
_visualizations.Remove(building.Id, out var visualization);
_allVisualizationsSpatialLookup.Remove(building.Rect, building.Id);
_canBeDeletedSpatialLookup.Remove(building.Rect, building.Id);
if (signal.Options == DeleteBuildingOptions.Silent)
{
FinalizeBuildingDeletion(building, visualization);
return;
}
_ = PlayDeleteAnimationAsync(building, visualization);
}
private async UniTask PlayDeleteAnimationAsync(Building building, BuildingVisualization visualization)
{
var deleteAnimation = visualization.GetComponent<BuildingDeleteAnimation>();
await deleteAnimation.PlayAsync(building);
FinalizeBuildingDeletion(building, visualization);
}
private void FinalizeBuildingDeletion(Building building, BuildingVisualization visualization)
{
_signalBus.Raise(new BuildingDeleteAnimationCompletedSignal(building));
building.Definition.Visualization.ReleaseInstance(visualization.gameObject);
}
private void OnBuildingUpgraded(BuildingUpgradedSignal signal)
{
var building = signal.Building;
var visualization = _visualizations[building.Id];
visualization.SetTier(building.TierIndex);
if (visualization.TryGetComponent<BuildingUpgradeAnimation>(out var animation)) _ = animation.PlayAsync(building);
}
public bool IsVisualizationPending(int id)
{
return _pendingVisualizations.Contains(id);
}
public bool TryGetVisualization(int id, out BuildingVisualization visualization)
{
return _visualizations.TryGetValue(id, out visualization);
}
}
}