171 lines
6.4 KiB
C#
171 lines
6.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Cysharp.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.Pool;
|
|
|
|
namespace DanieleMarotta.RiversongCodeShowcase
|
|
{
|
|
public class ConstructionSiteManager : GameSystem, IInitializable, IDisposable, IUpdatable
|
|
{
|
|
private const int SpatialLookupCellSize = 5;
|
|
|
|
private const int StorageCapacity = 100;
|
|
|
|
[InjectService]
|
|
private GameConfig _config;
|
|
|
|
[InjectService]
|
|
private IScene _scene;
|
|
|
|
[InjectService]
|
|
private ISignalBus _signalBus;
|
|
|
|
[InjectService]
|
|
private IEntityCollection _entityCollection;
|
|
|
|
[InjectService]
|
|
private ITileSpace _tileSpace;
|
|
|
|
[InjectService]
|
|
private IProductStorageManager _productStorageManager;
|
|
|
|
[InjectService]
|
|
private IProductCatalog _productCatalog;
|
|
|
|
[InjectService]
|
|
private IProductStackFactory _productStackFactory;
|
|
|
|
[InjectService]
|
|
private IAgentFactory _agentFactory;
|
|
|
|
private Dictionary<int, GameObject> _visualizations = new();
|
|
|
|
private SpatialLookup<(ConstructionSite, GameObject)> _spatialLookup = new(SpatialLookupCellSize);
|
|
|
|
private MaterialPropertyBlock _materialPropertyBlock;
|
|
|
|
public ConstructionSiteManager(IServiceLocator serviceLocator) : base(serviceLocator)
|
|
{
|
|
}
|
|
|
|
public UniTask InitializeAsync()
|
|
{
|
|
_signalBus.Subscribe<BuildingPlacementAnimationCompletedSignal>(OnBuildingPlaced);
|
|
_signalBus.Subscribe<CollectDeletedGameObjectsSignal>(OnCollectDeletedGameObjects);
|
|
_signalBus.Subscribe<DoDeleteToolSignal>(OnDoDeleteTool);
|
|
|
|
return UniTask.CompletedTask;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_signalBus.Unsubscribe<BuildingPlacementAnimationCompletedSignal>(OnBuildingPlaced);
|
|
_signalBus.Unsubscribe<CollectDeletedGameObjectsSignal>(OnCollectDeletedGameObjects);
|
|
_signalBus.Unsubscribe<DoDeleteToolSignal>(OnDoDeleteTool);
|
|
}
|
|
|
|
private void OnBuildingPlaced(BuildingPlacementAnimationCompletedSignal signal)
|
|
{
|
|
var constructionSite = _entityCollection.Create<ConstructionSite>();
|
|
|
|
constructionSite.Building = signal.Building;
|
|
constructionSite.Rect = signal.Rect;
|
|
constructionSite.Orientation = signal.Orientation;
|
|
_productStorageManager.InitializeProductStorage(constructionSite, StorageCapacity);
|
|
_agentFactory.InitializeAgentSource(constructionSite);
|
|
|
|
_entityCollection.Add(constructionSite);
|
|
|
|
_ = CreateVisualizationAsync(constructionSite);
|
|
}
|
|
|
|
private async UniTask CreateVisualizationAsync(ConstructionSite constructionSite)
|
|
{
|
|
var position = _tileSpace.GetRectWorldCenter(constructionSite.Rect);
|
|
var rotation = constructionSite.Orientation.ToQuaternion();
|
|
var folder = _scene.SceneFolders.Buildings;
|
|
|
|
var visualization = await constructionSite.Building.Visualization.InstantiateAsync(position, rotation, folder);
|
|
ReplaceMaterials(visualization);
|
|
|
|
_visualizations.Add(constructionSite.Id, visualization);
|
|
_spatialLookup.Add((constructionSite, visualization), constructionSite.Rect, constructionSite.Id);
|
|
}
|
|
|
|
private void ReplaceMaterials(GameObject gameObject)
|
|
{
|
|
var material = _config.Buildings.ConstructionSiteMaterial;
|
|
|
|
using var renderersScope = ListPool<Renderer>.Get(out var renderers);
|
|
gameObject.GetComponentsInChildren(renderers);
|
|
|
|
_materialPropertyBlock ??= new MaterialPropertyBlock();
|
|
|
|
foreach (var renderer in renderers) MaterialReplacementCache.ReplaceRendererMaterials(renderer, material, _materialPropertyBlock);
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
using var toCompleteScope = ListPool<ConstructionSite>.Get(out var toComplete);
|
|
|
|
foreach (ConstructionSite constructionSite in _entityCollection.GetInternalEntityList(typeof(ConstructionSite)))
|
|
if (_visualizations.ContainsKey(constructionSite.Id) && AllBuildingMaterialsFetched(constructionSite))
|
|
toComplete.Add(constructionSite);
|
|
|
|
foreach (var constructionSite in toComplete)
|
|
{
|
|
_entityCollection.Remove(constructionSite.Id);
|
|
|
|
_visualizations.Remove(constructionSite.Id, out var visualization);
|
|
_spatialLookup.Remove(constructionSite.Rect, constructionSite.Id);
|
|
|
|
constructionSite.Building.Visualization.ReleaseInstance(visualization);
|
|
|
|
_signalBus.Raise(new ConstructionCompletedSignal(constructionSite));
|
|
}
|
|
}
|
|
|
|
private bool AllBuildingMaterialsFetched(ConstructionSite constructionSite)
|
|
{
|
|
ref var storage = ref constructionSite.GetStorageRW();
|
|
|
|
foreach (var (product, amount) in constructionSite.Building.BuildingMaterials)
|
|
{
|
|
var handle = _productCatalog.GetHandle(product);
|
|
if (storage.AvailableNow(handle) < amount) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnCollectDeletedGameObjects(CollectDeletedGameObjectsSignal signal)
|
|
{
|
|
if ((signal.Filter & DeletedGameObjectsFilter.Buildings) == 0) return;
|
|
|
|
using var lookupResultScope = ListPool<(ConstructionSite, GameObject)>.Get(out var lookupResult);
|
|
_spatialLookup.Find(signal.Rect, lookupResult);
|
|
|
|
foreach (var (_, visualization) in lookupResult) signal.GameObjects.Add(visualization);
|
|
}
|
|
|
|
private void OnDoDeleteTool(DoDeleteToolSignal signal)
|
|
{
|
|
using var lookupResultScope = ListPool<(ConstructionSite, GameObject)>.Get(out var lookupResult);
|
|
_spatialLookup.Find(signal.Rect, lookupResult);
|
|
|
|
foreach (var (constructionSite, visualization) in lookupResult)
|
|
{
|
|
_productStackFactory.CreateProductStacksFrom(constructionSite);
|
|
|
|
_entityCollection.Remove(constructionSite.Id);
|
|
_visualizations.Remove(constructionSite.Id);
|
|
_spatialLookup.Remove(constructionSite.Rect, constructionSite.Id);
|
|
|
|
constructionSite.Building.Visualization.ReleaseInstance(visualization);
|
|
|
|
_signalBus.Raise(new ConstructionSiteDeletedSignal(constructionSite));
|
|
}
|
|
}
|
|
}
|
|
} |