Code commit

This commit is contained in:
RisaDev
2024-01-06 01:21:41 +03:00
parent a7d7297c59
commit a486dd2c96
90 changed files with 11576 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
namespace CustomizePlus.Game.Services;
public class ChatService
{
private readonly IChatGui _chatGui;
public ChatService(IChatGui chatGui)
{
_chatGui = chatGui;
}
public void PrintInChat(string message, ChatMessageColor color = ChatMessageColor.Info)
{
var stringBuilder = new SeStringBuilder();
stringBuilder.AddUiForeground((ushort)color);
stringBuilder.AddText($"[Customize+] {message}");
stringBuilder.AddUiForegroundOff();
_chatGui.Print(stringBuilder.BuiltString);
}
public void PrintInChat(SeString seString)
{
_chatGui.Print(seString);
}
public enum ChatMessageColor : ushort
{
Info = 45,
Warning = 500,
Error = 14
}
}

View File

@@ -0,0 +1,36 @@
using Dalamud.Game;
namespace CustomizePlus.Game.Services.GPose.ExternalTools;
/// <summary>
/// Service which detects if Anamnesis/Ktisis posing mode is enabled.
/// </summary>
public class PosingModeDetectService
{
// Borrowed from Ktisis:
// If this is NOP'd, Anam posing is enabled.
internal static unsafe byte* AnamnesisFreezePosition;
internal static unsafe byte* AnamnesisFreezeRotation;
internal static unsafe byte* AnamnesisFreezeScale;
internal static unsafe bool IsAnamnesisPositionFrozen =>
AnamnesisFreezePosition != null && *AnamnesisFreezePosition == 0x90 || *AnamnesisFreezePosition == 0x00;
internal static unsafe bool IsAnamnesisRotationFrozen =>
AnamnesisFreezeRotation != null && *AnamnesisFreezeRotation == 0x90 || *AnamnesisFreezeRotation == 0x00;
internal static unsafe bool IsAnamnesisScalingFrozen =>
AnamnesisFreezeScale != null && *AnamnesisFreezeScale == 0x90 || *AnamnesisFreezeScale == 0x00;
internal static bool IsAnamnesis =>
IsAnamnesisPositionFrozen || IsAnamnesisRotationFrozen || IsAnamnesisScalingFrozen;
public bool IsInPosingMode => IsAnamnesis; //Can't detect Ktisis for now
public unsafe PosingModeDetectService(ISigScanner sigScanner)
{
AnamnesisFreezePosition = (byte*)sigScanner.ScanText("41 0F 29 24 12");
AnamnesisFreezeRotation = (byte*)sigScanner.ScanText("41 0F 29 5C 12 10");
AnamnesisFreezeScale = (byte*)sigScanner.ScanText("41 0F 29 44 12 20");
}
}

View File

