163 lines
6.6 KiB
C#
163 lines
6.6 KiB
C#
using Brio.API;
|
|
using Dalamud.Game.ClientState.Objects.Types;
|
|
using Dalamud.Plugin;
|
|
using LightlessSync.API.Dto.CharaData;
|
|
using LightlessSync.Interop.Ipc.Framework;
|
|
using LightlessSync.Services;
|
|
using LightlessSync.Services.Mediator;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Numerics;
|
|
using System.Text.Json.Nodes;
|
|
|
|
namespace LightlessSync.Interop.Ipc;
|
|
|
|
public sealed class IpcCallerBrio : IpcServiceBase
|
|
{
|
|
private static readonly IpcServiceDescriptor BrioDescriptor = new("Brio", "Brio", new Version(0, 0, 0, 0));
|
|
|
|
private readonly ILogger<IpcCallerBrio> _logger;
|
|
private readonly DalamudUtilService _dalamudUtilService;
|
|
|
|
private readonly ApiVersion _apiVersion;
|
|
|
|
private readonly SpawnActor _spawnActor;
|
|
private readonly DespawnActor _despawnActor;
|
|
private readonly SetModelTransform _setModelTransform;
|
|
private readonly GetModelTransform _getModelTransform;
|
|
|
|
private readonly GetPoseAsJson _getPoseAsJson;
|
|
private readonly LoadPoseFromJson _setPoseFromJson;
|
|
|
|
private readonly FreezeActor _freezeActor;
|
|
private readonly FreezePhysics _freezePhysics;
|
|
|
|
public IpcCallerBrio(ILogger<IpcCallerBrio> logger, IDalamudPluginInterface dalamudPluginInterface,
|
|
DalamudUtilService dalamudUtilService, LightlessMediator mediator) : base(logger, mediator, dalamudPluginInterface, BrioDescriptor)
|
|
{
|
|
_logger = logger;
|
|
_dalamudUtilService = dalamudUtilService;
|
|
|
|
_apiVersion = new ApiVersion(dalamudPluginInterface);
|
|
_spawnActor = new SpawnActor(dalamudPluginInterface);
|
|
_despawnActor = new DespawnActor(dalamudPluginInterface);
|
|
|
|
_setModelTransform = new SetModelTransform(dalamudPluginInterface);
|
|
_getModelTransform = new GetModelTransform(dalamudPluginInterface);
|
|
|
|
_getPoseAsJson = new GetPoseAsJson(dalamudPluginInterface);
|
|
_setPoseFromJson = new LoadPoseFromJson(dalamudPluginInterface);
|
|
|
|
_freezeActor = new FreezeActor(dalamudPluginInterface);
|
|
_freezePhysics = new FreezePhysics(dalamudPluginInterface);
|
|
|
|
CheckAPI();
|
|
}
|
|
|
|
public async Task<IGameObject?> SpawnActorAsync()
|
|
{
|
|
if (!APIAvailable) return null;
|
|
_logger.LogDebug("Spawning Brio Actor");
|
|
return await _dalamudUtilService.RunOnFrameworkThread(() => _spawnActor.Invoke(Brio.API.Enums.SpawnFlags.Default, true)).ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<bool> DespawnActorAsync(nint address)
|
|
{
|
|
if (!APIAvailable) return false;
|
|
var gameObject = await _dalamudUtilService.CreateGameObjectAsync(address).ConfigureAwait(false);
|
|
if (gameObject == null) return false;
|
|
_logger.LogDebug("Despawning Brio Actor {actor}", gameObject.Name.TextValue);
|
|
return await _dalamudUtilService.RunOnFrameworkThread(() => _despawnActor.Invoke(gameObject)).ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<bool> ApplyTransformAsync(nint address, WorldData data)
|
|
{
|
|
if (!APIAvailable) return false;
|
|
var gameObject = await _dalamudUtilService.CreateGameObjectAsync(address).ConfigureAwait(false);
|
|
if (gameObject == null) return false;
|
|
_logger.LogDebug("Applying Transform to Actor {actor}", gameObject.Name.TextValue);
|
|
|
|
return await _dalamudUtilService.RunOnFrameworkThread(() => _setModelTransform.Invoke(gameObject,
|
|
new Vector3(data.PositionX, data.PositionY, data.PositionZ),
|
|
new Quaternion(data.RotationX, data.RotationY, data.RotationZ, data.RotationW),
|
|
new Vector3(data.ScaleX, data.ScaleY, data.ScaleZ), false)).ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<WorldData> GetTransformAsync(nint address)
|
|
{
|
|
if (!APIAvailable) return default;
|
|
var gameObject = await _dalamudUtilService.CreateGameObjectAsync(address).ConfigureAwait(false);
|
|
if (gameObject == null) return default;
|
|
var data = await _dalamudUtilService.RunOnFrameworkThread(() => _getModelTransform.Invoke(gameObject)).ConfigureAwait(false);
|
|
|
|
return new WorldData()
|
|
{
|
|
PositionX = data.Item1.Value.X,
|
|
PositionY = data.Item1.Value.Y,
|
|
PositionZ = data.Item1.Value.Z,
|
|
RotationX = data.Item2.Value.X,
|
|
RotationY = data.Item2.Value.Y,
|
|
RotationZ = data.Item2.Value.Z,
|
|
RotationW = data.Item2.Value.W,
|
|
ScaleX = data.Item3.Value.X,
|
|
ScaleY = data.Item3.Value.Y,
|
|
ScaleZ = data.Item3.Value.Z
|
|
};
|
|
}
|
|
|
|
public async Task<string?> GetPoseAsync(nint address)
|
|
{
|
|
if (!APIAvailable) return null;
|
|
var gameObject = await _dalamudUtilService.CreateGameObjectAsync(address).ConfigureAwait(false);
|
|
if (gameObject == null) return null;
|
|
_logger.LogDebug("Getting Pose from Actor {actor}", gameObject.Name.TextValue);
|
|
|
|
return await _dalamudUtilService.RunOnFrameworkThread(() => _getPoseAsJson.Invoke(gameObject)).ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<bool> SetPoseAsync(nint address, string pose)
|
|
{
|
|
if (!APIAvailable) return false;
|
|
var gameObject = await _dalamudUtilService.CreateGameObjectAsync(address).ConfigureAwait(false);
|
|
if (gameObject == null) return false;
|
|
_logger.LogDebug("Setting Pose to Actor {actor}", gameObject.Name.TextValue);
|
|
|
|
var applicablePose = JsonNode.Parse(pose)!;
|
|
var currentPose = await _dalamudUtilService.RunOnFrameworkThread(() => _getPoseAsJson.Invoke(gameObject)).ConfigureAwait(false);
|
|
applicablePose["ModelDifference"] = JsonNode.Parse(JsonNode.Parse(currentPose)!["ModelDifference"]!.ToJsonString());
|
|
|
|
await _dalamudUtilService.RunOnFrameworkThread(() =>
|
|
{
|
|
_freezeActor.Invoke(gameObject);
|
|
_freezePhysics.Invoke();
|
|
}).ConfigureAwait(false);
|
|
return await _dalamudUtilService.RunOnFrameworkThread(() => _setPoseFromJson.Invoke(gameObject, applicablePose.ToJsonString(), false)).ConfigureAwait(false);
|
|
}
|
|
|
|
protected override IpcConnectionState EvaluateState()
|
|
{
|
|
var state = base.EvaluateState();
|
|
if (state != IpcConnectionState.Available)
|
|
{
|
|
return state;
|
|
}
|
|
|
|
try
|
|
{
|
|
var version = _apiVersion.Invoke();
|
|
return version.Breaking == 3 && version.Feature >= 0
|
|
? IpcConnectionState.Available
|
|
: IpcConnectionState.VersionMismatch;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogDebug(ex, "Failed to query Brio IPC version");
|
|
return IpcConnectionState.Error;
|
|
}
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|