Updated to latest Penumbra.GameData, updated ObjectManager
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using PenumbraExtensions = Penumbra.GameData.Actors.ActorIdentifierExtensions;
|
||||||
|
|
||||||
namespace CustomizePlus.GameData.Extensions;
|
namespace CustomizePlus.GameData.Extensions;
|
||||||
|
|
||||||
@@ -19,10 +21,10 @@ public static class ActorIdentifierExtensions
|
|||||||
if (identifier.Type != IdentifierType.Owned)
|
if (identifier.Type != IdentifierType.Owned)
|
||||||
return identifier.ToName();
|
return identifier.ToName();
|
||||||
|
|
||||||
if (ActorIdentifier.Manager == null)
|
if (PenumbraExtensions.Manager == null)
|
||||||
throw new Exception("ActorIdentifier.Manager is not initialized");
|
throw new Exception("ActorIdentifier.Manager is not initialized");
|
||||||
|
|
||||||
return ActorIdentifier.Manager.Data.ToName(identifier.Kind, identifier.DataId);
|
return PenumbraExtensions.Manager.Data.ToName(identifier.Kind, identifier.DataId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -93,7 +95,7 @@ public static class ActorIdentifierExtensions
|
|||||||
if (identifier.Type != IdentifierType.Special)
|
if (identifier.Type != IdentifierType.Special)
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
|
|
||||||
if (ActorIdentifier.Manager == null)
|
if (PenumbraExtensions.Manager == null)
|
||||||
throw new Exception("ActorIdentifier.Manager is not initialized");
|
throw new Exception("ActorIdentifier.Manager is not initialized");
|
||||||
|
|
||||||
switch (identifier.Special)
|
switch (identifier.Special)
|
||||||
@@ -103,12 +105,12 @@ public static class ActorIdentifierExtensions
|
|||||||
case ScreenActor.FittingRoom:
|
case ScreenActor.FittingRoom:
|
||||||
case ScreenActor.DyePreview:
|
case ScreenActor.DyePreview:
|
||||||
case ScreenActor.Portrait:
|
case ScreenActor.Portrait:
|
||||||
return ActorIdentifier.Manager.GetCurrentPlayer();
|
return PenumbraExtensions.Manager.GetCurrentPlayer();
|
||||||
case ScreenActor.ExamineScreen:
|
case ScreenActor.ExamineScreen:
|
||||||
var examineIdentifier = ActorIdentifier.Manager.GetInspectPlayer();
|
var examineIdentifier = PenumbraExtensions.Manager.GetInspectPlayer();
|
||||||
|
|
||||||
if (!examineIdentifier.IsValid)
|
if (!examineIdentifier.IsValid)
|
||||||
examineIdentifier = ActorIdentifier.Manager.GetGlamourPlayer(); //returns ActorIdentifier.Invalid if player is invalid
|
examineIdentifier = PenumbraExtensions.Manager.GetGlamourPlayer(); //returns ActorIdentifier.Invalid if player is invalid
|
||||||
|
|
||||||
if (!examineIdentifier.IsValid)
|
if (!examineIdentifier.IsValid)
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
@@ -117,7 +119,7 @@ public static class ActorIdentifierExtensions
|
|||||||
case ScreenActor.Card6:
|
case ScreenActor.Card6:
|
||||||
case ScreenActor.Card7:
|
case ScreenActor.Card7:
|
||||||
case ScreenActor.Card8:
|
case ScreenActor.Card8:
|
||||||
return ActorIdentifier.Manager.GetCardPlayer();
|
return PenumbraExtensions.Manager.GetCardPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
|
|||||||
48
CustomizePlus.GameData/Hooks/Objects/CharacterDestructor.cs
Normal file
48
CustomizePlus.GameData/Hooks/Objects/CharacterDestructor.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Dalamud.Hooking;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using Penumbra.GameData;
|
||||||
|
|
||||||
|
namespace CustomizePlus.GameData.Hooks.Objects;
|
||||||
|
public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, CharacterDestructor.Priority>, IHookService
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
/// <seealso cref="PathResolving.CutsceneService"/>
|
||||||
|
CutsceneService = 0,
|
||||||
|
|
||||||
|
/// <seealso cref="PathResolving.IdentifiedCollectionCache"/>
|
||||||
|
IdentifiedCollectionCache = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterDestructor(HookManager hooks)
|
||||||
|
: base("Character Destructor")
|
||||||
|
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, true);
|
||||||
|
|
||||||
|
private readonly Task<Hook<Delegate>> _task;
|
||||||
|
|
||||||
|
public nint Address
|
||||||
|
=> _task.Result.Address;
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
=> _task.Result.Enable();
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
=> _task.Result.Disable();
|
||||||
|
|
||||||
|
public Task Awaiter
|
||||||
|
=> _task;
|
||||||
|
|
||||||
|
public bool Finished
|
||||||
|
=> _task.IsCompletedSuccessfully;
|
||||||
|
|
||||||
|
private delegate void Delegate(Character* character);
|
||||||
|
|
||||||
|
private void Detour(Character* character)
|
||||||
|
{
|
||||||
|
//Penumbra.Log.Verbose($"[{Name}] Triggered with 0x{(nint)character:X}.");
|
||||||
|
Invoke(character);
|
||||||
|
_task.Result.Original(character);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
CustomizePlus.GameData/Hooks/Objects/CopyCharacter.cs
Normal file
46
CustomizePlus.GameData/Hooks/Objects/CopyCharacter.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Dalamud.Hooking;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Services;
|
||||||
|
|
||||||
|
namespace CustomizePlus.GameData.Hooks.Objects;
|
||||||
|
public sealed unsafe class CopyCharacter : EventWrapperPtr<Character, Character, CopyCharacter.Priority>, IHookService
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
/// <seealso cref="PathResolving.CutsceneService"/>
|
||||||
|
CutsceneService = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public CopyCharacter(HookManager hooks)
|
||||||
|
: base("Copy Character")
|
||||||
|
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, true);
|
||||||
|
|
||||||
|
private readonly Task<Hook<Delegate>> _task;
|
||||||
|
|
||||||
|
public nint Address
|
||||||
|
=> (nint)CharacterSetup.MemberFunctionPointers.CopyFromCharacter;
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
=> _task.Result.Enable();
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
=> _task.Result.Disable();
|
||||||
|
|
||||||
|
public Task Awaiter
|
||||||
|
=> _task;
|
||||||
|
|
||||||
|
public bool Finished
|
||||||
|
=> _task.IsCompletedSuccessfully;
|
||||||
|
|
||||||
|
private delegate ulong Delegate(CharacterSetup* target, Character* source, uint unk);
|
||||||
|
|
||||||
|
private ulong Detour(CharacterSetup* target, Character* source, uint unk)
|
||||||
|
{
|
||||||
|
// TODO: update when CS updated.
|
||||||
|
var character = ((Character**)target)[1];
|
||||||
|
//Penumbra.Log.Verbose($"[{Name}] Triggered with target: 0x{(nint)target:X}, source : 0x{(nint)source:X} unk: {unk}.");
|
||||||
|
Invoke(character, source);
|
||||||
|
return _task.Result.Original(target, source, unk);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
using Dalamud.Plugin.Services;
|
using CustomizePlus.GameData.Hooks.Objects;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using Penumbra.GameData.Actors;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using System;
|
using OtterGui.Services;
|
||||||
using System.Collections.Generic;
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.String;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CustomizePlus.GameData.Services;
|
namespace CustomizePlus.GameData.Services;
|
||||||
|
|
||||||
public class CutsceneService : IDisposable
|
public class CutsceneService : IService, IDisposable
|
||||||
{
|
{
|
||||||
public const int CutsceneStartIdx = (int)ScreenActor.CutsceneStart;
|
public const int CutsceneStartIdx = (int)ScreenActor.CutsceneStart;
|
||||||
public const int CutsceneEndIdx = (int)ScreenActor.CutsceneEnd;
|
public const int CutsceneEndIdx = (int)ScreenActor.CutsceneEnd;
|
||||||
public const int CutsceneSlots = CutsceneEndIdx - CutsceneStartIdx;
|
public const int CutsceneSlots = CutsceneEndIdx - CutsceneStartIdx;
|
||||||
|
|
||||||
private readonly GameEventManager _events;
|
|
||||||
private readonly IObjectTable _objects;
|
private readonly IObjectTable _objects;
|
||||||
|
private readonly CopyCharacter _copyCharacter;
|
||||||
|
private readonly CharacterDestructor _characterDestructor;
|
||||||
private readonly short[] _copiedCharacters = Enumerable.Repeat((short)-1, CutsceneSlots).ToArray();
|
private readonly short[] _copiedCharacters = Enumerable.Repeat((short)-1, CutsceneSlots).ToArray();
|
||||||
|
|
||||||
public IEnumerable<KeyValuePair<int, Dalamud.Game.ClientState.Objects.Types.GameObject>> Actors
|
public IEnumerable<KeyValuePair<int, Dalamud.Game.ClientState.Objects.Types.GameObject>> Actors
|
||||||
@@ -25,14 +25,19 @@ public class CutsceneService : IDisposable
|
|||||||
.Where(i => _objects[i] != null)
|
.Where(i => _objects[i] != null)
|
||||||
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!));
|
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!));
|
||||||
|
|
||||||
public unsafe CutsceneService(IObjectTable objects, GameEventManager events)
|
public unsafe CutsceneService(IObjectTable objects, CopyCharacter copyCharacter, CharacterDestructor characterDestructor,
|
||||||
|
IClientState clientState)
|
||||||
{
|
{
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
_events = events;
|
_copyCharacter = copyCharacter;
|
||||||
_events.CopyCharacter += OnCharacterCopy;
|
_characterDestructor = characterDestructor;
|
||||||
_events.CharacterDestructor += OnCharacterDestructor;
|
_copyCharacter.Subscribe(OnCharacterCopy, CopyCharacter.Priority.CutsceneService);
|
||||||
|
_characterDestructor.Subscribe(OnCharacterDestructor, CharacterDestructor.Priority.CutsceneService);
|
||||||
|
if (clientState.IsGPosing)
|
||||||
|
RecoverGPoseActors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the related actor to a cutscene actor.
|
/// Get the related actor to a cutscene actor.
|
||||||
/// Does not check for valid input index.
|
/// Does not check for valid input index.
|
||||||
@@ -50,6 +55,27 @@ public class CutsceneService : IDisposable
|
|||||||
|
|
||||||
/// <summary> Return the currently set index of a parent or -1 if none is set or the index is invalid. </summary>
|
/// <summary> Return the currently set index of a parent or -1 if none is set or the index is invalid. </summary>
|
||||||
public int GetParentIndex(int idx)
|
public int GetParentIndex(int idx)
|
||||||
|
=> GetParentIndex((ushort)idx);
|
||||||
|
|
||||||
|
public bool SetParentIndex(int copyIdx, int parentIdx)
|
||||||
|
{
|
||||||
|
if (copyIdx is < CutsceneStartIdx or >= CutsceneEndIdx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (parentIdx is < -1 or >= CutsceneEndIdx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_objects.GetObjectAddress(copyIdx) == nint.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (parentIdx != -1 && _objects.GetObjectAddress(parentIdx) == nint.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short GetParentIndex(ushort idx)
|
||||||
{
|
{
|
||||||
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
|
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
|
||||||
return _copiedCharacters[idx - CutsceneStartIdx];
|
return _copiedCharacters[idx - CutsceneStartIdx];
|
||||||
@@ -59,18 +85,35 @@ public class CutsceneService : IDisposable
|
|||||||
|
|
||||||
public unsafe void Dispose()
|
public unsafe void Dispose()
|
||||||
{
|
{
|
||||||
_events.CopyCharacter -= OnCharacterCopy;
|
_copyCharacter.Unsubscribe(OnCharacterCopy);
|
||||||
_events.CharacterDestructor -= OnCharacterDestructor;
|
_characterDestructor.Unsubscribe(OnCharacterDestructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void OnCharacterDestructor(Character* character)
|
private unsafe void OnCharacterDestructor(Character* character)
|
||||||
{
|
{
|
||||||
if (character->GameObject.ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
|
if (character->GameObject.ObjectIndex < CutsceneStartIdx)
|
||||||
return;
|
{
|
||||||
|
// Remove all associations for now non-existing actor.
|
||||||
|
for (var i = 0; i < _copiedCharacters.Length; ++i)
|
||||||
|
{
|
||||||
|
if (_copiedCharacters[i] == character->GameObject.ObjectIndex)
|
||||||
|
{
|
||||||
|
// A hack to deal with GPose actors leaving and thus losing the link, we just set the home world instead.
|
||||||
|
// I do not think this breaks anything?
|
||||||
|
var address = (GameObject*)_objects.GetObjectAddress(i + CutsceneStartIdx);
|
||||||
|
if (address != null && address->GetObjectKind() is (byte)ObjectKind.Pc)
|
||||||
|
((Character*)address)->HomeWorld = character->HomeWorld;
|
||||||
|
|
||||||
|
_copiedCharacters[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (character->GameObject.ObjectIndex < CutsceneEndIdx)
|
||||||
|
{
|
||||||
var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
|
var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||||
_copiedCharacters[idx] = -1;
|
_copiedCharacters[idx] = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe void OnCharacterCopy(Character* target, Character* source)
|
private unsafe void OnCharacterCopy(Character* target, Character* source)
|
||||||
{
|
{
|
||||||
@@ -80,4 +123,45 @@ public class CutsceneService : IDisposable
|
|||||||
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
|
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||||
_copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1);
|
_copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Try to recover GPose actors on reloads into a running game. </summary>
|
||||||
|
/// <remarks> This is not 100% accurate due to world IDs, minions etc., but will be mostly sane. </remarks>
|
||||||
|
private unsafe void RecoverGPoseActors()
|
||||||
|
{
|
||||||
|
Dictionary<ByteString, short>? actors = null;
|
||||||
|
|
||||||
|
for (var i = CutsceneStartIdx; i < CutsceneEndIdx; ++i)
|
||||||
|
{
|
||||||
|
if (!TryGetName(i, out var name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((actors ??= CreateActors()).TryGetValue(name, out var idx))
|
||||||
|
_copiedCharacters[i - CutsceneStartIdx] = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool TryGetName(int idx, out ByteString name)
|
||||||
|
{
|
||||||
|
name = ByteString.Empty;
|
||||||
|
var address = (GameObject*)_objects.GetObjectAddress(idx);
|
||||||
|
if (address == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
name = new ByteString(address->Name);
|
||||||
|
return !name.IsEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<ByteString, short> CreateActors()
|
||||||
|
{
|
||||||
|
var ret = new Dictionary<ByteString, short>();
|
||||||
|
for (short i = 0; i < CutsceneStartIdx; ++i)
|
||||||
|
{
|
||||||
|
if (TryGetName(i, out var name))
|
||||||
|
ret.TryAdd(name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Dalamud.Plugin.Services;
|
|||||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -18,18 +19,18 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
private readonly IFramework _framework;
|
private readonly IFramework _framework;
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly IObjectTable _objects;
|
private readonly IObjectTable _objects;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorManager _actorManager;
|
||||||
private readonly ITargetManager _targets;
|
private readonly ITargetManager _targets;
|
||||||
|
|
||||||
public IObjectTable Objects
|
public IObjectTable Objects
|
||||||
=> _objects;
|
=> _objects;
|
||||||
|
|
||||||
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorService actors, ITargetManager targets)
|
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorManager actorManager, ITargetManager targets)
|
||||||
{
|
{
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
_actors = actors;
|
_actorManager = actorManager;
|
||||||
_targets = targets;
|
_targets = targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,23 +61,26 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
if (character.Identifier(_actorManager, out var identifier))
|
||||||
HandleIdentifier(identifier, character);
|
HandleIdentifier(identifier, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i)
|
for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (!character.Valid)
|
// Technically the game does not create holes in cutscenes or GPose.
|
||||||
|
// But for Brio compatibility, we allow holes in GPose.
|
||||||
|
// Since GPose always has the event actor in the first cutscene slot, we can still optimize in this case.
|
||||||
|
if (!character.Valid && i == (int)ScreenActor.CutsceneStart)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
HandleIdentifier(character.GetIdentifier(_actors.AwaitedService), character);
|
HandleIdentifier(character.GetIdentifier(_actorManager), character);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSpecial(ScreenActor idx, string label)
|
void AddSpecial(ScreenActor idx, string label)
|
||||||
{
|
{
|
||||||
Actor actor = _objects.GetObjectAddress((int)idx);
|
Actor actor = _objects.GetObjectAddress((int)idx);
|
||||||
if (actor.Identifier(_actors.AwaitedService, out var ident))
|
if (actor.Identifier(_actorManager, out var ident))
|
||||||
{
|
{
|
||||||
var data = new ActorData(actor, label);
|
var data = new ActorData(actor, label);
|
||||||
_identifiers.Add(ident, data);
|
_identifiers.Add(ident, data);
|
||||||
@@ -95,7 +99,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
for (var i = (int)ScreenActor.ScreenEnd; i < _objects.Length; ++i)
|
for (var i = (int)ScreenActor.ScreenEnd; i < _objects.Length; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
if (character.Identifier(_actorManager, out var identifier))
|
||||||
HandleIdentifier(identifier, character);
|
HandleIdentifier(identifier, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +124,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
|
|
||||||
if (identifier.Type is IdentifierType.Player or IdentifierType.Owned)
|
if (identifier.Type is IdentifierType.Player or IdentifierType.Owned)
|
||||||
{
|
{
|
||||||
var allWorld = _actors.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
var allWorld = _actorManager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||||
identifier.Kind,
|
identifier.Kind,
|
||||||
identifier.DataId);
|
identifier.DataId);
|
||||||
|
|
||||||
@@ -137,7 +141,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
|
|
||||||
if (identifier.Type is IdentifierType.Owned)
|
if (identifier.Type is IdentifierType.Owned)
|
||||||
{
|
{
|
||||||
var nonOwned = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId);
|
var nonOwned = _actorManager.CreateNpc(identifier.Kind, identifier.DataId);
|
||||||
if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var nonOwnedData))
|
if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var nonOwnedData))
|
||||||
{
|
{
|
||||||
nonOwnedData = new ActorData(character, nonOwned.ToString());
|
nonOwnedData = new ActorData(character, nonOwned.ToString());
|
||||||
@@ -170,7 +174,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
return Player.Identifier(_actors.AwaitedService, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
return Player.Identifier(_actorManager, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||||
? (ident, data)
|
? (ident, data)
|
||||||
: (ident, ActorData.Invalid);
|
: (ident, ActorData.Invalid);
|
||||||
}
|
}
|
||||||
@@ -181,7 +185,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
return Target.Identifier(_actors.AwaitedService, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
return Target.Identifier(_actorManager, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||||
? (ident, data)
|
? (ident, data)
|
||||||
: (ident, ActorData.Invalid);
|
: (ident, ActorData.Invalid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
using Penumbra.GameData;
|
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CustomizePlus.GameData.Services;
|
|
||||||
|
|
||||||
public abstract class AsyncServiceWrapper<T> : IDisposable
|
|
||||||
{
|
|
||||||
public string Name { get; }
|
|
||||||
public T? Service { get; private set; }
|
|
||||||
|
|
||||||
public T AwaitedService
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_task?.Wait();
|
|
||||||
return Service!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Valid
|
|
||||||
=> Service != null && !_isDisposed;
|
|
||||||
|
|
||||||
public event Action? FinishedCreation;
|
|
||||||
private Task? _task;
|
|
||||||
|
|
||||||
private bool _isDisposed;
|
|
||||||
|
|
||||||
protected AsyncServiceWrapper(string name, Func<T> factory)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
_task = Task.Run(() =>
|
|
||||||
{
|
|
||||||
var service = factory();
|
|
||||||
if (_isDisposed)
|
|
||||||
{
|
|
||||||
if (service is IDisposable d)
|
|
||||||
d.Dispose();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Service = service;
|
|
||||||
_task = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_task.ContinueWith((t, x) =>
|
|
||||||
{
|
|
||||||
if (!_isDisposed)
|
|
||||||
FinishedCreation?.Invoke();
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_isDisposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
_task = null;
|
|
||||||
if (Service is IDisposable d)
|
|
||||||
d.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
|
|
||||||
{
|
|
||||||
public ActorService(DalamudPluginInterface pi, IObjectTable objects, IClientState clientState, IFramework framework, IGameInteropProvider interop, IDataManager gameData,
|
|
||||||
IGameGui gui, CutsceneService cutsceneService, IPluginLog log)
|
|
||||||
: base(nameof(ActorService),
|
|
||||||
() => new ActorManager(pi, objects, clientState, framework, interop, gameData, gui, idx => (short)cutsceneService.GetParentIndex(idx), log))
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
@@ -20,6 +20,7 @@ using CustomizePlus.GameData.Services;
|
|||||||
using CustomizePlus.GameData.Extensions;
|
using CustomizePlus.GameData.Extensions;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace CustomizePlus.Armatures.Services;
|
namespace CustomizePlus.Armatures.Services;
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
private readonly FrameworkManager _framework;
|
private readonly FrameworkManager _framework;
|
||||||
private readonly ObjectManager _objectManager;
|
private readonly ObjectManager _objectManager;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actorManager;
|
||||||
private readonly ArmatureChanged _event;
|
private readonly ArmatureChanged _event;
|
||||||
|
|
||||||
public Dictionary<ActorIdentifier, Armature> Armatures { get; private set; } = new();
|
public Dictionary<ActorIdentifier, Armature> Armatures { get; private set; } = new();
|
||||||
@@ -47,7 +48,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
Logger logger,
|
Logger logger,
|
||||||
FrameworkManager framework,
|
FrameworkManager framework,
|
||||||
ObjectManager objectManager,
|
ObjectManager objectManager,
|
||||||
ActorService actorService,
|
ActorManager actorManager,
|
||||||
ArmatureChanged @event)
|
ArmatureChanged @event)
|
||||||
{
|
{
|
||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
@@ -58,7 +59,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_objectManager = objectManager;
|
_objectManager = objectManager;
|
||||||
_actorService = actorService;
|
_actorManager = actorManager;
|
||||||
_event = @event;
|
_event = @event;
|
||||||
|
|
||||||
_templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ArmatureManager);
|
_templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ArmatureManager);
|
||||||
@@ -92,7 +93,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnGameObjectMove(Actor actor)
|
public void OnGameObjectMove(Actor actor)
|
||||||
{
|
{
|
||||||
if (!actor.Identifier(_actorService.AwaitedService, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Armatures.TryGetValue(identifier, out var armature) && armature.IsBuilt && armature.IsVisible)
|
if (Armatures.TryGetValue(identifier, out var armature) && armature.IsBuilt && armature.IsVisible)
|
||||||
|
|||||||
@@ -28,16 +28,22 @@ using CustomizePlus.Game.Services.GPose;
|
|||||||
using CustomizePlus.Game.Services.GPose.ExternalTools;
|
using CustomizePlus.Game.Services.GPose.ExternalTools;
|
||||||
using CustomizePlus.GameData.Services;
|
using CustomizePlus.GameData.Services;
|
||||||
using CustomizePlus.Configuration.Services.Temporary;
|
using CustomizePlus.Configuration.Services.Temporary;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
using OtterGui;
|
||||||
|
|
||||||
namespace CustomizePlus.Core;
|
namespace CustomizePlus.Core;
|
||||||
|
|
||||||
public static class ServiceManager
|
public static class ServiceManagerBuilder
|
||||||
{
|
{
|
||||||
public static ServiceProvider CreateProvider(DalamudPluginInterface pi, Logger logger)
|
public static ServiceManager CreateProvider(DalamudPluginInterface pi, Logger logger)
|
||||||
{
|
{
|
||||||
var services = new ServiceCollection()
|
EventWrapperBase.ChangeLogger(logger);
|
||||||
.AddSingleton(logger)
|
|
||||||
.AddDalamud(pi)
|
var services = new ServiceManager(logger)
|
||||||
|
.AddExistingService(logger)
|
||||||
.AddCore()
|
.AddCore()
|
||||||
.AddEvents()
|
.AddEvents()
|
||||||
.AddGPoseServices()
|
.AddGPoseServices()
|
||||||
@@ -49,16 +55,20 @@ public static class ServiceManager
|
|||||||
.AddGameServices()
|
.AddGameServices()
|
||||||
.AddConfigServices()
|
.AddConfigServices()
|
||||||
.AddRestOfServices();
|
.AddRestOfServices();
|
||||||
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IServiceCollection AddDalamud(this IServiceCollection services, DalamudPluginInterface pluginInterface)
|
DalamudServices.AddServices(services, pi);
|
||||||
{
|
|
||||||
new DalamudServices(pluginInterface).AddServices(services);
|
services.AddIServices(typeof(EquipItem).Assembly);
|
||||||
|
services.AddIServices(typeof(Plugin).Assembly);
|
||||||
|
services.AddIServices(typeof(ObjectManager).Assembly);
|
||||||
|
services.AddIServices(typeof(ImGuiUtil).Assembly);
|
||||||
|
|
||||||
|
services.CreateProvider();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddGPoseServices(this IServiceCollection services)
|
private static ServiceManager AddGPoseServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<PosingModeDetectService>()
|
.AddSingleton<PosingModeDetectService>()
|
||||||
@@ -67,14 +77,14 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddArmatureServices(this IServiceCollection services)
|
private static ServiceManager AddArmatureServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<ArmatureManager>();
|
.AddSingleton<ArmatureManager>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddUI(this IServiceCollection services)
|
private static ServiceManager AddUI(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<TemplateCombo>()
|
.AddSingleton<TemplateCombo>()
|
||||||
@@ -107,7 +117,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddEvents(this IServiceCollection services)
|
private static ServiceManager AddEvents(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<ProfileChanged>()
|
.AddSingleton<ProfileChanged>()
|
||||||
@@ -118,7 +128,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddCore(this IServiceCollection services)
|
private static ServiceManager AddCore(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<HookingService>()
|
.AddSingleton<HookingService>()
|
||||||
@@ -133,7 +143,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddRestOfServices(this IServiceCollection services) //temp
|
private static ServiceManager AddRestOfServices(this ServiceManager services) //temp
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<PoseFileBoneLoader>()
|
.AddSingleton<PoseFileBoneLoader>()
|
||||||
@@ -142,7 +152,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddConfigServices(this IServiceCollection services)
|
private static ServiceManager AddConfigServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<PluginConfiguration>()
|
.AddSingleton<PluginConfiguration>()
|
||||||
@@ -153,7 +163,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddGameServices(this IServiceCollection services)
|
private static ServiceManager AddGameServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<GameObjectService>()
|
.AddSingleton<GameObjectService>()
|
||||||
@@ -162,7 +172,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddProfileServices(this IServiceCollection services)
|
private static ServiceManager AddProfileServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<ProfileManager>()
|
.AddSingleton<ProfileManager>()
|
||||||
@@ -172,7 +182,7 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddTemplateServices(this IServiceCollection services)
|
private static ServiceManager AddTemplateServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
.AddSingleton<TemplateManager>()
|
.AddSingleton<TemplateManager>()
|
||||||
@@ -182,12 +192,13 @@ public static class ServiceManager
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddGameDataServices(this IServiceCollection services)
|
private static ServiceManager AddGameDataServices(this ServiceManager services)
|
||||||
{
|
{
|
||||||
services
|
services
|
||||||
|
.AddSingleton<ActorManager>()
|
||||||
.AddSingleton<CutsceneService>()
|
.AddSingleton<CutsceneService>()
|
||||||
.AddSingleton<GameEventManager>()
|
.AddSingleton<GameEventManager>()
|
||||||
.AddSingleton<ActorService>()
|
.AddSingleton(p => new CutsceneResolver(idx => (short)p.GetRequiredService<CutsceneService>().GetParentIndex(idx)))
|
||||||
.AddSingleton<ObjectManager>();
|
.AddSingleton<ObjectManager>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
@@ -4,90 +4,27 @@ using Dalamud.IoC;
|
|||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using OtterGui.Services;
|
||||||
|
|
||||||
namespace CustomizePlus.Core.Services;
|
namespace CustomizePlus.Core.Services;
|
||||||
|
|
||||||
public class DalamudServices
|
public class DalamudServices
|
||||||
{
|
{
|
||||||
[PluginService]
|
public static void AddServices(ServiceManager services, DalamudPluginInterface pi)
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public ISigScanner SigScanner { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
public IFramework Framework { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IObjectTable ObjectTable { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public ICommandManager CommandManager { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IChatGui ChatGui { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IClientState ClientState { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IGameGui GameGui { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
internal IGameInteropProvider Hooker { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IKeyState KeyState { get; private set; } = null!;
|
|
||||||
|
|
||||||
//GameData
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IDataManager DataManager { get; private set; } = null!;
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public IPluginLog PluginLog { get; private set; } = null!;
|
|
||||||
|
|
||||||
/*[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public ICondition Condition { get; private set; } = null!;*/
|
|
||||||
|
|
||||||
[PluginService]
|
|
||||||
[RequiredVersion("1.0")]
|
|
||||||
public ITargetManager TargetManager { get; private set; } = null!;
|
|
||||||
|
|
||||||
public DalamudServices(DalamudPluginInterface pluginInterface)
|
|
||||||
{
|
{
|
||||||
pluginInterface.Inject(this);
|
services.AddExistingService(pi)
|
||||||
}
|
.AddExistingService(pi.UiBuilder)
|
||||||
|
.AddDalamudService<ISigScanner>(pi)
|
||||||
public void AddServices(IServiceCollection services)
|
.AddDalamudService<IFramework>(pi)
|
||||||
{
|
.AddDalamudService<IObjectTable>(pi)
|
||||||
services
|
.AddDalamudService<ICommandManager>(pi)
|
||||||
.AddSingleton(PluginInterface)
|
.AddDalamudService<IChatGui>(pi)
|
||||||
.AddSingleton(SigScanner)
|
.AddDalamudService<IClientState>(pi)
|
||||||
.AddSingleton(Framework)
|
.AddDalamudService<IGameGui>(pi)
|
||||||
.AddSingleton(ObjectTable)
|
.AddDalamudService<IGameInteropProvider>(pi)
|
||||||
.AddSingleton(CommandManager)
|
.AddDalamudService<IKeyState>(pi)
|
||||||
.AddSingleton(ChatGui)
|
.AddDalamudService<IDataManager>(pi)
|
||||||
.AddSingleton(ClientState)
|
.AddDalamudService<IPluginLog>(pi)
|
||||||
.AddSingleton(GameGui)
|
.AddDalamudService<ITargetManager>(pi);
|
||||||
.AddSingleton(Hooker)
|
|
||||||
.AddSingleton(KeyState)
|
|
||||||
.AddSingleton(this)
|
|
||||||
.AddSingleton(PluginInterface.UiBuilder)
|
|
||||||
.AddSingleton(DataManager)
|
|
||||||
.AddSingleton(PluginLog)
|
|
||||||
//.AddSingleton(Condition)
|
|
||||||
.AddSingleton(TargetManager);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,10 +140,18 @@ public class HookingService : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var actor = (Actor)gameObjectPtr;
|
var actor = (Actor)gameObjectPtr;
|
||||||
if (actor.Valid)
|
if (actor.Valid)
|
||||||
_armatureManager.OnGameObjectMove((Actor)gameObjectPtr);
|
_armatureManager.OnGameObjectMove((Actor)gameObjectPtr);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error($"Exception in Customize+ movement hook: {ex}");
|
||||||
|
_gameObjectMovementHook?.Disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,18 +5,19 @@ using CustomizePlus.Core.Data;
|
|||||||
using CustomizePlus.GameData.Data;
|
using CustomizePlus.GameData.Data;
|
||||||
using CustomizePlus.GameData.Services;
|
using CustomizePlus.GameData.Services;
|
||||||
using CustomizePlus.GameData.Extensions;
|
using CustomizePlus.GameData.Extensions;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace CustomizePlus.Game.Services;
|
namespace CustomizePlus.Game.Services;
|
||||||
|
|
||||||
public class GameObjectService
|
public class GameObjectService
|
||||||
{
|
{
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actorManager;
|
||||||
private readonly IObjectTable _objectTable;
|
private readonly IObjectTable _objectTable;
|
||||||
private readonly ObjectManager _objectManager;
|
private readonly ObjectManager _objectManager;
|
||||||
|
|
||||||
public GameObjectService(ActorService actorService, IObjectTable objectTable, ObjectManager objectManager)
|
public GameObjectService(ActorManager actorManager, IObjectTable objectTable, ObjectManager objectManager)
|
||||||
{
|
{
|
||||||
_actorService = actorService;
|
_actorManager = actorManager;
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_objectManager = objectManager;
|
_objectManager = objectManager;
|
||||||
}
|
}
|
||||||
@@ -33,7 +34,7 @@ public class GameObjectService
|
|||||||
|
|
||||||
public bool IsActorHasScalableRoot(Actor actor)
|
public bool IsActorHasScalableRoot(Actor actor)
|
||||||
{
|
{
|
||||||
if (!actor.Identifier(_actorService.AwaitedService, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !Constants.IsInObjectTableBusyNPCRange(actor.Index.Index)
|
return !Constants.IsInObjectTableBusyNPCRange(actor.Index.Index)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using CustomizePlus.UI;
|
|||||||
using CustomizePlus.Core;
|
using CustomizePlus.Core;
|
||||||
using CustomizePlus.Api.Compatibility;
|
using CustomizePlus.Api.Compatibility;
|
||||||
using CustomizePlus.Configuration.Services.Temporary;
|
using CustomizePlus.Configuration.Services.Temporary;
|
||||||
|
using OtterGui.Services;
|
||||||
|
|
||||||
namespace CustomizePlus;
|
namespace CustomizePlus;
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private readonly ServiceProvider _services;
|
private readonly ServiceManager _services;
|
||||||
|
|
||||||
public static readonly Logger Logger = new(); //for loggin in static classes/methods
|
public static readonly Logger Logger = new(); //for loggin in static classes/methods
|
||||||
|
|
||||||
@@ -27,18 +28,18 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_services = ServiceManager.CreateProvider(pluginInterface, Logger);
|
_services = ServiceManagerBuilder.CreateProvider(pluginInterface, Logger);
|
||||||
|
|
||||||
//temporary
|
//temporary
|
||||||
var configMover = _services.GetRequiredService<FantasiaPlusConfigMover>();
|
var configMover = _services.GetService<FantasiaPlusConfigMover>();
|
||||||
configMover.MoveConfigsIfNeeded();
|
configMover.MoveConfigsIfNeeded();
|
||||||
|
|
||||||
var v3ConfigFixer = _services.GetRequiredService<Version3ConfigFixer>();
|
var v3ConfigFixer = _services.GetService<Version3ConfigFixer>();
|
||||||
v3ConfigFixer.FixV3ConfigIfNeeded();
|
v3ConfigFixer.FixV3ConfigIfNeeded();
|
||||||
|
|
||||||
_services.GetRequiredService<CustomizePlusIpc>();
|
_services.GetService<CustomizePlusIpc>();
|
||||||
_services.GetRequiredService<CPlusWindowSystem>();
|
_services.GetService<CPlusWindowSystem>();
|
||||||
_services.GetRequiredService<CommandService>();
|
_services.GetService<CommandService>();
|
||||||
|
|
||||||
Logger.Information($"Customize+ v{Version} [FantasiaPlus] started");
|
Logger.Information($"Customize+ v{Version} [FantasiaPlus] started");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using CustomizePlus.GameData.Data;
|
|||||||
using CustomizePlus.GameData.Services;
|
using CustomizePlus.GameData.Services;
|
||||||
using CustomizePlus.GameData.Extensions;
|
using CustomizePlus.GameData.Extensions;
|
||||||
using CustomizePlus.Profiles.Enums;
|
using CustomizePlus.Profiles.Enums;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace CustomizePlus.Profiles;
|
namespace CustomizePlus.Profiles;
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ public class ProfileManager : IDisposable
|
|||||||
private readonly SaveService _saveService;
|
private readonly SaveService _saveService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
private readonly PluginConfiguration _configuration;
|
private readonly PluginConfiguration _configuration;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actorManager;
|
||||||
private readonly ProfileChanged _event;
|
private readonly ProfileChanged _event;
|
||||||
private readonly TemplateChanged _templateChangedEvent;
|
private readonly TemplateChanged _templateChangedEvent;
|
||||||
private readonly ReloadEvent _reloadEvent;
|
private readonly ReloadEvent _reloadEvent;
|
||||||
@@ -51,7 +52,7 @@ public class ProfileManager : IDisposable
|
|||||||
SaveService saveService,
|
SaveService saveService,
|
||||||
Logger logger,
|
Logger logger,
|
||||||
PluginConfiguration configuration,
|
PluginConfiguration configuration,
|
||||||
ActorService actorService,
|
ActorManager actorManager,
|
||||||
ProfileChanged @event,
|
ProfileChanged @event,
|
||||||
TemplateChanged templateChangedEvent,
|
TemplateChanged templateChangedEvent,
|
||||||
ReloadEvent reloadEvent,
|
ReloadEvent reloadEvent,
|
||||||
@@ -62,7 +63,7 @@ public class ProfileManager : IDisposable
|
|||||||
_saveService = saveService;
|
_saveService = saveService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_actorService = actorService;
|
_actorManager = actorManager;
|
||||||
_event = @event;
|
_event = @event;
|
||||||
_templateChangedEvent = templateChangedEvent;
|
_templateChangedEvent = templateChangedEvent;
|
||||||
_templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ProfileManager);
|
_templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ProfileManager);
|
||||||
@@ -375,7 +376,7 @@ public class ProfileManager : IDisposable
|
|||||||
|
|
||||||
public void AddTemporaryProfile(Profile profile, Actor actor/*, Template template*/)
|
public void AddTemporaryProfile(Profile profile, Actor actor/*, Template template*/)
|
||||||
{
|
{
|
||||||
if (!actor.Identifier(_actorService.AwaitedService, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
profile.Enabled = true;
|
profile.Enabled = true;
|
||||||
@@ -413,7 +414,7 @@ public class ProfileManager : IDisposable
|
|||||||
|
|
||||||
public void RemoveTemporaryProfile(Actor actor)
|
public void RemoveTemporaryProfile(Actor actor)
|
||||||
{
|
{
|
||||||
if (!actor.Identifier(_actorService.AwaitedService, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var profile = Profiles.FirstOrDefault(x => x.TemporaryActor == identifier && x.IsTemporary);
|
var profile = Profiles.FirstOrDefault(x => x.TemporaryActor == identifier && x.IsTemporary);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using CustomizePlus.Profiles;
|
|||||||
using CustomizePlus.Configuration.Helpers;
|
using CustomizePlus.Configuration.Helpers;
|
||||||
using CustomizePlus.Game.Services;
|
using CustomizePlus.Game.Services;
|
||||||
using CustomizePlus.GameData.Services;
|
using CustomizePlus.GameData.Services;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
|
|
||||||
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Debug;
|
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Debug;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ public class IPCTestTab //: IDisposable
|
|||||||
private readonly PopupSystem _popupSystem;
|
private readonly PopupSystem _popupSystem;
|
||||||
private readonly GameObjectService _gameObjectService;
|
private readonly GameObjectService _gameObjectService;
|
||||||
private readonly ObjectManager _objectManager;
|
private readonly ObjectManager _objectManager;
|
||||||
private readonly ActorService _actorService;
|
private readonly ActorManager _actorManager;
|
||||||
|
|
||||||
private readonly ICallGateSubscriber<(int, int)>? _getApiVersion;
|
private readonly ICallGateSubscriber<(int, int)>? _getApiVersion;
|
||||||
private readonly ICallGateSubscriber<string, Character?, object>? _setCharacterProfile;
|
private readonly ICallGateSubscriber<string, Character?, object>? _setCharacterProfile;
|
||||||
@@ -41,14 +42,14 @@ public class IPCTestTab //: IDisposable
|
|||||||
PopupSystem popupSystem,
|
PopupSystem popupSystem,
|
||||||
ObjectManager objectManager,
|
ObjectManager objectManager,
|
||||||
GameObjectService gameObjectService,
|
GameObjectService gameObjectService,
|
||||||
ActorService actorService)
|
ActorManager actorManager)
|
||||||
{
|
{
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
_popupSystem = popupSystem;
|
_popupSystem = popupSystem;
|
||||||
_objectManager = objectManager;
|
_objectManager = objectManager;
|
||||||
_gameObjectService = gameObjectService;
|
_gameObjectService = gameObjectService;
|
||||||
_actorService = actorService;
|
_actorManager = actorManager;
|
||||||
|
|
||||||
_popupSystem.RegisterPopup("ipc_v4_profile_remembered", "Current profile has been copied into memory");
|
_popupSystem.RegisterPopup("ipc_v4_profile_remembered", "Current profile has been copied into memory");
|
||||||
_popupSystem.RegisterPopup("ipc_get_profile_from_character_remembered", "GetProfileFromCharacter result has been copied into memory");
|
_popupSystem.RegisterPopup("ipc_get_profile_from_character_remembered", "GetProfileFromCharacter result has been copied into memory");
|
||||||
@@ -96,7 +97,7 @@ public class IPCTestTab //: IDisposable
|
|||||||
if (actors.Count == 0)
|
if (actors.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!actors[0].Item2.Identifier(_actorService.AwaitedService, out var identifier))
|
if (!actors[0].Item2.Identifier(_actorManager, out var identifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var profile = _profileManager.GetEnabledProfilesByActor(identifier).FirstOrDefault();
|
var profile = _profileManager.GetEnabledProfilesByActor(identifier).FirstOrDefault();
|
||||||
|
|||||||
Submodule submodules/Penumbra.Api updated: 80f9793ef2...cfc51714f7
Submodule submodules/Penumbra.GameData updated: ffdb966fec...260ac69cd6
Reference in New Issue
Block a user