using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.InputSystem; namespace DanieleMarotta.RiversongCodeShowcase { public class BuildTool : EditTool { private IPointerService _pointerService; private ITileSpace _tileSpace; private IEditToolValidatorService _validator; private IBuildToolPreviewManager _previewManager; private Directions _buildingOrientation; private EditToolValidationResult _validationResult; public BuildTool(IServiceLocator serviceLocator) : base(serviceLocator) { } public BuildingDefinition Building { get; set; } public BuildToolPreview Preview { get; private set; } public TileRect BuildingRect { get; private set; } public override UniTask InitializeAsync() { var config = ServiceLocator.GetService(); _pointerService = ServiceLocator.GetService(); _tileSpace = ServiceLocator.GetService(); _validator = ServiceLocator.GetService(); _previewManager = ServiceLocator.GetService(); Preview = new BuildToolPreview(config.UI.BuildTool, _tileSpace); return UniTask.CompletedTask; } public override void OnEnabled() { base.OnEnabled(); if (!Building) { Debug.LogError("Building not set when activating Build Tool"); return; } Preview.PrepareForBuilding(Building); _buildingOrientation = Directions.North; } public override void OnDisabled() { base.OnDisabled(); Preview.Release(); } public override void Update() { base.Update(); var pointerOnTerrain = _pointerService.TryGetPositionOnTerrain(out var position); var keyboard = Keyboard.current; if (keyboard.tKey.wasPressedThisFrame) _buildingOrientation = (Directions)(((int)_buildingOrientation + 6) % 8); var buildingCenter = _tileSpace.WorldToTile(position); BuildingRect = TileMath.GetBuildingRect(buildingCenter, _buildingOrientation, Building.Width, Building.Height); _validationResult = ValidatePlacement(pointerOnTerrain); var isValid = _validationResult == EditToolValidationResult.Success; AffectedTiles.Clear(); if (pointerOnTerrain) { var highlightType = isValid ? TileHighlightType.ValidTile : TileHighlightType.InvalidTile; foreach (var tile in TileRange.From(BuildingRect)) AffectedTiles.Add((tile, highlightType)); } Preview.Update(isValid, position, _buildingOrientation); if (isValid && _pointerService.TryConsumeLeftClick()) Build(); } private EditToolValidationResult ValidatePlacement(bool pointerOnTerrain) { if (!pointerOnTerrain) return EditToolValidationResult.BlockedTile; var commonValidation = _validator.DoCommonValidation(BuildingRect, BlockReason.CannotBuild); if (commonValidation != EditToolValidationResult.Success) return commonValidation; return _validator.ValidateBuildingPlacementRules(BuildingRect, Building); } public EditToolValidationResult GetLastValidationResult() { return _validationResult; } private void Build() { _previewManager.PlayPlacementAnimationAndBuild(Preview, Building, BuildingRect, _buildingOrientation); } public override void GetDeleteGameObjectsPreviewInfo(out DeletedGameObjectsFilter filter, out TileRect rect) { if (_validationResult != EditToolValidationResult.Success) { filter = DeletedGameObjectsFilter.None; rect = TileRect.Empty; return; } filter = DeletedGameObjectsFilter.RawResources | DeletedGameObjectsFilter.ProductStacks; rect = BuildingRect; } } }