159 lines
6.3 KiB
C#
159 lines
6.3 KiB
C#
![]() |
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<int, int> ButtonToFloor = new();
|
||
|
public readonly Dictionary<int, Transform> 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<UnityElevatorService> _logger;
|
||
|
private readonly IEntitiesService _entitiesService;
|
||
|
private readonly Dictionary<int, UnityElevatorNode> _elevatorNodes=new();
|
||
|
private readonly Dictionary<int, ElevatorData> _elevatorData = new();
|
||
|
private readonly Dictionary<int,int> _buttonToElevator = new();
|
||
|
private readonly Dictionary<int, CancellationTokenSource> _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<UnityElevatorService> 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;
|
||
|
}
|
||
|
}
|
||
|
}
|