mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Use Penumbra.GameData Actor and Model and ObjectManager.
This commit is contained in:
parent
05d261d4a3
commit
9750736d57
44 changed files with 171 additions and 512 deletions
|
|
@ -1,9 +1,9 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ using Glamourer.Designs.Links;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<RootNamespace>Glamourer</RootNamespace>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
|||
using FFXIVClientStructs.Interop;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
|
|
@ -13,6 +12,7 @@ using OtterGui.Raii;
|
|||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Gui.Materials;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ using OtterGui.Raii;
|
|||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
base64 = GlamourerIpc.GetAllCustomizationFromCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
if (base64 != null)
|
||||
ImGuiUtil.CopyOnClickSelectable(base64);
|
||||
else
|
||||
|
|
@ -66,7 +66,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromLockedCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
var base64Locked = GlamourerIpc.GetAllCustomizationFromLockedCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
var base64Locked = GlamourerIpc.GetAllCustomizationFromLockedCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337);
|
||||
if (base64Locked != null)
|
||||
ImGuiUtil.CopyOnClickSelectable(base64Locked);
|
||||
else
|
||||
|
|
@ -80,7 +80,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevertCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Revert##Character"))
|
||||
GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects[_gameObjectIndex] as Character);
|
||||
GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAll);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -96,13 +96,13 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##AllCharacter"))
|
||||
GlamourerIpc.ApplyAllToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllOnceToCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply Once##AllCharacter"))
|
||||
GlamourerIpc.ApplyAllOnceToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipment);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -113,7 +113,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##EquipCharacter"))
|
||||
GlamourerIpc.ApplyOnlyEquipmentToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomization);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -124,7 +124,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##CustomizeCharacter"))
|
||||
GlamourerIpc.ApplyOnlyCustomizationToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyByGuid);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -140,25 +140,25 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##ByGuidCharacter") && Guid.TryParse(_designIdentifier, out var guid2))
|
||||
GlamourerIpc.ApplyByGuidToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(guid2, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(guid2, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyByGuidOnceToCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply Once##ByGuidCharacter") && Guid.TryParse(_designIdentifier, out var guid2Once))
|
||||
GlamourerIpc.ApplyByGuidOnceToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(guid2Once, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
.Invoke(guid2Once, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex));
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllLock);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply With Lock##CustomizeCharacter"))
|
||||
GlamourerIpc.ApplyAllToCharacterLockSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
.Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelUnlock);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Unlock##CustomizeCharacter"))
|
||||
GlamourerIpc.UnlockSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
.Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelUnlockAll);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -170,7 +170,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Revert##CustomizeCharacter"))
|
||||
GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
.Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337);
|
||||
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetDesignList);
|
||||
|
|
@ -184,7 +184,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Set##SetItem"))
|
||||
_setItemEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, (byte)_slot, _customItemId.Id, _stainId.Id, 1337);
|
||||
.Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337);
|
||||
if (_setItemEc != GlamourerIpc.GlamourerErrorCode.Success)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
|
|
@ -195,7 +195,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Set Once##SetItem"))
|
||||
_setItemOnceEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemOnceSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, (byte)_slot, _customItemId.Id, _stainId.Id, 1337);
|
||||
.Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337);
|
||||
if (_setItemOnceEc != GlamourerIpc.GlamourerErrorCode.Success)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
|
|
@ -229,7 +229,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
|
|||
{
|
||||
var tmp = _customItemId.Id;
|
||||
if (ImGuiUtil.InputUlong("Custom Item ID", ref tmp))
|
||||
_customItemId = (CustomItemId)tmp;
|
||||
_customItemId = tmp;
|
||||
var width = ImGui.GetContentRegionAvail().X;
|
||||
EquipSlotCombo.Draw("Equip Slot", string.Empty, ref _slot);
|
||||
var value = (int)_stainId.Id;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Shader;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
|
|
@ -8,7 +7,9 @@ using OtterGui;
|
|||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
public void Draw()
|
||||
{
|
||||
ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0);
|
||||
var actor = (Actor)_objectManager.Objects.GetObjectAddress(_gameObjectIndex);
|
||||
var actor = _objectManager.Objects[_gameObjectIndex];
|
||||
var model = actor.Model;
|
||||
using var table = ImRaii.Table("##evaluationTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ using Dalamud.Hooking;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
@ -21,7 +21,7 @@ public class JobService : IDisposable
|
|||
|
||||
public event Action<Actor, Job, Job>? JobChanged;
|
||||
|
||||
public JobService(DictJob jobs, DictJobGroup jobGroups, IDataManager gameData, IGameInteropProvider interop)
|
||||
public JobService(DictJob jobs, DictJobGroup jobGroups, IGameInteropProvider interop)
|
||||
{
|
||||
interop.InitializeFromAttributes(this);
|
||||
_characterDataOffset = Marshal.OffsetOf<Character>(nameof(Character.CharacterData));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Interop.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Files;
|
||||
|
|
@ -9,9 +8,9 @@ namespace Glamourer.Interop.Material;
|
|||
|
||||
public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
||||
{
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly IFramework _framework;
|
||||
private readonly DirectXService _directXService;
|
||||
private readonly global::Penumbra.GameData.Interop.ObjectManager _objects;
|
||||
private readonly IFramework _framework;
|
||||
private readonly DirectXService _directXService;
|
||||
|
||||
public MaterialValueIndex LastValueIndex { get; private set; } = MaterialValueIndex.Invalid;
|
||||
public MtrlFile.ColorTable LastOriginalColorTable { get; private set; }
|
||||
|
|
@ -20,7 +19,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
|||
private ObjectIndex _objectIndex = ObjectIndex.AnyIndex;
|
||||
private MtrlFile.ColorTable _originalColorTable;
|
||||
|
||||
public LiveColorTablePreviewer(IObjectTable objects, IFramework framework, DirectXService directXService)
|
||||
public LiveColorTablePreviewer(global::Penumbra.GameData.Interop.ObjectManager objects, IFramework framework, DirectXService directXService)
|
||||
{
|
||||
_objects = objects;
|
||||
_framework = framework;
|
||||
|
|
@ -33,7 +32,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
|||
if (LastValueIndex.DrawObject is MaterialValueIndex.DrawObjectType.Invalid || _lastObjectIndex == ObjectIndex.AnyIndex)
|
||||
return;
|
||||
|
||||
var actor = (Actor)_objects.GetObjectAddress(_lastObjectIndex.Index);
|
||||
var actor = _objects[_lastObjectIndex];
|
||||
if (actor.IsCharacter && LastValueIndex.TryGetTexture(actor, out var texture))
|
||||
_directXService.ReplaceColorTable(texture, LastOriginalColorTable);
|
||||
|
||||
|
|
@ -51,7 +50,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
var actor = (Actor)_objects.GetObjectAddress(_objectIndex.Index);
|
||||
var actor = _objects[_objectIndex];
|
||||
if (!actor.IsCharacter)
|
||||
{
|
||||
_valueIndex = MaterialValueIndex.Invalid;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop.Material;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Lumina.Data.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using static Penumbra.GameData.Files.MtrlFile;
|
||||
using Texture = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Newtonsoft.Json;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop.Material;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop.Material;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,28 +4,15 @@ using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
|||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
||||
public class ObjectManager(IFramework framework, IClientState clientState, global::Penumbra.GameData.Interop.ObjectManager objects, ActorManager actors, ITargetManager targets)
|
||||
: IReadOnlyDictionary<ActorIdentifier, ActorData>
|
||||
{
|
||||
private readonly IFramework _framework;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ITargetManager _targets;
|
||||
|
||||
public IObjectTable Objects
|
||||
=> _objects;
|
||||
|
||||
public ObjectManager(IFramework framework, IClientState clientState, IObjectTable objects, ActorManager actors, ITargetManager targets)
|
||||
{
|
||||
_framework = framework;
|
||||
_clientState = clientState;
|
||||
_objects = objects;
|
||||
_actors = actors;
|
||||
_targets = targets;
|
||||
}
|
||||
public global::Penumbra.GameData.Interop.ObjectManager Objects
|
||||
=> objects;
|
||||
|
||||
public DateTime LastUpdate { get; private set; }
|
||||
|
||||
|
|
@ -41,39 +28,39 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
|
||||
public void Update()
|
||||
{
|
||||
var lastUpdate = _framework.LastUpdate;
|
||||
var lastUpdate = framework.LastUpdate;
|
||||
if (lastUpdate <= LastUpdate)
|
||||
return;
|
||||
|
||||
LastUpdate = lastUpdate;
|
||||
World = (ushort)(_clientState.LocalPlayer?.CurrentWorld.Id ?? 0u);
|
||||
World = (ushort)(clientState.LocalPlayer?.CurrentWorld.Id ?? 0u);
|
||||
_identifiers.Clear();
|
||||
_allWorldIdentifiers.Clear();
|
||||
_nonOwnedIdentifiers.Clear();
|
||||
|
||||
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
||||
{
|
||||
Actor character = _objects.GetObjectAddress(i);
|
||||
if (character.Identifier(_actors, out var identifier))
|
||||
var character = objects[i];
|
||||
if (character.Identifier(actors, out var identifier))
|
||||
HandleIdentifier(identifier, character);
|
||||
}
|
||||
|
||||
for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i)
|
||||
{
|
||||
Actor character = _objects.GetObjectAddress(i);
|
||||
var character = objects[i];
|
||||
// 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;
|
||||
|
||||
HandleIdentifier(character.GetIdentifier(_actors), character);
|
||||
HandleIdentifier(character.GetIdentifier(actors), character);
|
||||
}
|
||||
|
||||
void AddSpecial(ScreenActor idx, string label)
|
||||
{
|
||||
Actor actor = _objects.GetObjectAddress((int)idx);
|
||||
if (actor.Identifier(_actors, out var ident))
|
||||
var actor = objects[(int)idx];
|
||||
if (actor.Identifier(actors, out var ident))
|
||||
{
|
||||
var data = new ActorData(actor, label);
|
||||
_identifiers.Add(ident, data);
|
||||
|
|
@ -89,10 +76,10 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
AddSpecial(ScreenActor.Card7, "Card Actor 7");
|
||||
AddSpecial(ScreenActor.Card8, "Card Actor 8");
|
||||
|
||||
for (var i = (int)ScreenActor.ScreenEnd; i < _objects.Length; ++i)
|
||||
for (var i = (int)ScreenActor.ScreenEnd; i < objects.Count; ++i)
|
||||
{
|
||||
Actor character = _objects.GetObjectAddress(i);
|
||||
if (character.Identifier(_actors, out var identifier))
|
||||
var character = objects[i];
|
||||
if (character.Identifier(actors, out var identifier))
|
||||
HandleIdentifier(identifier, character);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +104,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
|
||||
if (identifier.Type is IdentifierType.Player or IdentifierType.Owned)
|
||||
{
|
||||
var allWorld = _actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
var allWorld = actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
|
||||
identifier.Kind,
|
||||
identifier.DataId);
|
||||
|
||||
|
|
@ -134,7 +121,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
|
||||
if (identifier.Type is IdentifierType.Owned)
|
||||
{
|
||||
var nonOwned = _actors.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
var nonOwned = actors.CreateNpc(identifier.Kind, identifier.DataId);
|
||||
if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var nonOwnedData))
|
||||
{
|
||||
nonOwnedData = new ActorData(character, nonOwned.ToString());
|
||||
|
|
@ -148,26 +135,26 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
}
|
||||
|
||||
public Actor GPosePlayer
|
||||
=> _objects.GetObjectAddress((int)ScreenActor.GPosePlayer);
|
||||
=> objects[(int)ScreenActor.GPosePlayer];
|
||||
|
||||
public Actor Player
|
||||
=> _objects.GetObjectAddress(0);
|
||||
=> objects[0];
|
||||
|
||||
public unsafe Actor Target
|
||||
=> _clientState.IsGPosing ? TargetSystem.Instance()->GPoseTarget : TargetSystem.Instance()->Target;
|
||||
=> clientState.IsGPosing ? TargetSystem.Instance()->GPoseTarget : TargetSystem.Instance()->Target;
|
||||
|
||||
public Actor Focus
|
||||
=> _targets.FocusTarget?.Address ?? nint.Zero;
|
||||
=> targets.FocusTarget?.Address ?? nint.Zero;
|
||||
|
||||
public Actor MouseOver
|
||||
=> _targets.MouseOverTarget?.Address ?? nint.Zero;
|
||||
=> targets.MouseOverTarget?.Address ?? nint.Zero;
|
||||
|
||||
public (ActorIdentifier Identifier, ActorData Data) PlayerData
|
||||
{
|
||||
get
|
||||
{
|
||||
Update();
|
||||
return Player.Identifier(_actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
return Player.Identifier(actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
? (ident, data)
|
||||
: (ident, ActorData.Invalid);
|
||||
}
|
||||
|
|
@ -178,7 +165,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
|||
get
|
||||
{
|
||||
Update();
|
||||
return Target.Identifier(_actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
return Target.Identifier(actors, out var ident) && _identifiers.TryGetValue(ident, out var data)
|
||||
? (ident, data)
|
||||
: (ident, ActorData.Invalid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop.Penumbra;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Api.Helpers;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop.Penumbra;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Dalamud.Hooking;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
|
|||
|
|
@ -1,142 +0,0 @@
|
|||
using Penumbra.GameData.Actors;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Interop.Structs;
|
||||
|
||||
public readonly unsafe struct Actor : IEquatable<Actor>
|
||||
{
|
||||
private Actor(nint address)
|
||||
=> Address = address;
|
||||
|
||||
public static readonly Actor Null = new(nint.Zero);
|
||||
|
||||
public readonly nint Address;
|
||||
|
||||
public GameObject* AsObject
|
||||
=> (GameObject*)Address;
|
||||
|
||||
public Character* AsCharacter
|
||||
=> (Character*)Address;
|
||||
|
||||
public bool Valid
|
||||
=> Address != nint.Zero;
|
||||
|
||||
public bool IsCharacter
|
||||
=> Valid && AsObject->IsCharacter();
|
||||
|
||||
public static implicit operator Actor(nint? pointer)
|
||||
=> new(pointer ?? nint.Zero);
|
||||
|
||||
public static implicit operator Actor(GameObject* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator Actor(Character* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator nint(Actor actor)
|
||||
=> actor.Address;
|
||||
|
||||
public bool IsGPoseOrCutscene
|
||||
=> Index.Index is >= (int)ScreenActor.CutsceneStart and < (int)ScreenActor.CutsceneEnd;
|
||||
|
||||
public bool IsTransformed
|
||||
=> AsCharacter->CharacterData.TransformationId != 0;
|
||||
|
||||
public ActorIdentifier GetIdentifier(ActorManager actors)
|
||||
=> actors.FromObject(AsObject, out _, true, true, false);
|
||||
|
||||
public ByteString Utf8Name
|
||||
=> Valid ? new ByteString(AsObject->Name) : ByteString.Empty;
|
||||
|
||||
public bool Identifier(ActorManager actors, out ActorIdentifier ident)
|
||||
{
|
||||
if (Valid)
|
||||
{
|
||||
ident = GetIdentifier(actors);
|
||||
return ident.IsValid;
|
||||
}
|
||||
|
||||
ident = ActorIdentifier.Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
public ObjectIndex Index
|
||||
=> Valid ? AsObject->ObjectIndex : ObjectIndex.AnyIndex;
|
||||
|
||||
public Model Model
|
||||
=> Valid ? AsObject->DrawObject : null;
|
||||
|
||||
public byte Job
|
||||
=> IsCharacter ? AsCharacter->CharacterData.ClassJob : (byte)0;
|
||||
|
||||
public static implicit operator bool(Actor actor)
|
||||
=> actor.Address != nint.Zero;
|
||||
|
||||
public static bool operator true(Actor actor)
|
||||
=> actor.Address != nint.Zero;
|
||||
|
||||
public static bool operator false(Actor actor)
|
||||
=> actor.Address == nint.Zero;
|
||||
|
||||
public static bool operator !(Actor actor)
|
||||
=> actor.Address == nint.Zero;
|
||||
|
||||
public bool Equals(Actor other)
|
||||
=> Address == other.Address;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is Actor other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Address.GetHashCode();
|
||||
|
||||
public static bool operator ==(Actor lhs, Actor rhs)
|
||||
=> lhs.Address == rhs.Address;
|
||||
|
||||
public static bool operator !=(Actor lhs, Actor rhs)
|
||||
=> lhs.Address != rhs.Address;
|
||||
|
||||
/// <summary> Only valid for characters. </summary>
|
||||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
||||
|
||||
public bool GetCrest(CrestFlag slot)
|
||||
=> CrestBitfield.HasFlag(slot);
|
||||
|
||||
public CharacterWeapon GetMainhand()
|
||||
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).ModelId.Value);
|
||||
|
||||
public CharacterWeapon GetOffhand()
|
||||
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).ModelId.Value);
|
||||
|
||||
public CustomizeArray GetCustomize()
|
||||
=> *(CustomizeArray*)&AsCharacter->DrawData.CustomizeData;
|
||||
|
||||
// TODO remove this when available in ClientStructs
|
||||
internal ref CrestFlag CrestBitfield
|
||||
=> ref *(CrestFlag*)((byte*)Address + 0x1BBB);
|
||||
|
||||
public override string ToString()
|
||||
=> $"0x{Address:X}";
|
||||
|
||||
public OnlineStatus OnlineStatus
|
||||
=> (OnlineStatus)AsCharacter->CharacterData.OnlineStatus;
|
||||
}
|
||||
|
||||
public enum OnlineStatus : byte
|
||||
{
|
||||
Normal = 0x00,
|
||||
Mentor = 0x1B,
|
||||
PvEMentor = 0x1C,
|
||||
TradeMentor = 0x1D,
|
||||
PvPMentor = 0x1E,
|
||||
Busy = 0x0C,
|
||||
Away = 0x11,
|
||||
MeldMateria = 0x15,
|
||||
RolePlaying = 0x16,
|
||||
LookingForGroup = 0x17,
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using OtterGui.Log;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop.Structs;
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ public readonly struct ActorData
|
|||
|
||||
public ActorData(Actor actor, string label)
|
||||
{
|
||||
Objects = new List<Actor> { actor };
|
||||
Objects = [actor];
|
||||
Label = label;
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ public readonly struct ActorData
|
|||
|
||||
private ActorData(bool _)
|
||||
{
|
||||
Objects = new List<Actor>(0);
|
||||
Objects = [];
|
||||
Label = string.Empty;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,259 +0,0 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Shader;
|
||||
using Glamourer.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
using ObjectType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.ObjectType;
|
||||
|
||||
namespace Glamourer.Interop.Structs;
|
||||
|
||||
public readonly unsafe struct Model : IEquatable<Model>
|
||||
{
|
||||
private Model(nint address)
|
||||
=> Address = address;
|
||||
|
||||
public readonly nint Address;
|
||||
|
||||
public static readonly Model Null = new(0);
|
||||
|
||||
public DrawObject* AsDrawObject
|
||||
=> (DrawObject*)Address;
|
||||
|
||||
public CharacterBase* AsCharacterBase
|
||||
=> (CharacterBase*)Address;
|
||||
|
||||
public Weapon* AsWeapon
|
||||
=> (Weapon*)Address;
|
||||
|
||||
public Human* AsHuman
|
||||
=> (Human*)Address;
|
||||
|
||||
public static implicit operator Model(nint? pointer)
|
||||
=> new(pointer ?? nint.Zero);
|
||||
|
||||
public static implicit operator Model(Object* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator Model(DrawObject* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator Model(Human* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator Model(CharacterBase* pointer)
|
||||
=> new((nint)pointer);
|
||||
|
||||
public static implicit operator nint(Model model)
|
||||
=> model.Address;
|
||||
|
||||
public bool Valid
|
||||
=> Address != nint.Zero;
|
||||
|
||||
public bool IsCharacterBase
|
||||
=> Valid && AsDrawObject->Object.GetObjectType() == ObjectType.CharacterBase;
|
||||
|
||||
public bool IsHuman
|
||||
=> IsCharacterBase && AsCharacterBase->GetModelType() == CharacterBase.ModelType.Human;
|
||||
|
||||
public bool IsWeapon
|
||||
=> IsCharacterBase && AsCharacterBase->GetModelType() == CharacterBase.ModelType.Weapon;
|
||||
|
||||
public static implicit operator bool(Model actor)
|
||||
=> actor.Address != nint.Zero;
|
||||
|
||||
public static bool operator true(Model actor)
|
||||
=> actor.Address != nint.Zero;
|
||||
|
||||
public static bool operator false(Model actor)
|
||||
=> actor.Address == nint.Zero;
|
||||
|
||||
public static bool operator !(Model actor)
|
||||
=> actor.Address == nint.Zero;
|
||||
|
||||
public bool Equals(Model other)
|
||||
=> Address == other.Address;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is Model other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Address.GetHashCode();
|
||||
|
||||
public static bool operator ==(Model lhs, Model rhs)
|
||||
=> lhs.Address == rhs.Address;
|
||||
|
||||
public static bool operator !=(Model lhs, Model rhs)
|
||||
=> lhs.Address != rhs.Address;
|
||||
|
||||
/// <summary> Only valid for humans. </summary>
|
||||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
||||
|
||||
public CustomizeArray GetCustomize()
|
||||
=> *(CustomizeArray*)&AsHuman->Customize;
|
||||
|
||||
public (Model Address, CharacterWeapon Data) GetMainhand()
|
||||
{
|
||||
Model weapon = AsDrawObject->Object.ChildObject;
|
||||
return !weapon.IsWeapon
|
||||
? (Null, CharacterWeapon.Empty)
|
||||
: (weapon, new CharacterWeapon(weapon.AsWeapon->ModelSetId, weapon.AsWeapon->SecondaryId, (Variant)weapon.AsWeapon->Variant,
|
||||
(StainId)weapon.AsWeapon->ModelUnknown));
|
||||
}
|
||||
|
||||
public (Model Address, CharacterWeapon Data) GetOffhand()
|
||||
{
|
||||
var mainhand = AsDrawObject->Object.ChildObject;
|
||||
if (mainhand == null)
|
||||
return (Null, CharacterWeapon.Empty);
|
||||
|
||||
Model offhand = mainhand->NextSiblingObject;
|
||||
if (offhand == mainhand || !offhand.IsWeapon)
|
||||
return (Null, CharacterWeapon.Empty);
|
||||
|
||||
return (offhand, new CharacterWeapon(offhand.AsWeapon->ModelSetId, offhand.AsWeapon->SecondaryId, (Variant)offhand.AsWeapon->Variant,
|
||||
(StainId)offhand.AsWeapon->ModelUnknown));
|
||||
}
|
||||
|
||||
/// <summary> Obtain the mainhand and offhand and their data by guesstimating which child object is which. </summary>
|
||||
public (Model Mainhand, Model Offhand, CharacterWeapon MainData, CharacterWeapon OffData) GetWeapons()
|
||||
{
|
||||
var (first, second, count) = GetChildrenWeapons();
|
||||
switch (count)
|
||||
{
|
||||
case 0: return (Null, Null, CharacterWeapon.Empty, CharacterWeapon.Empty);
|
||||
case 1:
|
||||
return (first, Null, new CharacterWeapon(first.AsWeapon->ModelSetId, first.AsWeapon->SecondaryId,
|
||||
(Variant)first.AsWeapon->Variant,
|
||||
(StainId)first.AsWeapon->ModelUnknown), CharacterWeapon.Empty);
|
||||
default:
|
||||
var (main, off) = DetermineMainhand(first, second);
|
||||
var mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, (Variant)main.AsWeapon->Variant,
|
||||
(StainId)main.AsWeapon->ModelUnknown);
|
||||
var offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, (Variant)off.AsWeapon->Variant,
|
||||
(StainId)off.AsWeapon->ModelUnknown);
|
||||
return (main, off, mainData, offData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Obtain the mainhand and offhand and their data by using the drawdata container from the corresponding actor. </summary>
|
||||
public (Model Mainhand, Model Offhand, CharacterWeapon MainData, CharacterWeapon OffData) GetWeapons(Actor actor)
|
||||
{
|
||||
if (!Valid || !actor.IsCharacter || actor.Model.Address != Address)
|
||||
return (Null, Null, CharacterWeapon.Empty, CharacterWeapon.Empty);
|
||||
|
||||
Model main = actor.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).DrawObject;
|
||||
var mainData = CharacterWeapon.Empty;
|
||||
if (main.IsWeapon)
|
||||
mainData = new CharacterWeapon(main.AsWeapon->ModelSetId, main.AsWeapon->SecondaryId, (Variant)main.AsWeapon->Variant,
|
||||
(StainId)main.AsWeapon->ModelUnknown);
|
||||
else
|
||||
main = Null;
|
||||
Model off = actor.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject;
|
||||
var offData = CharacterWeapon.Empty;
|
||||
if (off.IsWeapon)
|
||||
offData = new CharacterWeapon(off.AsWeapon->ModelSetId, off.AsWeapon->SecondaryId, (Variant)off.AsWeapon->Variant,
|
||||
(StainId)off.AsWeapon->ModelUnknown);
|
||||
else
|
||||
off = Null;
|
||||
return (main, off, mainData, offData);
|
||||
}
|
||||
|
||||
public CustomizeParameterData GetParameterData()
|
||||
{
|
||||
if (!IsHuman)
|
||||
return default;
|
||||
|
||||
var cBuffer1 = AsHuman->CustomizeParameterCBuffer;
|
||||
var cBuffer2 = AsHuman->DecalColorCBuffer;
|
||||
var ptr1 = (CustomizeParameter*)(cBuffer1 == null ? null : cBuffer1->UnsafeSourcePointer);
|
||||
var ptr2 = (DecalParameters*)(cBuffer2 == null ? null : cBuffer2->UnsafeSourcePointer);
|
||||
return CustomizeParameterData.FromParameters(ptr1 != null ? *ptr1 : default, ptr2 != null ? *ptr2 : default);
|
||||
}
|
||||
|
||||
public void ApplyParameterData(CustomizeParameterFlag flags, in CustomizeParameterData data)
|
||||
{
|
||||
if (!IsHuman)
|
||||
return;
|
||||
|
||||
if (flags.HasFlag(CustomizeParameterFlag.DecalColor))
|
||||
{
|
||||
var cBufferDecal = AsHuman->DecalColorCBuffer;
|
||||
var ptrDecal = (DecalParameters*)(cBufferDecal == null ? null : cBufferDecal->UnsafeSourcePointer);
|
||||
if (ptrDecal != null)
|
||||
data.Apply(ref *ptrDecal);
|
||||
}
|
||||
|
||||
flags &= ~CustomizeParameterFlag.DecalColor;
|
||||
var cBuffer = AsHuman->CustomizeParameterCBuffer;
|
||||
var ptr = (CustomizeParameter*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr != null)
|
||||
data.Apply(ref *ptr, flags);
|
||||
}
|
||||
|
||||
public bool ApplySingleParameterData(CustomizeParameterFlag flag, in CustomizeParameterData data)
|
||||
{
|
||||
if (!IsHuman)
|
||||
return false;
|
||||
|
||||
if (flag is CustomizeParameterFlag.DecalColor)
|
||||
{
|
||||
var cBuffer = AsHuman->DecalColorCBuffer;
|
||||
var ptr = (DecalParameters*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr == null)
|
||||
return false;
|
||||
|
||||
data.Apply(ref *ptr);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cBuffer = AsHuman->CustomizeParameterCBuffer;
|
||||
var ptr = (CustomizeParameter*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr == null)
|
||||
return false;
|
||||
|
||||
data.ApplySingle(ref *ptr, flag);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private (Model, Model, int) GetChildrenWeapons()
|
||||
{
|
||||
Span<Model> weapons = stackalloc Model[2];
|
||||
weapons[0] = Null;
|
||||
weapons[1] = Null;
|
||||
var count = 0;
|
||||
|
||||
if (!Valid || AsDrawObject->Object.ChildObject == null)
|
||||
return (weapons[0], weapons[1], count);
|
||||
|
||||
Model starter = AsDrawObject->Object.ChildObject;
|
||||
var iterator = starter;
|
||||
do
|
||||
{
|
||||
if (iterator.IsWeapon)
|
||||
weapons[count++] = iterator;
|
||||
if (count == 2)
|
||||
return (weapons[0], weapons[1], count);
|
||||
|
||||
iterator = iterator.AsDrawObject->Object.NextSiblingObject;
|
||||
} while (iterator.Address != starter.Address);
|
||||
|
||||
return (weapons[0], weapons[1], count);
|
||||
}
|
||||
|
||||
/// <summary> I don't know a safe way to do this but in experiments this worked.
|
||||
/// The first uint at +0x8 was set to non-zero for the mainhand and zero for the offhand. </summary>
|
||||
private static (Model Mainhand, Model Offhand) DetermineMainhand(Model first, Model second)
|
||||
{
|
||||
var discriminator1 = *(ulong*)(first.Address + 0x10);
|
||||
var discriminator2 = *(ulong*)(second.Address + 0x10);
|
||||
return discriminator1 == 0 && discriminator2 != 0 ? (second, first) : (first, second);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"0x{Address:X}";
|
||||
}
|
||||
67
Glamourer/Interop/Structs/ModelExtensions.cs
Normal file
67
Glamourer/Interop/Structs/ModelExtensions.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
using FFXIVClientStructs.FFXIV.Shader;
|
||||
using Glamourer.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop.Structs;
|
||||
|
||||
public static unsafe class ModelExtensions
|
||||
{
|
||||
public static CustomizeParameterData GetParameterData(this Model model)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return default;
|
||||
|
||||
var cBuffer1 = model.AsHuman->CustomizeParameterCBuffer;
|
||||
var cBuffer2 = model.AsHuman->DecalColorCBuffer;
|
||||
var ptr1 = (CustomizeParameter*)(cBuffer1 == null ? null : cBuffer1->UnsafeSourcePointer);
|
||||
var ptr2 = (DecalParameters*)(cBuffer2 == null ? null : cBuffer2->UnsafeSourcePointer);
|
||||
return CustomizeParameterData.FromParameters(ptr1 != null ? *ptr1 : default, ptr2 != null ? *ptr2 : default);
|
||||
}
|
||||
|
||||
public static void ApplyParameterData(this Model model, CustomizeParameterFlag flags, in CustomizeParameterData data)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
||||
if (flags.HasFlag(CustomizeParameterFlag.DecalColor))
|
||||
{
|
||||
var cBufferDecal = model.AsHuman->DecalColorCBuffer;
|
||||
var ptrDecal = (DecalParameters*)(cBufferDecal == null ? null : cBufferDecal->UnsafeSourcePointer);
|
||||
if (ptrDecal != null)
|
||||
data.Apply(ref *ptrDecal);
|
||||
}
|
||||
|
||||
flags &= ~CustomizeParameterFlag.DecalColor;
|
||||
var cBuffer = model.AsHuman->CustomizeParameterCBuffer;
|
||||
var ptr = (CustomizeParameter*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr != null)
|
||||
data.Apply(ref *ptr, flags);
|
||||
}
|
||||
|
||||
public static bool ApplySingleParameterData(this Model model, CustomizeParameterFlag flag, in CustomizeParameterData data)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return false;
|
||||
|
||||
if (flag is CustomizeParameterFlag.DecalColor)
|
||||
{
|
||||
var cBuffer = model.AsHuman->DecalColorCBuffer;
|
||||
var ptr = (DecalParameters*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr == null)
|
||||
return false;
|
||||
|
||||
data.Apply(ref *ptr);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cBuffer = model.AsHuman->CustomizeParameterCBuffer;
|
||||
var ptr = (CustomizeParameter*)(cBuffer == null ? null : cBuffer->UnsafeSourcePointer);
|
||||
if (ptr == null)
|
||||
return false;
|
||||
|
||||
data.ApplySingle(ref *ptr, flag);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ using Glamourer.Automation;
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,5 +26,6 @@ public class DalamudServices
|
|||
services.AddDalamudService<ITextureProvider>(pi);
|
||||
services.AddDalamudService<IPluginLog>(pi);
|
||||
services.AddDalamudService<IGameInteropProvider>(pi);
|
||||
services.AddDalamudService<INotificationManager>(pi);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using CustomizeIndex = Penumbra.GameData.Enums.CustomizeIndex;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ using Dalamud.Plugin.Services;
|
|||
using Glamourer.GameData;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Glamourer.Designs;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -550,10 +552,10 @@ public class StateListener : IDisposable
|
|||
/// only if we kept track of state of someone who went to the aesthetician,
|
||||
/// or if they used other tools to change things.
|
||||
/// </summary>
|
||||
private UpdateState UpdateBaseData(Actor actor, ActorState state, CustomizeArray customize, bool checkTransform)
|
||||
private unsafe UpdateState UpdateBaseData(Actor actor, ActorState state, CustomizeArray customize, bool checkTransform)
|
||||
{
|
||||
// Customize array does not agree between game object and draw object => transformation.
|
||||
if (checkTransform && !actor.GetCustomize().Equals(customize))
|
||||
if (checkTransform && !actor.Customize->Equals(customize))
|
||||
return UpdateState.Transformed;
|
||||
|
||||
// Customize array did not change to stored state.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Penumbra.GameData.Actors;
|
|||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ public sealed class StateManager(
|
|||
else
|
||||
{
|
||||
// Obtain all data from the game object.
|
||||
ret.Customize = actor.GetCustomize();
|
||||
ret.Customize = *actor.Customize;
|
||||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
|
@ -344,10 +344,10 @@ public class WorldSets
|
|||
}
|
||||
|
||||
|
||||
private unsafe (byte, byte, Race, Gender) GetData(Actor actor)
|
||||
private static unsafe (byte, byte, Race, Gender) GetData(Actor actor)
|
||||
{
|
||||
var customize = actor.GetCustomize();
|
||||
return (actor.AsCharacter->CharacterData.Level, actor.Job, customize.Race, customize.Gender);
|
||||
var customize = actor.Customize;
|
||||
return (actor.AsCharacter->CharacterData.Level, actor.Job, customize->Race, customize->Gender);
|
||||
}
|
||||
|
||||
public void Apply(Actor actor, Random rng, Span<CharacterArmor> armor)
|
||||
|
|
@ -356,7 +356,7 @@ public class WorldSets
|
|||
Apply(level, job, race, gender, rng, armor);
|
||||
}
|
||||
|
||||
public void Apply(byte level, byte job, Race race, Gender gender, Random rng, Span<CharacterArmor> armor)
|
||||
private void Apply(byte level, byte job, Race race, Gender gender, Random rng, Span<CharacterArmor> armor)
|
||||
{
|
||||
var opt = GetGroup(level, job, race, gender, rng);
|
||||
if (opt == null)
|
||||
|
|
@ -375,7 +375,7 @@ public class WorldSets
|
|||
Apply(level, job, race, gender, rng, ref armor, slot);
|
||||
}
|
||||
|
||||
public void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterArmor armor, EquipSlot slot)
|
||||
private void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterArmor armor, EquipSlot slot)
|
||||
{
|
||||
var opt = GetGroup(level, job, race, gender, rng);
|
||||
if (opt == null)
|
||||
|
|
@ -398,7 +398,7 @@ public class WorldSets
|
|||
Apply(level, job, race, gender, rng, ref weapon, slot);
|
||||
}
|
||||
|
||||
public void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterWeapon weapon, EquipSlot slot)
|
||||
private void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterWeapon weapon, EquipSlot slot)
|
||||
{
|
||||
var opt = GetGroup(level, job, race, gender, rng);
|
||||
if (opt == null)
|
||||
|
|
|
|||
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit d71f8540a2c2efb4f2cb96e4706bb056397daf0a
|
||||
Subproject commit b4b14367d8235eabedd561ad3626beb1d2a83889
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 34921fd2c5a9aff5d34aef664bdb78331e8b9436
|
||||
Subproject commit d2a1406bc32f715c0687613f02e3f74caf7ceea9
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d0db2f1fbc3ce26d0756da5118157e5fc723c62f
|
||||
Subproject commit 74a305768880cd783b21e85ef97e9be77b119885
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 620a7edf009b92288257ce7d64fffb8fba44d8b5
|
||||
Subproject commit 14e00f77d42bc677e02325660db765ef11932560
|
||||
Loading…
Add table
Add a link
Reference in a new issue