mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Use ObjectManager, Actor and Model.
This commit is contained in:
parent
5b9309a311
commit
c8216b0acc
22 changed files with 240 additions and 325 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 1df06807650a79813791effaa01fb7c4710b3dab
|
||||
Subproject commit d2a1406bc32f715c0687613f02e3f74caf7ceea9
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d53db6a358cedecd3ef18f62f12a07deff4b61ee
|
||||
Subproject commit a1262e242ca33bb0e9e4f080d294d9160b5e54eb
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Plugin;
|
||||
|
|
@ -18,6 +19,7 @@ using Penumbra.Collections.Manager;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Api;
|
||||
|
||||
|
|
@ -40,7 +42,7 @@ public class IpcTester : IDisposable
|
|||
private readonly Temporary _temporary;
|
||||
private readonly ResourceTree _resourceTree;
|
||||
|
||||
public IpcTester(Configuration config, DalamudPluginInterface pi, IObjectTable objects, IClientState clientState,
|
||||
public IpcTester(Configuration config, DalamudPluginInterface pi, ObjectManager objects, IClientState clientState,
|
||||
PenumbraIpcProviders ipcProviders, ModManager modManager, CollectionManager collections, TempModManager tempMods,
|
||||
TempCollectionManager tempCollections, SaveService saveService)
|
||||
{
|
||||
|
|
@ -280,16 +282,16 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
|
||||
using var popup = ImRaii.Popup("Config Popup");
|
||||
if (popup)
|
||||
{
|
||||
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
ImGuiUtil.TextWrapped(_currentConfiguration);
|
||||
}
|
||||
if (!popup)
|
||||
return;
|
||||
|
||||
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
||||
ImGui.CloseCurrentPopup();
|
||||
using (ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
ImGuiUtil.TextWrapped(_currentConfiguration);
|
||||
}
|
||||
|
||||
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
private void UpdateModDirectoryChanged(string path, bool valid)
|
||||
|
|
@ -304,15 +306,15 @@ public class IpcTester : IDisposable
|
|||
public readonly EventSubscriber<ChangedItemType, uint> Tooltip;
|
||||
public readonly EventSubscriber<MouseButton, ChangedItemType, uint> Click;
|
||||
|
||||
private string _lastDrawnMod = string.Empty;
|
||||
private DateTimeOffset _lastDrawnModTime = DateTimeOffset.MinValue;
|
||||
private bool _subscribedToTooltip = false;
|
||||
private bool _subscribedToClick = false;
|
||||
private string _lastClicked = string.Empty;
|
||||
private string _lastHovered = string.Empty;
|
||||
private TabType _selectTab = TabType.None;
|
||||
private string _modName = string.Empty;
|
||||
private PenumbraApiEc _ec = PenumbraApiEc.Success;
|
||||
private string _lastDrawnMod = string.Empty;
|
||||
private DateTimeOffset _lastDrawnModTime = DateTimeOffset.MinValue;
|
||||
private bool _subscribedToTooltip;
|
||||
private bool _subscribedToClick;
|
||||
private string _lastClicked = string.Empty;
|
||||
private string _lastHovered = string.Empty;
|
||||
private TabType _selectTab = TabType.None;
|
||||
private string _modName = string.Empty;
|
||||
private PenumbraApiEc _ec = PenumbraApiEc.Success;
|
||||
|
||||
public Ui(DalamudPluginInterface pi)
|
||||
{
|
||||
|
|
@ -401,14 +403,14 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
public readonly EventSubscriber<IntPtr, int> Redrawn;
|
||||
|
||||
private string _redrawName = string.Empty;
|
||||
private int _redrawIndex = 0;
|
||||
private string _redrawName = string.Empty;
|
||||
private int _redrawIndex;
|
||||
private string _lastRedrawnString = "None";
|
||||
|
||||
public Redrawing(DalamudPluginInterface pi, IObjectTable objects, IClientState clientState)
|
||||
public Redrawing(DalamudPluginInterface pi, ObjectManager objects, IClientState clientState)
|
||||
{
|
||||
_pi = pi;
|
||||
_objects = objects;
|
||||
|
|
@ -440,8 +442,8 @@ public class IpcTester : IDisposable
|
|||
DrawIntro(Ipc.RedrawObjectByIndex.Label, "Redraw by Index");
|
||||
var tmp = _redrawIndex;
|
||||
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
||||
if (ImGui.DragInt("##redrawIndex", ref tmp, 0.1f, 0, _objects.Length))
|
||||
_redrawIndex = Math.Clamp(tmp, 0, _objects.Length);
|
||||
if (ImGui.DragInt("##redrawIndex", ref tmp, 0.1f, 0, _objects.Count))
|
||||
_redrawIndex = Math.Clamp(tmp, 0, _objects.Count);
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Redraw##Index"))
|
||||
|
|
@ -458,12 +460,12 @@ public class IpcTester : IDisposable
|
|||
private void SetLastRedrawn(IntPtr address, int index)
|
||||
{
|
||||
if (index < 0
|
||||
|| index > _objects.Length
|
||||
|| index > _objects.Count
|
||||
|| address == IntPtr.Zero
|
||||
|| _objects[index]?.Address != address)
|
||||
|| _objects[index].Address != address)
|
||||
_lastRedrawnString = "Invalid";
|
||||
|
||||
_lastRedrawnString = $"{_objects[index]!.Name} (0x{address:X}, {index})";
|
||||
_lastRedrawnString = $"{_objects[index].Utf8Name} (0x{address:X}, {index})";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -588,8 +590,8 @@ public class IpcTester : IDisposable
|
|||
private string _currentResolvePath = string.Empty;
|
||||
private string _currentResolveCharacter = string.Empty;
|
||||
private string _currentReversePath = string.Empty;
|
||||
private int _currentReverseIdx = 0;
|
||||
private Task<(string[], string[][])> _task = Task.FromException<(string[], string[][])>(new Exception());
|
||||
private int _currentReverseIdx;
|
||||
private Task<(string[], string[][])> _task = Task.FromException<(string[], string[][])>(new Exception());
|
||||
|
||||
public Resolve(DalamudPluginInterface pi)
|
||||
=> _pi = pi;
|
||||
|
|
@ -696,8 +698,6 @@ public class IpcTester : IDisposable
|
|||
return text;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
DrawIntro(Ipc.ResolvePlayerPaths.Label, "Resolved Paths (Player)");
|
||||
if (forwardArray.Length > 0 || reverseArray.Length > 0)
|
||||
{
|
||||
|
|
@ -721,18 +721,18 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
|
||||
private int _objectIdx = 0;
|
||||
private int _objectIdx;
|
||||
private string _collectionName = string.Empty;
|
||||
private bool _allowCreation = true;
|
||||
private bool _allowDeletion = true;
|
||||
private ApiCollectionType _type = ApiCollectionType.Current;
|
||||
|
||||
private string _characterCollectionName = string.Empty;
|
||||
private IList<string> _collections = new List<string>();
|
||||
private IList<string> _collections = [];
|
||||
private string _changedItemCollection = string.Empty;
|
||||
private IReadOnlyDictionary<string, object?> _changedItems = new Dictionary<string, object?>();
|
||||
private PenumbraApiEc _returnCode = PenumbraApiEc.Success;
|
||||
private string? _oldCollection = null;
|
||||
private string? _oldCollection;
|
||||
|
||||
public Collections(DalamudPluginInterface pi)
|
||||
=> _pi = pi;
|
||||
|
|
@ -845,8 +845,8 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
|
||||
private string _characterName = string.Empty;
|
||||
private int _gameObjectIndex = 0;
|
||||
private string _characterName = string.Empty;
|
||||
private int _gameObjectIndex;
|
||||
|
||||
public Meta(DalamudPluginInterface pi)
|
||||
=> _pi = pi;
|
||||
|
|
@ -1040,11 +1040,11 @@ public class IpcTester : IDisposable
|
|||
private string _settingsModName = string.Empty;
|
||||
private string _settingsCollection = string.Empty;
|
||||
private bool _settingsAllowInheritance = true;
|
||||
private bool _settingsInherit = false;
|
||||
private bool _settingsEnabled = false;
|
||||
private int _settingsPriority = 0;
|
||||
private bool _settingsInherit;
|
||||
private bool _settingsEnabled;
|
||||
private int _settingsPriority;
|
||||
private IDictionary<string, (IList<string>, GroupType)>? _availableSettings;
|
||||
private IDictionary<string, IList<string>>? _currentSettings = null;
|
||||
private IDictionary<string, IList<string>>? _currentSettings;
|
||||
|
||||
public ModSettings(DalamudPluginInterface pi)
|
||||
{
|
||||
|
|
@ -1287,7 +1287,7 @@ public class IpcTester : IDisposable
|
|||
private string _tempFilePath = "test/success.mtrl";
|
||||
private string _tempManipulation = string.Empty;
|
||||
private PenumbraApiEc _lastTempError;
|
||||
private int _tempActorIndex = 0;
|
||||
private int _tempActorIndex;
|
||||
private bool _forceOverwrite;
|
||||
|
||||
public void Draw()
|
||||
|
|
@ -1441,15 +1441,13 @@ public class IpcTester : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private class ResourceTree
|
||||
private class ResourceTree(DalamudPluginInterface pi, ObjectManager objects)
|
||||
{
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly Stopwatch _stopwatch = new();
|
||||
private readonly Stopwatch _stopwatch = new();
|
||||
|
||||
private string _gameObjectIndices = "0";
|
||||
private ResourceType _type = ResourceType.Mtrl;
|
||||
private bool _withUIData = false;
|
||||
private bool _withUiData;
|
||||
|
||||
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastGameObjectResourcePaths;
|
||||
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastPlayerResourcePaths;
|
||||
|
|
@ -1459,12 +1457,6 @@ public class IpcTester : IDisposable
|
|||
private (string, Ipc.ResourceTree)[]? _lastPlayerResourceTrees;
|
||||
private TimeSpan _lastCallDuration;
|
||||
|
||||
public ResourceTree(DalamudPluginInterface pi, IObjectTable objects)
|
||||
{
|
||||
_pi = pi;
|
||||
_objects = objects;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var _ = ImRaii.TreeNode("Resource Tree");
|
||||
|
|
@ -1473,7 +1465,7 @@ public class IpcTester : IDisposable
|
|||
|
||||
ImGui.InputText("GameObject indices", ref _gameObjectIndices, 511);
|
||||
ImGuiUtil.GenericEnumCombo("Resource type", ImGui.CalcItemWidth(), _type, out _type, Enum.GetValues<ResourceType>());
|
||||
ImGui.Checkbox("Also get names and icons", ref _withUIData);
|
||||
ImGui.Checkbox("Also get names and icons", ref _withUiData);
|
||||
|
||||
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
|
|
@ -1483,7 +1475,7 @@ public class IpcTester : IDisposable
|
|||
if (ImGui.Button("Get##GameObjectResourcePaths"))
|
||||
{
|
||||
var gameObjects = GetSelectedGameObjects();
|
||||
var subscriber = Ipc.GetGameObjectResourcePaths.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetGameObjectResourcePaths.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var resourcePaths = subscriber.Invoke(gameObjects);
|
||||
|
||||
|
|
@ -1499,7 +1491,7 @@ public class IpcTester : IDisposable
|
|||
DrawIntro(Ipc.GetPlayerResourcePaths.Label, "Get local player resource paths");
|
||||
if (ImGui.Button("Get##PlayerResourcePaths"))
|
||||
{
|
||||
var subscriber = Ipc.GetPlayerResourcePaths.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetPlayerResourcePaths.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var resourcePaths = subscriber.Invoke();
|
||||
|
||||
|
|
@ -1515,9 +1507,9 @@ public class IpcTester : IDisposable
|
|||
if (ImGui.Button("Get##GameObjectResourcesOfType"))
|
||||
{
|
||||
var gameObjects = GetSelectedGameObjects();
|
||||
var subscriber = Ipc.GetGameObjectResourcesOfType.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetGameObjectResourcesOfType.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var resourcesOfType = subscriber.Invoke(_type, _withUIData, gameObjects);
|
||||
var resourcesOfType = subscriber.Invoke(_type, _withUiData, gameObjects);
|
||||
|
||||
_lastCallDuration = _stopwatch.Elapsed;
|
||||
_lastGameObjectResourcesOfType = gameObjects
|
||||
|
|
@ -1531,9 +1523,9 @@ public class IpcTester : IDisposable
|
|||
DrawIntro(Ipc.GetPlayerResourcesOfType.Label, "Get local player resources of type");
|
||||
if (ImGui.Button("Get##PlayerResourcesOfType"))
|
||||
{
|
||||
var subscriber = Ipc.GetPlayerResourcesOfType.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetPlayerResourcesOfType.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var resourcesOfType = subscriber.Invoke(_type, _withUIData);
|
||||
var resourcesOfType = subscriber.Invoke(_type, _withUiData);
|
||||
|
||||
_lastCallDuration = _stopwatch.Elapsed;
|
||||
_lastPlayerResourcesOfType = resourcesOfType
|
||||
|
|
@ -1547,9 +1539,9 @@ public class IpcTester : IDisposable
|
|||
if (ImGui.Button("Get##GameObjectResourceTrees"))
|
||||
{
|
||||
var gameObjects = GetSelectedGameObjects();
|
||||
var subscriber = Ipc.GetGameObjectResourceTrees.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetGameObjectResourceTrees.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var trees = subscriber.Invoke(_withUIData, gameObjects);
|
||||
var trees = subscriber.Invoke(_withUiData, gameObjects);
|
||||
|
||||
_lastCallDuration = _stopwatch.Elapsed;
|
||||
_lastGameObjectResourceTrees = gameObjects
|
||||
|
|
@ -1563,9 +1555,9 @@ public class IpcTester : IDisposable
|
|||
DrawIntro(Ipc.GetPlayerResourceTrees.Label, "Get local player resource trees");
|
||||
if (ImGui.Button("Get##PlayerResourceTrees"))
|
||||
{
|
||||
var subscriber = Ipc.GetPlayerResourceTrees.Subscriber(_pi);
|
||||
var subscriber = Ipc.GetPlayerResourceTrees.Subscriber(pi);
|
||||
_stopwatch.Restart();
|
||||
var trees = subscriber.Invoke(_withUIData);
|
||||
var trees = subscriber.Invoke(_withUiData);
|
||||
|
||||
_lastCallDuration = _stopwatch.Elapsed;
|
||||
_lastPlayerResourceTrees = trees
|
||||
|
|
@ -1666,13 +1658,13 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
DrawWithHeaders(result, resources =>
|
||||
{
|
||||
using var table = ImRaii.Table(string.Empty, _withUIData ? 3 : 2, ImGuiTableFlags.SizingFixedFit);
|
||||
using var table = ImRaii.Table(string.Empty, _withUiData ? 3 : 2, ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupColumn("Resource Handle", ImGuiTableColumnFlags.WidthStretch, 0.15f);
|
||||
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, _withUIData ? 0.55f : 0.85f);
|
||||
if (_withUIData)
|
||||
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, _withUiData ? 0.55f : 0.85f);
|
||||
if (_withUiData)
|
||||
ImGui.TableSetupColumn("Icon & Name", ImGuiTableColumnFlags.WidthStretch, 0.3f);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
|
|
@ -1682,7 +1674,7 @@ public class IpcTester : IDisposable
|
|||
TextUnformattedMono($"0x{resourceHandle:X}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(actualPath);
|
||||
if (_withUIData)
|
||||
if (_withUiData)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
TextUnformattedMono(icon.ToString());
|
||||
|
|
@ -1699,11 +1691,11 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
ImGui.TextUnformatted($"Name: {tree.Name}\nRaceCode: {(GenderRace)tree.RaceCode}");
|
||||
|
||||
using var table = ImRaii.Table(string.Empty, _withUIData ? 7 : 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Resizable);
|
||||
using var table = ImRaii.Table(string.Empty, _withUiData ? 7 : 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Resizable);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (_withUIData)
|
||||
if (_withUiData)
|
||||
{
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch, 0.5f);
|
||||
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthStretch, 0.1f);
|
||||
|
|
@ -1726,11 +1718,11 @@ public class IpcTester : IDisposable
|
|||
ImGui.TableNextColumn();
|
||||
var hasChildren = node.Children.Any();
|
||||
using var treeNode = ImRaii.TreeNode(
|
||||
$"{(_withUIData ? node.Name ?? "Unknown" : node.Type)}##{node.ObjectAddress:X8}",
|
||||
$"{(_withUiData ? node.Name ?? "Unknown" : node.Type)}##{node.ObjectAddress:X8}",
|
||||
hasChildren
|
||||
? ImGuiTreeNodeFlags.SpanFullWidth
|
||||
: ImGuiTreeNodeFlags.SpanFullWidth | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen);
|
||||
if (_withUIData)
|
||||
if (_withUiData)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
TextUnformattedMono(node.Type.ToString());
|
||||
|
|
@ -1770,10 +1762,10 @@ public class IpcTester : IDisposable
|
|||
|
||||
private unsafe string GameObjectToString(ObjectIndex gameObjectIndex)
|
||||
{
|
||||
var gameObject = _objects[gameObjectIndex.Index];
|
||||
var gameObject = objects[gameObjectIndex];
|
||||
|
||||
return gameObject != null
|
||||
? $"[{gameObjectIndex}] {gameObject.Name} ({gameObject.ObjectKind})"
|
||||
return gameObject.Valid
|
||||
? $"[{gameObjectIndex}] {gameObject.Utf8Name} ({(ObjectKind)gameObject.AsObject->ObjectKind})"
|
||||
: $"[{gameObjectIndex}] null";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ using Penumbra.String.Classes;
|
|||
using Penumbra.Services;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.UI;
|
||||
|
|
@ -93,7 +94,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
private IDataManager _gameData;
|
||||
private IFramework _framework;
|
||||
private IObjectTable _objects;
|
||||
private ObjectManager _objects;
|
||||
private ModManager _modManager;
|
||||
private ResourceLoader _resourceLoader;
|
||||
private Configuration _config;
|
||||
|
|
@ -111,7 +112,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
private TextureManager _textureManager;
|
||||
private ResourceTreeFactory _resourceTreeFactory;
|
||||
|
||||
public unsafe PenumbraApi(CommunicatorService communicator, IDataManager gameData, IFramework framework, IObjectTable objects,
|
||||
public unsafe PenumbraApi(CommunicatorService communicator, IDataManager gameData, IFramework framework, ObjectManager objects,
|
||||
ModManager modManager, ResourceLoader resourceLoader, Configuration config, CollectionManager collectionManager,
|
||||
TempCollectionManager tempCollections, TempModManager tempMods, ActorManager actors, CollectionResolver collectionResolver,
|
||||
CutsceneService cutsceneService, ModImportManager modImportManager, CollectionEditor collectionEditor, RedrawService redrawService,
|
||||
|
|
@ -928,10 +929,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
CheckInitialized();
|
||||
|
||||
if (actorIndex < 0 || actorIndex >= _objects.Length)
|
||||
if (actorIndex < 0 || actorIndex >= _objects.Count)
|
||||
return PenumbraApiEc.InvalidArgument;
|
||||
|
||||
var identifier = _actors.FromObject(_objects[actorIndex], false, false, true);
|
||||
var identifier = _actors.FromObject(_objects[actorIndex], out _, false, false, true);
|
||||
if (!identifier.IsValid)
|
||||
return PenumbraApiEc.InvalidArgument;
|
||||
|
||||
|
|
@ -1076,11 +1077,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public IReadOnlyDictionary<string, string[]>?[] GetGameObjectResourcePaths(ushort[] gameObjects)
|
||||
{
|
||||
var characters = gameObjects.Select(index => _objects[index]).OfType<Character>();
|
||||
var characters = gameObjects.Select(index => _objects.GetDalamudObject((int) index)).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, 0);
|
||||
var pathDictionaries = ResourceTreeApiHelper.GetResourcePathDictionaries(resourceTrees);
|
||||
|
||||
return Array.ConvertAll(gameObjects, obj => pathDictionaries.TryGetValue(obj, out var pathDict) ? pathDict : null);
|
||||
return Array.ConvertAll(gameObjects, obj => pathDictionaries.GetValueOrDefault(obj));
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>> GetPlayerResourcePaths()
|
||||
|
|
@ -1091,39 +1092,39 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return pathDictionaries.AsReadOnly();
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[] GetGameObjectResourcesOfType(ResourceType type, bool withUIData,
|
||||
public IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[] GetGameObjectResourcesOfType(ResourceType type, bool withUiData,
|
||||
params ushort[] gameObjects)
|
||||
{
|
||||
var characters = gameObjects.Select(index => _objects[index]).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUiData : 0);
|
||||
var characters = gameObjects.Select(index => _objects.GetDalamudObject((int)index)).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUiData ? ResourceTreeFactory.Flags.WithUiData : 0);
|
||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||
|
||||
return Array.ConvertAll(gameObjects, obj => resDictionaries.TryGetValue(obj, out var resDict) ? resDict : null);
|
||||
return Array.ConvertAll(gameObjects, obj => resDictionaries.GetValueOrDefault(obj));
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>> GetPlayerResourcesOfType(ResourceType type,
|
||||
bool withUIData)
|
||||
bool withUiData)
|
||||
{
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly
|
||||
| (withUIData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||
| (withUiData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||
|
||||
return resDictionaries.AsReadOnly();
|
||||
}
|
||||
|
||||
public Ipc.ResourceTree?[] GetGameObjectResourceTrees(bool withUIData, params ushort[] gameObjects)
|
||||
public Ipc.ResourceTree?[] GetGameObjectResourceTrees(bool withUiData, params ushort[] gameObjects)
|
||||
{
|
||||
var characters = gameObjects.Select(index => _objects[index]).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUiData : 0);
|
||||
var characters = gameObjects.Select(index => _objects.GetDalamudObject((int)index)).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUiData ? ResourceTreeFactory.Flags.WithUiData : 0);
|
||||
var resDictionary = ResourceTreeApiHelper.EncapsulateResourceTrees(resourceTrees);
|
||||
|
||||
return Array.ConvertAll(gameObjects, obj => resDictionary.TryGetValue(obj, out var nodes) ? nodes : null);
|
||||
return Array.ConvertAll(gameObjects, obj => resDictionary.GetValueOrDefault(obj));
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<ushort, Ipc.ResourceTree> GetPlayerResourceTrees(bool withUIData)
|
||||
public IReadOnlyDictionary<ushort, Ipc.ResourceTree> GetPlayerResourceTrees(bool withUiData)
|
||||
{
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly
|
||||
| (withUIData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||
| (withUiData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||
var resDictionary = ResourceTreeApiHelper.EncapsulateResourceTrees(resourceTrees);
|
||||
|
||||
return resDictionary.AsReadOnly();
|
||||
|
|
@ -1165,11 +1166,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
private unsafe bool AssociatedCollection(int gameObjectIdx, out ModCollection collection)
|
||||
{
|
||||
collection = _collectionManager.Active.Default;
|
||||
if (gameObjectIdx < 0 || gameObjectIdx >= _objects.Length)
|
||||
if (gameObjectIdx < 0 || gameObjectIdx >= _objects.Count)
|
||||
return false;
|
||||
|
||||
var ptr = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_objects.GetObjectAddress(gameObjectIdx);
|
||||
var data = _collectionResolver.IdentifyCollection(ptr, false);
|
||||
var ptr = _objects[gameObjectIdx];
|
||||
var data = _collectionResolver.IdentifyCollection(ptr.AsObject, false);
|
||||
if (data.Valid)
|
||||
collection = data.ModCollection;
|
||||
|
||||
|
|
@ -1179,10 +1180,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private unsafe ActorIdentifier AssociatedIdentifier(int gameObjectIdx)
|
||||
{
|
||||
if (gameObjectIdx < 0 || gameObjectIdx >= _objects.Length)
|
||||
if (gameObjectIdx < 0 || gameObjectIdx >= _objects.Count)
|
||||
return ActorIdentifier.Invalid;
|
||||
|
||||
var ptr = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_objects.GetObjectAddress(gameObjectIdx);
|
||||
var ptr = _objects[gameObjectIdx];
|
||||
return _actors.FromObject(ptr, out _, false, true, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.CrashHandler.Buffers;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -16,10 +16,10 @@ public sealed unsafe class LoadCharacterVfx : FastHook<LoadCharacterVfx.Delegate
|
|||
{
|
||||
private readonly GameState _state;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CrashHandlerService _crashHandler;
|
||||
|
||||
public LoadCharacterVfx(HookManager hooks, GameState state, CollectionResolver collectionResolver, IObjectTable objects,
|
||||
public LoadCharacterVfx(HookManager hooks, GameState state, CollectionResolver collectionResolver, ObjectManager objects,
|
||||
CrashHandlerService crashHandler)
|
||||
{
|
||||
_state = state;
|
||||
|
|
@ -39,19 +39,19 @@ public sealed unsafe class LoadCharacterVfx : FastHook<LoadCharacterVfx.Delegate
|
|||
{
|
||||
var obj = vfxParams->GameObjectType switch
|
||||
{
|
||||
0 => _objects.SearchById(vfxParams->GameObjectId),
|
||||
0 => _objects.ById(vfxParams->GameObjectId),
|
||||
2 => _objects[(int)vfxParams->GameObjectId],
|
||||
4 => GetOwnedObject(vfxParams->GameObjectId),
|
||||
_ => null,
|
||||
_ => Actor.Null,
|
||||
};
|
||||
newData = obj != null
|
||||
newData = obj.Valid
|
||||
? _collectionResolver.IdentifyCollection((GameObject*)obj.Address, true)
|
||||
: ResolveData.Invalid;
|
||||
}
|
||||
|
||||
var last = _state.SetAnimationData(newData);
|
||||
_crashHandler.LogAnimation(newData.AssociatedGameObject, newData.ModCollection, AnimationInvocationType.LoadCharacterVfx);
|
||||
var ret = Task.Result.Original(vfxPath, vfxParams, unk1, unk2, unk3, unk4);
|
||||
var ret = Task.Result.Original(vfxPath, vfxParams, unk1, unk2, unk3, unk4);
|
||||
Penumbra.Log.Excessive(
|
||||
$"[Load Character VFX] Invoked with {new ByteString(vfxPath)}, 0x{vfxParams->GameObjectId:X}, {vfxParams->TargetCount}, {unk1}, {unk2}, {unk3}, {unk4} -> 0x{ret:X}.");
|
||||
_state.RestoreAnimationData(last);
|
||||
|
|
@ -59,13 +59,11 @@ public sealed unsafe class LoadCharacterVfx : FastHook<LoadCharacterVfx.Delegate
|
|||
}
|
||||
|
||||
/// <summary> Search an object by its id, then get its minion/mount/ornament. </summary>
|
||||
private Dalamud.Game.ClientState.Objects.Types.GameObject? GetOwnedObject(uint id)
|
||||
private Actor GetOwnedObject(uint id)
|
||||
{
|
||||
var owner = _objects.SearchById(id);
|
||||
if (owner == null)
|
||||
return null;
|
||||
|
||||
var idx = ((GameObject*)owner.Address)->ObjectIndex;
|
||||
return _objects[idx + 1];
|
||||
var owner = _objects.ById(id);
|
||||
return !owner.Valid
|
||||
? Actor.Null
|
||||
: _objects[owner.Index.Index + 1];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ using Dalamud.Plugin.Services;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.CrashHandler;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Services;
|
||||
|
||||
|
|
@ -19,11 +19,11 @@ public sealed unsafe class LoadTimelineResources : FastHook<LoadTimelineResource
|
|||
private readonly GameState _state;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly ICondition _conditions;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CrashHandlerService _crashHandler;
|
||||
|
||||
public LoadTimelineResources(HookManager hooks, GameState state, CollectionResolver collectionResolver, ICondition conditions,
|
||||
IObjectTable objects, CrashHandlerService crashHandler)
|
||||
ObjectManager objects, CrashHandlerService crashHandler)
|
||||
{
|
||||
_state = state;
|
||||
_collectionResolver = collectionResolver;
|
||||
|
|
@ -56,7 +56,7 @@ public sealed unsafe class LoadTimelineResources : FastHook<LoadTimelineResource
|
|||
}
|
||||
|
||||
/// <summary> Use timelines vfuncs to obtain the associated game object. </summary>
|
||||
public static ResolveData GetDataFromTimeline(IObjectTable objects, CollectionResolver resolver, nint timeline)
|
||||
public static ResolveData GetDataFromTimeline(ObjectManager objects, CollectionResolver resolver, nint timeline)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -64,10 +64,10 @@ public sealed unsafe class LoadTimelineResources : FastHook<LoadTimelineResource
|
|||
{
|
||||
var getGameObjectIdx = ((delegate* unmanaged<nint, int>**)timeline)[0][Offsets.GetGameObjectIdxVfunc];
|
||||
var idx = getGameObjectIdx(timeline);
|
||||
if (idx >= 0 && idx < objects.Length)
|
||||
if (idx >= 0 && idx < objects.Count)
|
||||
{
|
||||
var obj = (GameObject*)objects.GetObjectAddress(idx);
|
||||
return obj != null ? resolver.IdentifyCollection(obj, true) : ResolveData.Invalid;
|
||||
var obj = objects[idx];
|
||||
return obj.Valid ? resolver.IdentifyCollection(obj.AsObject, true) : ResolveData.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.CrashHandler.Buffers;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -13,10 +13,10 @@ public sealed unsafe class ScheduleClipUpdate : FastHook<ScheduleClipUpdate.Dele
|
|||
{
|
||||
private readonly GameState _state;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CrashHandlerService _crashHandler;
|
||||
|
||||
public ScheduleClipUpdate(HookManager hooks, GameState state, CollectionResolver collectionResolver, IObjectTable objects,
|
||||
public ScheduleClipUpdate(HookManager hooks, GameState state, CollectionResolver collectionResolver, ObjectManager objects,
|
||||
CrashHandlerService crashHandler)
|
||||
{
|
||||
_state = state;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.CrashHandler.Buffers;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Services;
|
||||
|
||||
|
|
@ -13,10 +12,10 @@ public sealed unsafe class SomePapLoad : FastHook<SomePapLoad.Delegate>
|
|||
{
|
||||
private readonly GameState _state;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CrashHandlerService _crashHandler;
|
||||
|
||||
public SomePapLoad(HookManager hooks, GameState state, CollectionResolver collectionResolver, IObjectTable objects,
|
||||
public SomePapLoad(HookManager hooks, GameState state, CollectionResolver collectionResolver, ObjectManager objects,
|
||||
CrashHandlerService crashHandler)
|
||||
{
|
||||
_state = state;
|
||||
|
|
@ -36,9 +35,9 @@ public sealed unsafe class SomePapLoad : FastHook<SomePapLoad.Delegate>
|
|||
if (timelinePtr != nint.Zero)
|
||||
{
|
||||
var actorIdx = (int)(*(*(ulong**)timelinePtr + 1) >> 3);
|
||||
if (actorIdx >= 0 && actorIdx < _objects.Length)
|
||||
if (actorIdx >= 0 && actorIdx < _objects.Count)
|
||||
{
|
||||
var newData = _collectionResolver.IdentifyCollection((GameObject*)_objects.GetObjectAddress(actorIdx), true);
|
||||
var newData = _collectionResolver.IdentifyCollection(_objects[actorIdx].AsObject, true);
|
||||
var last = _state.SetAnimationData(newData);
|
||||
_crashHandler.LogAnimation(newData.AssociatedGameObject, newData.ModCollection, AnimationInvocationType.PapLoad);
|
||||
Task.Result.Original(a1, a2, a3, a4);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.SafeHandles;
|
||||
|
||||
namespace Penumbra.Interop.MaterialPreview;
|
||||
|
|
@ -20,7 +21,7 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
|
|||
|
||||
public Half[] ColorTable { get; }
|
||||
|
||||
public LiveColorTablePreviewer(IObjectTable objects, IFramework framework, MaterialInfo materialInfo)
|
||||
public LiveColorTablePreviewer(ObjectManager objects, IFramework framework, MaterialInfo materialInfo)
|
||||
: base(objects, materialInfo)
|
||||
{
|
||||
_framework = framework;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.MaterialPreview;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ public sealed unsafe class LiveMaterialPreviewer : LiveMaterialPreviewerBase
|
|||
private readonly float[] _originalMaterialParameter;
|
||||
private readonly uint[] _originalSamplerFlags;
|
||||
|
||||
public LiveMaterialPreviewer(IObjectTable objects, MaterialInfo materialInfo)
|
||||
public LiveMaterialPreviewer(ObjectManager objects, MaterialInfo materialInfo)
|
||||
: base(objects, materialInfo)
|
||||
{
|
||||
var mtrlHandle = Material->MaterialResourceHandle;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.MaterialPreview;
|
||||
|
||||
public abstract unsafe class LiveMaterialPreviewerBase : IDisposable
|
||||
{
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
|
||||
public readonly MaterialInfo MaterialInfo;
|
||||
public readonly CharacterBase* DrawObject;
|
||||
|
|
@ -14,7 +15,7 @@ public abstract unsafe class LiveMaterialPreviewerBase : IDisposable
|
|||
|
||||
protected bool Valid;
|
||||
|
||||
public LiveMaterialPreviewerBase(IObjectTable objects, MaterialInfo materialInfo)
|
||||
public LiveMaterialPreviewerBase(ObjectManager objects, MaterialInfo materialInfo)
|
||||
{
|
||||
_objects = objects;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.ResourceTree;
|
||||
using Penumbra.String;
|
||||
using Model = Penumbra.GameData.Interop.Model;
|
||||
|
||||
namespace Penumbra.Interop.MaterialPreview;
|
||||
|
||||
|
|
@ -18,13 +19,13 @@ public enum DrawObjectType
|
|||
|
||||
public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectType Type, int ModelSlot, int MaterialSlot)
|
||||
{
|
||||
public nint GetCharacter(IObjectTable objects)
|
||||
=> objects.GetObjectAddress(ObjectIndex.Index);
|
||||
public Actor GetCharacter(ObjectManager objects)
|
||||
=> objects[ObjectIndex];
|
||||
|
||||
public nint GetDrawObject(nint address)
|
||||
public nint GetDrawObject(Actor address)
|
||||
=> GetDrawObject(Type, address);
|
||||
|
||||
public unsafe Material* GetDrawObjectMaterial(IObjectTable objects)
|
||||
public unsafe Material* GetDrawObjectMaterial(ObjectManager objects)
|
||||
=> GetDrawObjectMaterial((CharacterBase*)GetDrawObject(GetCharacter(objects)));
|
||||
|
||||
public unsafe Material* GetDrawObjectMaterial(CharacterBase* drawObject)
|
||||
|
|
@ -60,13 +61,13 @@ public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectTy
|
|||
|
||||
foreach (var type in Enum.GetValues<DrawObjectType>())
|
||||
{
|
||||
var drawObject = (CharacterBase*)GetDrawObject(type, objectPtr);
|
||||
if (drawObject == null)
|
||||
var drawObject = GetDrawObject(type, objectPtr);
|
||||
if (!drawObject.Valid)
|
||||
continue;
|
||||
|
||||
for (var i = 0; i < drawObject->SlotCount; ++i)
|
||||
for (var i = 0; i < drawObject.AsCharacterBase->SlotCount; ++i)
|
||||
{
|
||||
var model = drawObject->Models[i];
|
||||
var model = drawObject.AsCharacterBase->Models[i];
|
||||
if (model == null)
|
||||
continue;
|
||||
|
||||
|
|
@ -88,19 +89,18 @@ public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectTy
|
|||
return result;
|
||||
}
|
||||
|
||||
private static unsafe nint GetDrawObject(DrawObjectType type, nint address)
|
||||
private static unsafe Model GetDrawObject(DrawObjectType type, Actor address)
|
||||
{
|
||||
var gameObject = (Character*)address;
|
||||
if (gameObject == null)
|
||||
return nint.Zero;
|
||||
if (!address.Valid)
|
||||
return Model.Null;
|
||||
|
||||
return type switch
|
||||
{
|
||||
DrawObjectType.Character => (nint)gameObject->GameObject.GetDrawObject(),
|
||||
DrawObjectType.Mainhand => (nint)gameObject->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).DrawObject,
|
||||
DrawObjectType.Offhand => (nint)gameObject->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject,
|
||||
DrawObjectType.Vfx => (nint)gameObject->DrawData.Weapon(DrawDataContainer.WeaponSlot.Unk).DrawObject,
|
||||
_ => nint.Zero,
|
||||
DrawObjectType.Character => address.Model,
|
||||
DrawObjectType.Mainhand => address.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).DrawObject,
|
||||
DrawObjectType.Offhand => address.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject,
|
||||
DrawObjectType.Vfx => address.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.Unk).DrawObject,
|
||||
_ => Model.Null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Penumbra.Collections.Manager;
|
|||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Util;
|
||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||
|
|
@ -170,10 +171,10 @@ public sealed unsafe class CollectionResolver(
|
|||
: null;
|
||||
|
||||
/// <summary> Check for the Yourself collection. </summary>
|
||||
private ModCollection? CheckYourself(ActorIdentifier identifier, GameObject* actor)
|
||||
private ModCollection? CheckYourself(ActorIdentifier identifier, Actor actor)
|
||||
{
|
||||
if (actor->ObjectIndex == 0
|
||||
|| cutscenes.GetParentIndex(actor->ObjectIndex) == 0
|
||||
if (actor.Index == 0
|
||||
|| cutscenes.GetParentIndex(actor.Index.Index) == 0
|
||||
|| identifier.Equals(actors.GetCurrentPlayer()))
|
||||
return collectionManager.Active.ByType(CollectionType.Yourself);
|
||||
|
||||
|
|
@ -181,23 +182,23 @@ public sealed unsafe class CollectionResolver(
|
|||
}
|
||||
|
||||
/// <summary> Check special collections given the actor. Returns notYetReady if the customize array is not filled. </summary>
|
||||
private ModCollection? CollectionByAttributes(GameObject* actor, ref bool notYetReady)
|
||||
private ModCollection? CollectionByAttributes(Actor actor, ref bool notYetReady)
|
||||
{
|
||||
if (!actor->IsCharacter())
|
||||
if (!actor.IsCharacter)
|
||||
return null;
|
||||
|
||||
// Only handle human models.
|
||||
var character = (Character*)actor;
|
||||
if (!IsModelHuman((uint)character->CharacterData.ModelCharaId))
|
||||
|
||||
if (!IsModelHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
|
||||
return null;
|
||||
|
||||
if (character->DrawData.CustomizeData[0] == 0)
|
||||
if (actor.Customize->Data[0] == 0)
|
||||
{
|
||||
notYetReady = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
var bodyType = character->DrawData.CustomizeData[2];
|
||||
var bodyType = actor.Customize->Data[2];
|
||||
var collection = bodyType switch
|
||||
{
|
||||
3 => collectionManager.Active.ByType(CollectionType.NonPlayerElderly),
|
||||
|
|
@ -207,9 +208,9 @@ public sealed unsafe class CollectionResolver(
|
|||
if (collection != null)
|
||||
return collection;
|
||||
|
||||
var race = (SubRace)character->DrawData.CustomizeData[4];
|
||||
var gender = (Gender)(character->DrawData.CustomizeData[1] + 1);
|
||||
var isNpc = actor->ObjectKind != (byte)ObjectKind.Player;
|
||||
var race = (SubRace)actor.Customize->Data[4];
|
||||
var gender = (Gender)(actor.Customize->Data[1] + 1);
|
||||
var isNpc = !actor.IsPlayer;
|
||||
|
||||
var type = CollectionTypeExtensions.FromParts(race, gender, isNpc);
|
||||
collection = collectionManager.Active.ByType(type);
|
||||
|
|
@ -218,15 +219,14 @@ public sealed unsafe class CollectionResolver(
|
|||
}
|
||||
|
||||
/// <summary> Get the collection applying to the owner if it is available. </summary>
|
||||
private ModCollection? CheckOwnedCollection(ActorIdentifier identifier, GameObject* owner, ref bool notYetReady)
|
||||
private ModCollection? CheckOwnedCollection(ActorIdentifier identifier, Actor owner, ref bool notYetReady)
|
||||
{
|
||||
if (identifier.Type != IdentifierType.Owned || !config.UseOwnerNameForCharacterCollection || owner == null)
|
||||
if (identifier.Type != IdentifierType.Owned || !config.UseOwnerNameForCharacterCollection || !owner.Valid)
|
||||
return null;
|
||||
|
||||
var id = actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id,
|
||||
ObjectKind.None,
|
||||
uint.MaxValue);
|
||||
return CheckYourself(id, owner)
|
||||
?? CollectionByAttributes(owner, ref notYetReady);
|
||||
return CheckYourself(id, owner) ?? CollectionByAttributes(owner, ref notYetReady);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
using Penumbra.String;
|
||||
|
||||
|
|
@ -14,17 +15,17 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
public const int CutsceneEndIdx = (int)ScreenActor.CutsceneEnd;
|
||||
public const int CutsceneSlots = CutsceneEndIdx - CutsceneStartIdx;
|
||||
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CopyCharacter _copyCharacter;
|
||||
private readonly CharacterDestructor _characterDestructor;
|
||||
private readonly short[] _copiedCharacters = Enumerable.Repeat((short)-1, CutsceneSlots).ToArray();
|
||||
|
||||
public IEnumerable<KeyValuePair<int, Dalamud.Game.ClientState.Objects.Types.GameObject>> Actors
|
||||
=> Enumerable.Range(CutsceneStartIdx, CutsceneSlots)
|
||||
.Where(i => _objects[i] != null)
|
||||
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!));
|
||||
.Where(i => _objects[i].Valid)
|
||||
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects.GetDalamudObject(i)!));
|
||||
|
||||
public unsafe CutsceneService(IObjectTable objects, CopyCharacter copyCharacter, CharacterDestructor characterDestructor,
|
||||
public unsafe CutsceneService(ObjectManager objects, CopyCharacter copyCharacter, CharacterDestructor characterDestructor,
|
||||
IClientState clientState)
|
||||
{
|
||||
_objects = objects;
|
||||
|
|
@ -42,13 +43,13 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
/// Does not check for valid input index.
|
||||
/// Returns null if no connected actor is set or the actor does not exist anymore.
|
||||
/// </summary>
|
||||
public Dalamud.Game.ClientState.Objects.Types.GameObject? this[int idx]
|
||||
private Dalamud.Game.ClientState.Objects.Types.GameObject? this[int idx]
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(idx is >= CutsceneStartIdx and < CutsceneEndIdx);
|
||||
idx = _copiedCharacters[idx - CutsceneStartIdx];
|
||||
return idx < 0 ? null : _objects[idx];
|
||||
return idx < 0 ? null : _objects.GetDalamudObject(idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,10 +65,10 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
if (parentIdx is < -1 or >= CutsceneEndIdx)
|
||||
return false;
|
||||
|
||||
if (_objects.GetObjectAddress(copyIdx) == nint.Zero)
|
||||
if (!_objects[copyIdx].Valid)
|
||||
return false;
|
||||
|
||||
if (parentIdx != -1 && _objects.GetObjectAddress(parentIdx) == nint.Zero)
|
||||
if (parentIdx != -1 && !_objects[parentIdx].Valid)
|
||||
return false;
|
||||
|
||||
_copiedCharacters[copyIdx - CutsceneStartIdx] = (short)parentIdx;
|
||||
|
|
@ -99,9 +100,9 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
{
|
||||
// A hack to deal with GPose actors leaving and thus losing the link, we just set the home world instead.
|
||||
// I do not think this breaks anything?
|
||||
var address = (GameObject*)_objects.GetObjectAddress(i + CutsceneStartIdx);
|
||||
if (address != null && address->GetObjectKind() is (byte)ObjectKind.Pc)
|
||||
((Character*)address)->HomeWorld = character->HomeWorld;
|
||||
var address = _objects[i + CutsceneStartIdx];
|
||||
if (address.IsPlayer)
|
||||
address.AsCharacter->HomeWorld = character->HomeWorld;
|
||||
|
||||
_copiedCharacters[i] = -1;
|
||||
}
|
||||
|
|
@ -125,7 +126,7 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
|
||||
/// <summary> Try to recover GPose actors on reloads into a running game. </summary>
|
||||
/// <remarks> This is not 100% accurate due to world IDs, minions etc., but will be mostly sane. </remarks>
|
||||
private unsafe void RecoverGPoseActors()
|
||||
private void RecoverGPoseActors()
|
||||
{
|
||||
Dictionary<ByteString, short>? actors = null;
|
||||
|
||||
|
|
@ -143,11 +144,11 @@ public sealed class CutsceneService : IService, IDisposable
|
|||
bool TryGetName(int idx, out ByteString name)
|
||||
{
|
||||
name = ByteString.Empty;
|
||||
var address = (GameObject*)_objects.GetObjectAddress(idx);
|
||||
if (address == null)
|
||||
var address = _objects[idx];
|
||||
if (!address.Valid)
|
||||
return false;
|
||||
|
||||
name = new ByteString(address->Name);
|
||||
name = address.Utf8Name;
|
||||
return !name.IsEmpty;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
|
|
@ -11,7 +10,7 @@ namespace Penumbra.Interop.PathResolving;
|
|||
|
||||
public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<nint, (nint, bool)>, IService
|
||||
{
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CreateCharacterBase _createCharacterBase;
|
||||
private readonly WeaponReload _weaponReload;
|
||||
private readonly CharacterBaseDestructor _characterBaseDestructor;
|
||||
|
|
@ -22,7 +21,7 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<nint, (ni
|
|||
public nint LastGameObject
|
||||
=> _gameState.LastGameObject;
|
||||
|
||||
public unsafe DrawObjectState(IObjectTable objects, CreateCharacterBase createCharacterBase, WeaponReload weaponReload,
|
||||
public unsafe DrawObjectState(ObjectManager objects, CreateCharacterBase createCharacterBase, WeaponReload weaponReload,
|
||||
CharacterBaseDestructor characterBaseDestructor, GameState gameState)
|
||||
{
|
||||
_objects = objects;
|
||||
|
|
@ -95,11 +94,11 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<nint, (ni
|
|||
/// </summary>
|
||||
private unsafe void InitializeDrawObjects()
|
||||
{
|
||||
for (var i = 0; i < _objects.Length; ++i)
|
||||
for (var i = 0; i < _objects.Count; ++i)
|
||||
{
|
||||
var ptr = (GameObject*)_objects.GetObjectAddress(i);
|
||||
if (ptr != null && ptr->IsCharacter() && ptr->DrawObject != null)
|
||||
IterateDrawObjectTree(&ptr->DrawObject->Object, (nint)ptr, false, false);
|
||||
var ptr = _objects[i];
|
||||
if (ptr is { IsCharacter: true, Model.Valid: true })
|
||||
IterateDrawObjectTree((Object*)ptr.Model.Address, ptr, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +1,26 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
public class ResourceTreeFactory
|
||||
public class ResourceTreeFactory(
|
||||
IDataManager gameData,
|
||||
ObjectManager objects,
|
||||
CollectionResolver resolver,
|
||||
ObjectIdentification identifier,
|
||||
Configuration config,
|
||||
ActorManager actors,
|
||||
PathState pathState)
|
||||
{
|
||||
private readonly IDataManager _gameData;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
private readonly Configuration _config;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly PathState _pathState;
|
||||
|
||||
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, ObjectIdentification identifier,
|
||||
Configuration config, ActorManager actors, PathState pathState)
|
||||
{
|
||||
_gameData = gameData;
|
||||
_objects = objects;
|
||||
_collectionResolver = resolver;
|
||||
_identifier = identifier;
|
||||
_config = config;
|
||||
_actors = actors;
|
||||
_pathState = pathState;
|
||||
}
|
||||
|
||||
private TreeBuildCache CreateTreeBuildCache()
|
||||
=> new(_objects, _gameData, _actors);
|
||||
=> new(objects, gameData, actors);
|
||||
|
||||
public IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> GetLocalPlayerRelatedCharacters()
|
||||
{
|
||||
|
|
@ -80,7 +67,7 @@ public class ResourceTreeFactory
|
|||
if (drawObjStruct == null)
|
||||
return null;
|
||||
|
||||
var collectionResolveData = _collectionResolver.IdentifyCollection(gameObjStruct, true);
|
||||
var collectionResolveData = resolver.IdentifyCollection(gameObjStruct, true);
|
||||
if (!collectionResolveData.Valid)
|
||||
return null;
|
||||
|
||||
|
|
@ -89,9 +76,9 @@ public class ResourceTreeFactory
|
|||
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
||||
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
|
||||
networked, collectionResolveData.ModCollection.Name);
|
||||
var globalContext = new GlobalResolveContext(_identifier, collectionResolveData.ModCollection,
|
||||
var globalContext = new GlobalResolveContext(identifier, collectionResolveData.ModCollection,
|
||||
cache, (flags & Flags.WithUiData) != 0);
|
||||
using (var _ = _pathState.EnterInternalResolve())
|
||||
using (var _ = pathState.EnterInternalResolve())
|
||||
{
|
||||
tree.LoadResources(globalContext);
|
||||
}
|
||||
|
|
@ -103,56 +90,12 @@ public class ResourceTreeFactory
|
|||
// ResolveGamePaths(tree, collectionResolveData.ModCollection);
|
||||
if (globalContext.WithUiData)
|
||||
ResolveUiData(tree);
|
||||
FilterFullPaths(tree, (flags & Flags.RedactExternalPaths) != 0 ? _config.ModDirectory : null);
|
||||
FilterFullPaths(tree, (flags & Flags.RedactExternalPaths) != 0 ? config.ModDirectory : null);
|
||||
Cleanup(tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static void ResolveGamePaths(ResourceTree tree, ModCollection collection)
|
||||
{
|
||||
var forwardDictionary = new Dictionary<Utf8GamePath, FullPath?>();
|
||||
var reverseDictionary = new Dictionary<string, HashSet<Utf8GamePath>>();
|
||||
foreach (var node in tree.FlatNodes)
|
||||
{
|
||||
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
||||
reverseDictionary.TryAdd(node.FullPath.ToPath(), null!);
|
||||
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
||||
forwardDictionary.TryAdd(node.GamePath, null);
|
||||
}
|
||||
|
||||
foreach (var key in forwardDictionary.Keys)
|
||||
forwardDictionary[key] = collection.ResolvePath(key);
|
||||
|
||||
var reverseResolvedArray = collection.ReverseResolvePaths(reverseDictionary.Keys);
|
||||
foreach (var (key, set) in reverseDictionary.Keys.Zip(reverseResolvedArray))
|
||||
reverseDictionary[key] = set;
|
||||
|
||||
foreach (var node in tree.FlatNodes)
|
||||
{
|
||||
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
||||
{
|
||||
if (!reverseDictionary.TryGetValue(node.FullPath.ToPath(), out var resolvedSet))
|
||||
continue;
|
||||
|
||||
if (resolvedSet.Count != 1)
|
||||
{
|
||||
Penumbra.Log.Debug(
|
||||
$"Found {resolvedSet.Count} game paths while reverse-resolving {node.FullPath} in {collection.Name}:");
|
||||
foreach (var gamePath in resolvedSet)
|
||||
Penumbra.Log.Debug($"Game path: {gamePath}");
|
||||
}
|
||||
|
||||
node.PossibleGamePaths = resolvedSet.ToArray();
|
||||
}
|
||||
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
||||
{
|
||||
if (forwardDictionary.TryGetValue(node.GamePath, out var resolved))
|
||||
node.FullPath = resolved ?? new FullPath(node.GamePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResolveUiData(ResourceTree tree)
|
||||
{
|
||||
foreach (var node in tree.FlatNodes)
|
||||
|
|
@ -217,12 +160,12 @@ public class ResourceTreeFactory
|
|||
private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character,
|
||||
TreeBuildCache cache)
|
||||
{
|
||||
var identifier = _actors.FromObject((GameObject*)character.Address, out var owner, true, false, false);
|
||||
var identifier = actors.FromObject((GameObject*)character.Address, out var owner, true, false, false);
|
||||
switch (identifier.Type)
|
||||
{
|
||||
case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);
|
||||
case IdentifierType.Owned:
|
||||
var ownerChara = _objects.CreateObjectReference((nint)owner) as Dalamud.Game.ClientState.Objects.Types.Character;
|
||||
var ownerChara = objects.Objects.CreateObjectReference(owner) as Dalamud.Game.ClientState.Objects.Types.Character;
|
||||
if (ownerChara != null)
|
||||
{
|
||||
var ownerName = GetCharacterName(ownerChara, cache);
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@ using Dalamud.Plugin.Services;
|
|||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorManager actors)
|
||||
internal readonly struct TreeBuildCache(ObjectManager objects, IDataManager dataManager, ActorManager actors)
|
||||
{
|
||||
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = [];
|
||||
|
||||
public unsafe bool IsLocalPlayerRelated(Character character)
|
||||
{
|
||||
var player = objects[0];
|
||||
var player = objects.GetDalamudObject(0);
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
|
|
@ -31,30 +31,30 @@ internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataM
|
|||
}
|
||||
|
||||
public IEnumerable<Character> GetCharacters()
|
||||
=> objects.OfType<Character>();
|
||||
=> objects.Objects.OfType<Character>();
|
||||
|
||||
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
|
||||
{
|
||||
var player = objects[0];
|
||||
var player = objects.GetDalamudObject(0);
|
||||
if (player == null)
|
||||
yield break;
|
||||
|
||||
yield return (Character)player;
|
||||
|
||||
var minion = objects[1];
|
||||
var minion = objects.GetDalamudObject(1);
|
||||
if (minion != null)
|
||||
yield return (Character)minion;
|
||||
|
||||
var playerId = player.ObjectId;
|
||||
for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2)
|
||||
{
|
||||
if (objects[i] is Character owned && owned.OwnerId == playerId)
|
||||
if (objects.GetDalamudObject(i) is Character owned && owned.OwnerId == playerId)
|
||||
yield return owned;
|
||||
}
|
||||
|
||||
for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i)
|
||||
{
|
||||
var character = objects[i] as Character;
|
||||
var character = objects.GetDalamudObject((int) i) as Character;
|
||||
if (character == null)
|
||||
continue;
|
||||
|
||||
|
|
@ -62,34 +62,11 @@ internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataM
|
|||
if (parent < 0)
|
||||
continue;
|
||||
|
||||
if (parent is 0 or 1 || objects[parent]?.OwnerId == playerId)
|
||||
if (parent is 0 or 1 || objects.GetDalamudObject(parent)?.OwnerId == playerId)
|
||||
yield return character;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe ByteString GetPlayerName(GameObject player)
|
||||
{
|
||||
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)player.Address;
|
||||
return new ByteString(gameObject->Name);
|
||||
}
|
||||
|
||||
private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character)
|
||||
{
|
||||
character = objects[idx] as Character;
|
||||
if (character == null)
|
||||
return false;
|
||||
|
||||
var actorId = actors.FromObject(character, out var owner, true, true, true);
|
||||
if (!actorId.IsValid)
|
||||
return false;
|
||||
if (owner != null && owner->OwnerID != playerId)
|
||||
return false;
|
||||
if (actorId.Type is not IdentifierType.Player || !actorId.PlayerName.Equals(playerName))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Try to read a shpk file from the given path and cache it on success. </summary>
|
||||
public ShpkFile? ReadShaderPackage(FullPath path)
|
||||
=> ReadFile(dataManager, path, _shaderPackages, bytes => new ShpkFile(bytes));
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using Penumbra.Api.Enums;
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
|
|
@ -57,7 +58,7 @@ public unsafe partial class RedrawService
|
|||
// this will be in obj and true will be returned.
|
||||
private bool FindCorrectActor(int idx, out GameObject? obj)
|
||||
{
|
||||
obj = _objects[idx];
|
||||
obj = _objects.GetDalamudObject(idx);
|
||||
if (!InGPose || obj == null || IsGPoseActor(idx))
|
||||
return false;
|
||||
|
||||
|
|
@ -70,21 +71,21 @@ public unsafe partial class RedrawService
|
|||
|
||||
if (name == gPoseName)
|
||||
{
|
||||
obj = _objects[GPosePlayerIdx + i];
|
||||
obj = _objects.GetDalamudObject(GPosePlayerIdx + i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (; _gPoseNameCounter < GPoseSlots; ++_gPoseNameCounter)
|
||||
{
|
||||
var gPoseName = _objects[GPosePlayerIdx + _gPoseNameCounter]?.Name.ToString();
|
||||
var gPoseName = _objects.GetDalamudObject(GPosePlayerIdx + _gPoseNameCounter)?.Name.ToString();
|
||||
_gPoseNames[_gPoseNameCounter] = gPoseName;
|
||||
if (gPoseName == null)
|
||||
break;
|
||||
|
||||
if (name == gPoseName)
|
||||
{
|
||||
obj = _objects[GPosePlayerIdx + _gPoseNameCounter];
|
||||
obj = _objects.GetDalamudObject(GPosePlayerIdx + _gPoseNameCounter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
private const int FurnitureIdx = 1337;
|
||||
|
||||
private readonly IFramework _framework;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly ITargetManager _targets;
|
||||
private readonly ICondition _conditions;
|
||||
private readonly IClientState _clientState;
|
||||
|
|
@ -133,7 +134,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
|
||||
public event GameObjectRedrawnDelegate? GameObjectRedrawn;
|
||||
|
||||
public RedrawService(IFramework framework, IObjectTable objects, ITargetManager targets, ICondition conditions, IClientState clientState,
|
||||
public RedrawService(IFramework framework, ObjectManager objects, ITargetManager targets, ICondition conditions, IClientState clientState,
|
||||
Configuration config, CommunicatorService communicator)
|
||||
{
|
||||
_framework = framework;
|
||||
|
|
@ -170,7 +171,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
if (gPose)
|
||||
DisableDraw(actor!);
|
||||
|
||||
if (actor is PlayerCharacter && _objects[tableIndex + 1] is { ObjectKind: ObjectKind.MountType or ObjectKind.Ornament } mountOrOrnament)
|
||||
if (actor is PlayerCharacter && _objects.GetDalamudObject(tableIndex + 1) is { ObjectKind: ObjectKind.MountType or ObjectKind.Ornament } mountOrOrnament)
|
||||
{
|
||||
*ActorDrawState(mountOrOrnament) |= DrawState.Invisibility;
|
||||
if (gPose)
|
||||
|
|
@ -189,7 +190,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
if (gPose)
|
||||
EnableDraw(actor!);
|
||||
|
||||
if (actor is PlayerCharacter && _objects[tableIndex + 1] is { ObjectKind: ObjectKind.MountType or ObjectKind.Ornament } mountOrOrnament)
|
||||
if (actor is PlayerCharacter && _objects.GetDalamudObject(tableIndex + 1) is { ObjectKind: ObjectKind.MountType or ObjectKind.Ornament } mountOrOrnament)
|
||||
{
|
||||
*ActorDrawState(mountOrOrnament) &= ~DrawState.Invisibility;
|
||||
if (gPose)
|
||||
|
|
@ -212,7 +213,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
|
||||
private void ReloadActorAfterGPose(GameObject? actor)
|
||||
{
|
||||
if (_objects[GPosePlayerIdx] != null)
|
||||
if (_objects[GPosePlayerIdx].Valid)
|
||||
{
|
||||
ReloadActor(actor);
|
||||
return;
|
||||
|
|
@ -230,7 +231,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
if (_target < 0)
|
||||
return;
|
||||
|
||||
var actor = _objects[_target];
|
||||
var actor = _objects.GetDalamudObject(_target);
|
||||
if (actor == null || _targets.Target != null)
|
||||
return;
|
||||
|
||||
|
|
@ -316,12 +317,12 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
if (idx < 0)
|
||||
{
|
||||
var newIdx = ~idx;
|
||||
WriteInvisible(_objects[newIdx]);
|
||||
WriteInvisible(_objects.GetDalamudObject(newIdx));
|
||||
_afterGPoseQueue[numKept++] = newIdx;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteVisible(_objects[idx]);
|
||||
WriteVisible(_objects.GetDalamudObject(idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,8 +358,8 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
|
||||
private GameObject? GetLocalPlayer()
|
||||
{
|
||||
var gPosePlayer = _objects[GPosePlayerIdx];
|
||||
return gPosePlayer ?? _objects[0];
|
||||
var gPosePlayer = _objects.GetDalamudObject(GPosePlayerIdx);
|
||||
return gPosePlayer ?? _objects.GetDalamudObject(0);
|
||||
}
|
||||
|
||||
public bool GetName(string lowerName, out GameObject? actor)
|
||||
|
|
@ -379,7 +380,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
if (!ret && lowerName.Length > 1 && lowerName[0] == '#' && ushort.TryParse(lowerName[1..], out var objectIndex))
|
||||
{
|
||||
ret = true;
|
||||
actor = _objects[objectIndex];
|
||||
actor = _objects.GetDalamudObject((int) objectIndex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -387,8 +388,8 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
|
||||
public void RedrawObject(int tableIndex, RedrawType settings)
|
||||
{
|
||||
if (tableIndex >= 0 && tableIndex < _objects.Length)
|
||||
RedrawObject(_objects[tableIndex], settings);
|
||||
if (tableIndex >= 0 && tableIndex < _objects.Count)
|
||||
RedrawObject(_objects.GetDalamudObject(tableIndex), settings);
|
||||
}
|
||||
|
||||
public void RedrawObject(string name, RedrawType settings)
|
||||
|
|
@ -399,13 +400,13 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
else if (GetName(lowerName, out var target))
|
||||
RedrawObject(target, settings);
|
||||
else
|
||||
foreach (var actor in _objects.Where(a => a.Name.ToString().ToLowerInvariant() == lowerName))
|
||||
foreach (var actor in _objects.Objects.Where(a => a.Name.ToString().ToLowerInvariant() == lowerName))
|
||||
RedrawObject(actor, settings);
|
||||
}
|
||||
|
||||
public void RedrawAll(RedrawType settings)
|
||||
{
|
||||
foreach (var actor in _objects)
|
||||
foreach (var actor in _objects.Objects)
|
||||
RedrawObject(actor, settings);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Penumbra.Collections.Manager;
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Import.Models;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
|
|
@ -46,7 +47,7 @@ public partial class ModEditWindow : Window, IDisposable
|
|||
private readonly IDragDropManager _dragDropManager;
|
||||
private readonly IDataManager _gameData;
|
||||
private readonly IFramework _framework;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CharacterBaseDestructor _characterBaseDestructor;
|
||||
|
||||
private Vector2 _iconSize = Vector2.Zero;
|
||||
|
|
@ -446,7 +447,7 @@ public partial class ModEditWindow : Window, IDisposable
|
|||
|
||||
DrawOptionSelectHeader();
|
||||
|
||||
var setsEqual = !_editor!.SwapEditor.Changes;
|
||||
var setsEqual = !_editor.SwapEditor.Changes;
|
||||
var tt = setsEqual ? "No changes staged." : "Apply the currently staged changes to the option.";
|
||||
ImGui.NewLine();
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply Changes", Vector2.Zero, tt, setsEqual))
|
||||
|
|
@ -577,7 +578,7 @@ public partial class ModEditWindow : Window, IDisposable
|
|||
Configuration config, ModEditor editor, ResourceTreeFactory resourceTreeFactory, MetaFileManager metaFileManager,
|
||||
StainService stainService, ActiveCollections activeCollections, ModMergeTab modMergeTab,
|
||||
CommunicatorService communicator, TextureManager textures, ModelManager models, IDragDropManager dragDropManager,
|
||||
ChangedItemDrawer changedItemDrawer, IObjectTable objects, IFramework framework, CharacterBaseDestructor characterBaseDestructor)
|
||||
ChangedItemDrawer changedItemDrawer, ObjectManager objects, IFramework framework, CharacterBaseDestructor characterBaseDestructor)
|
||||
: base(WindowBaseLabel)
|
||||
{
|
||||
_performance = performance;
|
||||
|
|
|
|||
|
|
@ -71,8 +71,7 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>
|
|||
foreach (var (tag, data) in tags)
|
||||
_predefinedTags.TryAdd(tag, data);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Invalid version {version}.");
|
||||
default: throw new Exception($"Invalid version {version}.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ using Penumbra.Collections.Manager;
|
|||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Import.Structs;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
|
|
@ -90,12 +91,12 @@ public class DebugTab : Window, ITab
|
|||
private readonly RedrawService _redraws;
|
||||
private readonly DictEmote _emotes;
|
||||
private readonly Diagnostics _diagnostics;
|
||||
private readonly IObjectTable _objects;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IpcTester _ipcTester;
|
||||
private readonly CrashHandlerPanel _crashHandlerPanel;
|
||||
|
||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, IObjectTable objects,
|
||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
||||
IClientState clientState,
|
||||
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors, StainService stains,
|
||||
CharacterUtility characterUtility, ResidentResourceManager residentResources,
|
||||
|
|
@ -430,7 +431,7 @@ public class DebugTab : Window, ITab
|
|||
DrawSpecial("Current Card", _actors.GetCardPlayer());
|
||||
DrawSpecial("Current Glamour", _actors.GetGlamourPlayer());
|
||||
|
||||
foreach (var obj in _objects)
|
||||
foreach (var obj in _objects.Objects)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn($"{((GameObject*)obj.Address)->ObjectIndex}");
|
||||
ImGuiUtil.DrawTableColumn($"0x{obj.Address:X}");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ using Penumbra.Mods.Manager;
|
|||
using Penumbra.UI.ModsTab;
|
||||
using ModFileSystemSelector = Penumbra.UI.ModsTab.ModFileSystemSelector;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.UI.Tabs;
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ public class ModsTab(
|
|||
IClientState clientState,
|
||||
CollectionSelectHeader collectionHeader,
|
||||
ITargetManager targets,
|
||||
IObjectTable objectTable)
|
||||
ObjectManager objects)
|
||||
: ITab
|
||||
{
|
||||
private readonly ActiveCollections _activeCollections = collectionManager.Active;
|
||||
|
|
@ -128,7 +129,7 @@ public class ModsTab(
|
|||
using var disabled = ImRaii.Disabled(clientState.LocalPlayer == null);
|
||||
ImGui.SameLine();
|
||||
var buttonWidth = frameHeight with { X = ImGui.GetContentRegionAvail().X / 5 };
|
||||
var tt = objectTable.GetObjectAddress(0) == nint.Zero
|
||||
var tt = !objects[0].Valid
|
||||
? "\nCan only be used when you are logged in and your character is available."
|
||||
: string.Empty;
|
||||
DrawButton(buttonWidth, "All", string.Empty, tt);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue