Use Penumbra.GameData Actor and Model and ObjectManager.

This commit is contained in:
Ottermandias 2024-03-19 23:19:46 +01:00
parent 05d261d4a3
commit 9750736d57
44 changed files with 171 additions and 512 deletions

View file

@ -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;

View file

@ -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;

View file

@ -1,5 +1,5 @@
using Glamourer.Interop.Structs;
using OtterGui.Classes;
using Penumbra.GameData.Interop;
namespace Glamourer.Events;

View file

@ -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;

View file

@ -1,5 +1,5 @@
using Glamourer.Interop.Structs;
using OtterGui.Classes;
using Penumbra.GameData.Interop;
namespace Glamourer.Events;

View file

@ -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;

View file

@ -1,5 +1,5 @@
using Glamourer.Interop.Structs;
using OtterGui.Classes;
using Penumbra.GameData.Interop;
namespace Glamourer.Events;

View file

@ -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>

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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));

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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,
}

View file

@ -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;
}

View file

@ -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}";
}

View 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;
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -26,5 +26,6 @@ public class DalamudServices
services.AddDalamudService<ITextureProvider>(pi);
services.AddDalamudService<IPluginLog>(pi);
services.AddDalamudService<IGameInteropProvider>(pi);
services.AddDalamudService<INotificationManager>(pi);
}
}

View file

@ -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;

View file

@ -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.

View file

@ -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)
{

View file

@ -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)

@ -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