@@ -0,0 +1,138 @@
using System;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.System.Framework;
using OtterGui.Log;
using CustomizePlus.Game.Events;
namespace CustomizePlus.Game.Services.GPose;
public class GPoseService : IDisposable
{
private readonly ChatService _chatService;
private readonly GPoseStateChanged _event;
private readonly Logger _logger;
private Hook<EnterGPoseDelegate>? _enterGPoseHook;
private Hook<ExitGPoseDelegate>? _exitGPoseHook;
private bool _fakeGPose;
public GPoseState GPoseState { get; private set; }
public bool IsInGPose => GPoseState == GPoseState.Inside;
public bool FakeGPose
{
get => _fakeGPose;
set
{
if (value != _fakeGPose)
{
if (!value)
{
_fakeGPose = false;
HandleGPoseChange(GPoseState.Exiting);
HandleGPoseChange(GPoseState.Outside);
}
else
{
HandleGPoseChange(GPoseState.Inside);
_fakeGPose = true;
}
}
}
}
public unsafe GPoseService(
IClientState clientState,
IGameInteropProvider hooker,
ChatService chatService,
GPoseStateChanged @event,
Logger logger)
{
_chatService = chatService;
_event = @event;
_logger = logger;
GPoseState = clientState.IsGPosing ? GPoseState.Inside : GPoseState.Outside;
var uiModule = Framework.Instance()->GetUiModule();
var enterGPoseAddress = (nint)uiModule->VTable->EnterGPose;
var exitGPoseAddress = (nint)uiModule->VTable->ExitGPose;
_enterGPoseHook = hooker.HookFromAddress<EnterGPoseDelegate>(enterGPoseAddress, EnteringGPoseDetour);
_enterGPoseHook.Enable();
_exitGPoseHook = hooker.HookFromAddress<ExitGPoseDelegate>(exitGPoseAddress, ExitingGPoseDetour);
_exitGPoseHook.Enable();
}
private void ExitingGPoseDetour(nint addr)
{
if (HandleGPoseChange(GPoseState.AttemptExit))
{
HandleGPoseChange(GPoseState.Exiting);
_exitGPoseHook!.Original.Invoke(addr);
HandleGPoseChange(GPoseState.Outside);
}
}
private bool EnteringGPoseDetour(nint addr)
{
var didEnter = _enterGPoseHook!.Original.Invoke(addr);
if (didEnter)
{
_fakeGPose = false;
HandleGPoseChange(GPoseState.Inside);
}
return didEnter;
}
private bool HandleGPoseChange(GPoseState state)
{
if (state == GPoseState || _fakeGPose)
{
return true;
}
GPoseState = state;
switch (state)
{
case GPoseState.Inside:
_event.Invoke(GPoseStateChanged.Type.Entered);
break;
case GPoseState.AttemptExit:
_event.Invoke(GPoseStateChanged.Type.AttemptingExit);
break;
case GPoseState.Exiting:
_event.Invoke(GPoseStateChanged.Type.Exiting);
break;
case GPoseState.Outside:
_event.Invoke(GPoseStateChanged.Type.Exited);
break;
}
return true;
}
public void Dispose()
{
_exitGPoseHook?.Dispose();
_enterGPoseHook?.Dispose();
}
private delegate void ExitGPoseDelegate(nint addr);
private delegate bool EnterGPoseDelegate(nint addr);
}
public enum GPoseState
{
Inside,
AttemptExit,
Exiting,
Outside
}

View File

@@ -0,0 +1,71 @@
using Dalamud.Plugin.Services;
using Penumbra.GameData.Actors;
using System.Collections.Generic;
using CustomizePlus.Core.Data;
using CustomizePlus.GameData.Data;
using CustomizePlus.GameData.Services;
using CustomizePlus.GameData.Extensions;
namespace CustomizePlus.Game.Services;
public class GameObjectService
{
private readonly ActorService _actorService;
private readonly IObjectTable _objectTable;
private readonly ObjectManager _objectManager;
public GameObjectService(ActorService actorService, IObjectTable objectTable, ObjectManager objectManager)
{
_actorService = actorService;
_objectTable = objectTable;
_objectManager = objectManager;
}
public string GetCurrentPlayerName()
{
return _objectManager.PlayerData.Identifier.ToName();
}
public string GetCurrentPlayerTargetName()
{
return _objectManager.TargetData.Identifier.ToNameWithoutOwnerName();
}
public bool IsActorHasScalableRoot(Actor actor)
{
if (!actor.Identifier(_actorService.AwaitedService, out var identifier))
return false;
return !Constants.IsInObjectTableBusyNPCRange(actor.Index.Index)
&& (identifier.IsAllowedForProfiles()
|| actor == _objectTable.GetObjectAddress(0));
}
/// <summary>
/// Case sensitive
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IEnumerable<(ActorIdentifier, Actor)> FindActorsByName(string name)
{
foreach (var kvPair in _objectManager)
{
var identifier = kvPair.Key;
if (kvPair.Key.Type == IdentifierType.Special)
identifier = identifier.GetTrueActorForSpecialType();
if (!identifier.IsValid)
continue;
if (identifier.ToNameWithoutOwnerName() == name)
{
if (kvPair.Value.Objects.Count > 1) //in gpose we can have more than a single object for one actor
foreach (var obj in kvPair.Value.Objects)
yield return (kvPair.Key, obj);
else
yield return (kvPair.Key, kvPair.Value.Objects[0]);
}
}
}
}

View File

@@ -0,0 +1,21 @@
using CustomizePlus.Game.Services.GPose;
using CustomizePlus.Game.Services.GPose.ExternalTools;
namespace CustomizePlus.Game.Services;
public class GameStateService
{
private readonly GPoseService _gposeService;
private readonly PosingModeDetectService _posingModeDetectService;
public GameStateService(GPoseService gposeService, PosingModeDetectService posingModeDetectService)
{
_gposeService = gposeService;
_posingModeDetectService = posingModeDetectService;
}
public bool GameInPosingMode()
{
return _gposeService.GPoseState == GPoseState.Inside || _posingModeDetectService.IsInPosingMode;
}
}