using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using BITKit; using BITKit.Entities; using BITKit.StateMachine; using BITKit.Tween; using BITKit.UX.Hotkey; using BITKit.WorldNode; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Net.Project.B.Interaction; using UnityEngine; namespace Net.Project.B.WorldNode { public class UnityElevatorService:IDisposable { public sealed class ElevatorData { public int ElevatorId; public Rigidbody Rigidbody; public int ElevatorButtonId; public readonly Dictionary ButtonToFloor = new(); public readonly Dictionary Floors = new(); } public abstract class ElevatorState:StateAsync { } public sealed class IdleState:ElevatorState { } public sealed class TransportingState:ElevatorState { } public sealed class FaultState:ElevatorState { } private readonly ILogger _logger; private readonly IEntitiesService _entitiesService; private readonly Dictionary _elevatorNodes=new(); private readonly Dictionary _elevatorData = new(); private readonly Dictionary _buttonToElevator = new(); private readonly Dictionary _cts = new(); private readonly IWorldInteractionService _interactionService; private readonly IFixedTicker _fixedTicker; private readonly IUXHotKey _uxHotKey; public UnityElevatorService(IFixedTicker fixedTicker, IWorldInteractionService interactionService, IEntitiesService entitiesService, IUXHotKey uxHotKey, ILogger logger) { _fixedTicker = fixedTicker; _interactionService = interactionService; _entitiesService = entitiesService; _uxHotKey = uxHotKey; _logger = logger; _interactionService.OnInteraction+=OnInteraction; _entitiesService.OnAdd += OnNodeRegistered; _entitiesService.OnRemove += OnRemove; } private void OnRemove(IEntity obj) { if (!_cts.TryGetValue(obj.Id, out var cts)) return; cts.Cancel(); cts.Dispose(); } private async void OnInteraction(object arg1, IWorldInteractable arg2, WorldInteractionProcess arg3, object arg4) { if(arg3 is not (WorldInteractionProcess.Performed or WorldInteractionProcess.System))return; if(_buttonToElevator.TryGetValue(arg2.Id,out var elevatorId) is false)return; if(_elevatorData.TryGetValue(elevatorId,out var elevatorData) is false)return; if (elevatorData.ElevatorButtonId != arg2.Id) { if(elevatorData.ButtonToFloor.TryGetValue(arg2.Id,out var floor) is false)return; if(elevatorData.Floors.TryGetValue(floor,out var floorTransform) is false)return; var currentPosition = elevatorData.Rigidbody.position; var targetPosition = currentPosition; targetPosition.y = floorTransform.position.y; _logger.LogInformation($"Elevator {elevatorId} to {floor+1}F"); if (_cts.TryGetValue(elevatorData.ElevatorId, out var cts)) { cts.Cancel(); cts.Dispose(); } cts = _cts[elevatorData.ElevatorId] = new CancellationTokenSource(); await BITween.MoveToForward(elevatorData.Rigidbody.MovePosition, currentPosition,targetPosition, 1, Vector3.MoveTowards,cts.Token); } else { _logger.LogInformation($"Elevator {elevatorId} Menu"); var hotKeyCollections = new HotkeyCollection(); foreach (var (buttonId,floor) in elevatorData.ButtonToFloor) { if(_entitiesService.TryGetEntity(buttonId,out var buttonEntity) is false)continue; if(buttonEntity.ServiceProvider.QueryComponents(out IWorldInteractable buttonInteractable) is false)continue; var hotkeyProvider = new HotkeyProvider { Name = $"{floor+1}F", Description = $"Elevator to {floor+1}F", Enabled = buttonId!=arg2.Id, OnPerform = () => { if(buttonEntity.CancellationToken.IsCancellationRequested)return; OnInteraction(arg1, buttonInteractable, WorldInteractionProcess.System, arg4); } }; hotKeyCollections.Register(hotkeyProvider); } _uxHotKey.Perform(hotKeyCollections); } } private void OnNodeRegistered(IEntity entity) { if (entity.ServiceProvider.QueryComponents(out UnityElevatorNode elevatorNode) is false) return; _elevatorNodes[entity.Id]=elevatorNode; var elevatorData = new ElevatorData { ElevatorId = entity.Id, Rigidbody = elevatorNode.Platform, }; for (var i = 0; i < elevatorNode.FloorButtons.Length; i++) { var button = elevatorNode.FloorButtons[i]; var buttonId = button.gameObject.GetInstanceID(); _buttonToElevator[buttonId] = entity.Id; elevatorData.ButtonToFloor[buttonId] = i; elevatorData.Floors[i] = elevatorNode.Floors[i].transform; } elevatorData.ElevatorButtonId = elevatorNode.ElevatorButton.GetInstanceID(); _buttonToElevator[elevatorData.ElevatorButtonId]=entity.Id; _elevatorData[entity.Id] = elevatorData; } public void Dispose() { _entitiesService.OnAdd -= OnNodeRegistered; _interactionService.OnInteraction-=OnInteraction; } } }