mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add handling for cached TMBs.
This commit is contained in:
parent
f679e0ccee
commit
b3883c1306
9 changed files with 415 additions and 40 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit ffc149cc8c169c2c6e838cbd138676f6fe4daeea
|
||||
Subproject commit 19355cfa0ec80e8d5a91de11ecffc49257b37b53
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
|
|
@ -33,5 +32,8 @@ public sealed class ResolvedFileChanged()
|
|||
{
|
||||
/// <seealso cref="Api.DalamudSubstitutionProvider.OnResolvedFileChange"/>
|
||||
DalamudSubstitutionProvider = 0,
|
||||
|
||||
/// <seealso cref="Interop.Services.SchedulerResourceManagementService.OnResolvedFileChange"/>
|
||||
SchedulerResourceManagementService = 0,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ public class GameState : IService
|
|||
public void RestoreAnimationData(ResolveData old)
|
||||
=> _animationLoadData.Value = old;
|
||||
|
||||
public readonly ThreadLocal<bool> InLoadActionTmb = new(() => false);
|
||||
public readonly ThreadLocal<bool> SkipTmbCache = new(() => false);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sound Data
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
|
||||
using JetBrains.Annotations;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Animation;
|
||||
|
||||
/// <summary> Load a cached TMB resource from SchedulerResourceManagement. </summary>
|
||||
public sealed unsafe class GetCachedScheduleResource : FastHook<GetCachedScheduleResource.Delegate>
|
||||
{
|
||||
private readonly GameState _state;
|
||||
|
||||
public GetCachedScheduleResource(HookManager hooks, GameState state)
|
||||
{
|
||||
_state = state;
|
||||
Task = hooks.CreateHook<Delegate>("Get Cached Schedule Resource", Sigs.GetCachedScheduleResource, Detour,
|
||||
!HookOverrides.Instance.Animation.GetCachedScheduleResource);
|
||||
}
|
||||
|
||||
public delegate SchedulerResource* Delegate(SchedulerResourceManagement* a, ScheduleResourceLoadData* b, byte useMap);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private SchedulerResource* Detour(SchedulerResourceManagement* a, ScheduleResourceLoadData* b, byte c)
|
||||
{
|
||||
if (_state.SkipTmbCache.Value)
|
||||
{
|
||||
Penumbra.Log.Verbose(
|
||||
$"[GetCachedScheduleResource] Called with 0x{(ulong)a:X}, {b->Id}, {new CiByteString(b->Path, MetaDataComputation.None)}, {c} from LoadActionTmb with forced skipping of cache, returning NULL.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret = Task.Result.Original(a, b, c);
|
||||
Penumbra.Log.Excessive(
|
||||
$"[GetCachedScheduleResource] Called with 0x{(ulong)a:X}, {b->Id}, {new CiByteString(b->Path, MetaDataComputation.None)}, {c}, returning 0x{(ulong)ret:X} ({(ret != null && Resource(ret) != null ? Resource(ret)->FileName().ToString() : "No Path")}).");
|
||||
return ret;
|
||||
}
|
||||
|
||||
public struct ScheduleResourceLoadData
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public byte* Path;
|
||||
|
||||
[UsedImplicitly]
|
||||
public uint Id;
|
||||
}
|
||||
|
||||
|
||||
// #TODO: remove when fixed in CS.
|
||||
public static ResourceHandle* Resource(SchedulerResource* r)
|
||||
=> ((ResourceHandle**)r)[3];
|
||||
}
|
||||
55
Penumbra/Interop/Hooks/Animation/LoadActionTmb.cs
Normal file
55
Penumbra/Interop/Hooks/Animation/LoadActionTmb.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Animation;
|
||||
|
||||
/// <summary> Load a Action TMB. </summary>
|
||||
public sealed unsafe class LoadActionTmb : FastHook<LoadActionTmb.Delegate>
|
||||
{
|
||||
private readonly GameState _state;
|
||||
private readonly SchedulerResourceManagementService _scheduler;
|
||||
|
||||
public LoadActionTmb(HookManager hooks, GameState state, SchedulerResourceManagementService scheduler)
|
||||
{
|
||||
_state = state;
|
||||
_scheduler = scheduler;
|
||||
Task = hooks.CreateHook<Delegate>("Load Action TMB", Sigs.LoadActionTmb, Detour, !HookOverrides.Instance.Animation.LoadActionTmb);
|
||||
}
|
||||
|
||||
public delegate SchedulerResource* Delegate(SchedulerResourceManagement* scheduler,
|
||||
GetCachedScheduleResource.ScheduleResourceLoadData* loadData, nint b, byte c, byte d, byte e);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private SchedulerResource* Detour(SchedulerResourceManagement* scheduler, GetCachedScheduleResource.ScheduleResourceLoadData* loadData,
|
||||
nint b, byte c, byte d, byte e)
|
||||
{
|
||||
_state.InLoadActionTmb.Value = true;
|
||||
SchedulerResource* ret;
|
||||
if (ShouldSkipCache(loadData))
|
||||
{
|
||||
_state.SkipTmbCache.Value = true;
|
||||
ret = Task.Result.Original(scheduler, loadData, b, c, d, 1);
|
||||
Penumbra.Log.Verbose(
|
||||
$"[LoadActionTMB] Called with 0x{(ulong)scheduler:X}, {loadData->Id}, {new CiByteString(loadData->Path, MetaDataComputation.None)}, 0x{b:X}, {c}, {d}, {e}, forced no-cache use, returned 0x{(ulong)ret:X} ({(ret != null && GetCachedScheduleResource.Resource(ret) != null ? GetCachedScheduleResource.Resource(ret)->FileName().ToString() : "No Path")}).");
|
||||
_state.SkipTmbCache.Value = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = Task.Result.Original(scheduler, loadData, b, c, d, e);
|
||||
Penumbra.Log.Excessive(
|
||||
$"[LoadActionTMB] Called with 0x{(ulong)scheduler:X}, {loadData->Id}, {new CiByteString(loadData->Path)}, 0x{b:X}, {c}, {d}, {e}, returned 0x{(ulong)ret:X} ({(ret != null && GetCachedScheduleResource.Resource(ret) != null ? GetCachedScheduleResource.Resource(ret)->FileName().ToString() : "No Path")}).");
|
||||
}
|
||||
|
||||
_state.InLoadActionTmb.Value = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private bool ShouldSkipCache(GetCachedScheduleResource.ScheduleResourceLoadData* loadData)
|
||||
=> _scheduler.Contains(loadData->Id);
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ public class HookOverrides
|
|||
public bool SomeMountAnimation;
|
||||
public bool SomePapLoad;
|
||||
public bool SomeParasolAnimation;
|
||||
public bool GetCachedScheduleResource;
|
||||
public bool LoadActionTmb;
|
||||
}
|
||||
|
||||
public struct MetaHooks
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
using System.Collections.Frozen;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.Services;
|
||||
|
||||
public unsafe class SchedulerResourceManagementService : IService, IDisposable
|
||||
{
|
||||
private static readonly CiByteString TmbExtension = new(".tmb"u8, MetaDataComputation.All);
|
||||
private static readonly CiByteString FolderPrefix = new("chara/action/"u8, MetaDataComputation.All);
|
||||
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly FrozenDictionary<CiByteString, uint> _actionTmbs;
|
||||
|
||||
private readonly ConcurrentDictionary<uint, CiByteString> _listedTmbIds = [];
|
||||
|
||||
public bool Contains(uint tmbId)
|
||||
=> _listedTmbIds.ContainsKey(tmbId);
|
||||
|
||||
public IReadOnlyDictionary<uint, CiByteString> ListedTmbs
|
||||
=> _listedTmbIds;
|
||||
|
||||
public IReadOnlyDictionary<CiByteString, uint> ActionTmbs
|
||||
=> _actionTmbs;
|
||||
|
||||
public SchedulerResourceManagementService(IGameInteropProvider interop, CommunicatorService communicator, IDataManager dataManager)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_actionTmbs = CreateActionTmbs(dataManager);
|
||||
_communicator.ResolvedFileChanged.Subscribe(OnResolvedFileChange, ResolvedFileChanged.Priority.SchedulerResourceManagementService);
|
||||
interop.InitializeFromAttributes(this);
|
||||
}
|
||||
|
||||
private void OnResolvedFileChange(ModCollection collection, ResolvedFileChanged.Type type, Utf8GamePath gamePath, FullPath oldPath,
|
||||
FullPath newPath, IMod? mod)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ResolvedFileChanged.Type.Added:
|
||||
CheckFile(gamePath);
|
||||
return;
|
||||
case ResolvedFileChanged.Type.FullRecomputeFinished:
|
||||
foreach (var path in collection.ResolvedFiles.Keys)
|
||||
CheckFile(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private void CheckFile(Utf8GamePath gamePath)
|
||||
{
|
||||
if (!gamePath.Extension().Equals(TmbExtension))
|
||||
return;
|
||||
|
||||
if (!gamePath.Path.StartsWith(FolderPrefix))
|
||||
return;
|
||||
|
||||
var tmb = gamePath.Path.Substring(FolderPrefix.Length, gamePath.Length - FolderPrefix.Length - TmbExtension.Length).Clone();
|
||||
if (_actionTmbs.TryGetValue(tmb, out var rowId))
|
||||
_listedTmbIds[rowId] = tmb;
|
||||
else
|
||||
Penumbra.Log.Debug($"Action TMB {gamePath} encountered with no corresponding row ID.");
|
||||
}
|
||||
|
||||
[Signature(Sigs.SchedulerResourceManagementInstance, ScanType = ScanType.StaticAddress)]
|
||||
public readonly SchedulerResourceManagement** Address = null;
|
||||
|
||||
public SchedulerResourceManagement* Scheduler
|
||||
=> *Address;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_listedTmbIds.Clear();
|
||||
_communicator.ResolvedFileChanged.Unsubscribe(OnResolvedFileChange);
|
||||
}
|
||||
|
||||
private static FrozenDictionary<CiByteString, uint> CreateActionTmbs(IDataManager dataManager)
|
||||
{
|
||||
var sheet = dataManager.GetExcelSheet<ActionTimeline>();
|
||||
return sheet.Where(row => !row.Key.IsEmpty).DistinctBy(row => row.Key).ToFrozenDictionary(row => new CiByteString(row.Key, MetaDataComputation.All).Clone(), row => row.RowId);
|
||||
}
|
||||
}
|
||||
|
|
@ -69,38 +69,39 @@ public class Diagnostics(ServiceManager provider) : IUiService
|
|||
|
||||
public class DebugTab : Window, ITab, IUiService
|
||||
{
|
||||
private readonly PerformanceTracker _performance;
|
||||
private readonly Configuration _config;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
private readonly HttpApi _httpApi;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly StainService _stains;
|
||||
private readonly GlobalVariablesDrawer _globalVariablesDrawer;
|
||||
private readonly ResourceManagerService _resourceManager;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly DrawObjectState _drawObjectState;
|
||||
private readonly PathState _pathState;
|
||||
private readonly SubfileHelper _subfileHelper;
|
||||
private readonly IdentifiedCollectionCache _identifiedCollectionCache;
|
||||
private readonly CutsceneService _cutsceneService;
|
||||
private readonly ModImportManager _modImporter;
|
||||
private readonly ImportPopup _importPopup;
|
||||
private readonly FrameworkManager _framework;
|
||||
private readonly TextureManager _textureManager;
|
||||
private readonly ShaderReplacementFixer _shaderReplacementFixer;
|
||||
private readonly RedrawService _redraws;
|
||||
private readonly DictEmote _emotes;
|
||||
private readonly Diagnostics _diagnostics;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IDataManager _dataManager;
|
||||
private readonly IpcTester _ipcTester;
|
||||
private readonly CrashHandlerPanel _crashHandlerPanel;
|
||||
private readonly TexHeaderDrawer _texHeaderDrawer;
|
||||
private readonly HookOverrideDrawer _hookOverrides;
|
||||
private readonly RsfService _rsfService;
|
||||
private readonly PerformanceTracker _performance;
|
||||
private readonly Configuration _config;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
private readonly HttpApi _httpApi;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly StainService _stains;
|
||||
private readonly GlobalVariablesDrawer _globalVariablesDrawer;
|
||||
private readonly ResourceManagerService _resourceManager;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly DrawObjectState _drawObjectState;
|
||||
private readonly PathState _pathState;
|
||||
private readonly SubfileHelper _subfileHelper;
|
||||
private readonly IdentifiedCollectionCache _identifiedCollectionCache;
|
||||
private readonly CutsceneService _cutsceneService;
|
||||
private readonly ModImportManager _modImporter;
|
||||
private readonly ImportPopup _importPopup;
|
||||
private readonly FrameworkManager _framework;
|
||||
private readonly TextureManager _textureManager;
|
||||
private readonly ShaderReplacementFixer _shaderReplacementFixer;
|
||||
private readonly RedrawService _redraws;
|
||||
private readonly DictEmote _emotes;
|
||||
private readonly Diagnostics _diagnostics;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IDataManager _dataManager;
|
||||
private readonly IpcTester _ipcTester;
|
||||
private readonly CrashHandlerPanel _crashHandlerPanel;
|
||||
private readonly TexHeaderDrawer _texHeaderDrawer;
|
||||
private readonly HookOverrideDrawer _hookOverrides;
|
||||
private readonly RsfService _rsfService;
|
||||
private readonly SchedulerResourceManagementService _schedulerService;
|
||||
|
||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
||||
IClientState clientState, IDataManager dataManager,
|
||||
|
|
@ -110,7 +111,8 @@ public class DebugTab : Window, ITab, IUiService
|
|||
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
||||
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
|
||||
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
|
||||
HookOverrideDrawer hookOverrides, RsfService rsfService, GlobalVariablesDrawer globalVariablesDrawer)
|
||||
HookOverrideDrawer hookOverrides, RsfService rsfService, GlobalVariablesDrawer globalVariablesDrawer,
|
||||
SchedulerResourceManagementService schedulerService)
|
||||
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
||||
{
|
||||
IsOpen = true;
|
||||
|
|
@ -148,6 +150,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
_hookOverrides = hookOverrides;
|
||||
_rsfService = rsfService;
|
||||
_globalVariablesDrawer = globalVariablesDrawer;
|
||||
_schedulerService = schedulerService;
|
||||
_objects = objects;
|
||||
_clientState = clientState;
|
||||
_dataManager = dataManager;
|
||||
|
|
@ -672,6 +675,22 @@ public class DebugTab : Window, ITab, IUiService
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (var tmbCache = TreeNode("TMB Cache"))
|
||||
{
|
||||
if (tmbCache)
|
||||
{
|
||||
using var table = Table("###TmbTable", 2, ImGuiTableFlags.SizingFixedFit);
|
||||
if (table)
|
||||
{
|
||||
foreach (var (id, name) in _schedulerService.ListedTmbs.OrderBy(kvp => kvp.Key))
|
||||
{
|
||||
ImUtf8.DrawTableColumn($"{id:D6}");
|
||||
ImUtf8.DrawTableColumn(name.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawData()
|
||||
|
|
@ -680,6 +699,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
return;
|
||||
|
||||
DrawEmotes();
|
||||
DrawActionTmbs();
|
||||
DrawStainTemplates();
|
||||
DrawAtch();
|
||||
}
|
||||
|
|
@ -739,6 +759,27 @@ public class DebugTab : Window, ITab, IUiService
|
|||
ImGuiClip.DrawEndDummy(dummy, ImGui.GetTextLineHeightWithSpacing());
|
||||
}
|
||||
|
||||
private void DrawActionTmbs()
|
||||
{
|
||||
using var mainTree = TreeNode("Action TMBs");
|
||||
if (!mainTree)
|
||||
return;
|
||||
|
||||
using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
|
||||
new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing()));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
var dummy = ImGuiClip.ClippedDraw(_schedulerService.ActionTmbs.OrderBy(r => r.Value), skips,
|
||||
p =>
|
||||
{
|
||||
ImUtf8.DrawTableColumn($"{p.Value}");
|
||||
ImUtf8.DrawTableColumn(p.Key.Span);
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(dummy, ImGui.GetTextLineHeightWithSpacing());
|
||||
}
|
||||
|
||||
private void DrawStainTemplates()
|
||||
{
|
||||
using var mainTree = TreeNode("Staining Templates");
|
||||
|
|
|
|||
|
|
@ -1,12 +1,23 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
|
||||
using FFXIVClientStructs.Interop;
|
||||
using FFXIVClientStructs.STD;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.String;
|
||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||
|
||||
namespace Penumbra.UI.Tabs.Debug;
|
||||
|
||||
public unsafe class GlobalVariablesDrawer(CharacterUtility characterUtility, ResidentResourceManager residentResources) : IUiService
|
||||
public unsafe class GlobalVariablesDrawer(
|
||||
CharacterUtility characterUtility,
|
||||
ResidentResourceManager residentResources,
|
||||
SchedulerResourceManagementService scheduler) : IUiService
|
||||
{
|
||||
/// <summary> Draw information about some game global variables. </summary>
|
||||
public void Draw()
|
||||
|
|
@ -16,13 +27,22 @@ public unsafe class GlobalVariablesDrawer(CharacterUtility characterUtility, Res
|
|||
if (!header)
|
||||
return;
|
||||
|
||||
DebugTab.DrawCopyableAddress("CharacterUtility"u8, characterUtility.Address);
|
||||
DebugTab.DrawCopyableAddress("ResidentResourceManager"u8, residentResources.Address);
|
||||
DebugTab.DrawCopyableAddress("Device"u8, Device.Instance());
|
||||
var actionManager = (ActionTimelineManager**)ActionTimelineManager.Instance();
|
||||
DebugTab.DrawCopyableAddress("CharacterUtility"u8, characterUtility.Address);
|
||||
DebugTab.DrawCopyableAddress("ResidentResourceManager"u8, residentResources.Address);
|
||||
DebugTab.DrawCopyableAddress("ScheduleManagement"u8, ScheduleManagement.Instance());
|
||||
DebugTab.DrawCopyableAddress("ActionTimelineManager*"u8, actionManager);
|
||||
DebugTab.DrawCopyableAddress("ActionTimelineManager"u8, actionManager != null ? *actionManager : null);
|
||||
DebugTab.DrawCopyableAddress("SchedulerResourceManagement*"u8, scheduler.Address);
|
||||
DebugTab.DrawCopyableAddress("SchedulerResourceManagement"u8, scheduler.Address != null ? *scheduler.Address : null);
|
||||
DebugTab.DrawCopyableAddress("Device"u8, Device.Instance());
|
||||
DrawCharacterUtility();
|
||||
DrawResidentResources();
|
||||
DrawSchedulerResourcesMap();
|
||||
DrawSchedulerResourcesList();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Draw information about the character utility class from SE,
|
||||
/// displaying all files, their sizes, the default files and the default sizes.
|
||||
|
|
@ -123,4 +143,111 @@ public unsafe class GlobalVariablesDrawer(CharacterUtility characterUtility, Res
|
|||
ImUtf8.DrawTableColumn(length.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private string _schedulerFilterList = string.Empty;
|
||||
private string _schedulerFilterMap = string.Empty;
|
||||
private CiByteString _schedulerFilterListU8 = CiByteString.Empty;
|
||||
private CiByteString _schedulerFilterMapU8 = CiByteString.Empty;
|
||||
private int _shownResourcesList = 0;
|
||||
private int _shownResourcesMap = 0;
|
||||
|
||||
private void DrawSchedulerResourcesMap()
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode("Scheduler Resources (Map)"u8);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
if (scheduler.Address == null || scheduler.Scheduler == null)
|
||||
return;
|
||||
|
||||
if (ImUtf8.InputText("##SchedulerMapFilter"u8, ref _schedulerFilterMap, "Filter..."u8))
|
||||
_schedulerFilterMapU8 = CiByteString.FromString(_schedulerFilterMap, out var t, MetaDataComputation.All, false)
|
||||
? t
|
||||
: CiByteString.Empty;
|
||||
ImUtf8.Text($"{_shownResourcesMap} / {scheduler.Scheduler->NumResources}");
|
||||
using var table = ImUtf8.Table("##SchedulerMapResources"u8, 10, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
var map = (StdMap<int, Pointer<SchedulerResource>>*)&scheduler.Scheduler->Unknown;
|
||||
var total = 0;
|
||||
_shownResourcesMap = 0;
|
||||
foreach (var (key, resourcePtr) in *map)
|
||||
{
|
||||
var resource = resourcePtr.Value;
|
||||
if (_schedulerFilterMap.Length is 0 || resource->Name.Buffer.IndexOf(_schedulerFilterMapU8.Span) >= 0)
|
||||
{
|
||||
ImUtf8.DrawTableColumn($"[{total:D4}]");
|
||||
ImUtf8.DrawTableColumn($"{resource->Name.Unk1}");
|
||||
ImUtf8.DrawTableColumn(new CiByteString(resource->Name.Buffer, MetaDataComputation.None).Span);
|
||||
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
||||
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
||||
ImGui.TableNextColumn();
|
||||
var resourceHandle = *((ResourceHandle**)resource + 3);
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resourceHandle:X}");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
||||
ImGui.TableNextColumn();
|
||||
uint dataLength = 0;
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource->GetResourceData(&dataLength):X}");
|
||||
ImUtf8.DrawTableColumn($"{dataLength}");
|
||||
++_shownResourcesMap;
|
||||
}
|
||||
|
||||
++total;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSchedulerResourcesList()
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode("Scheduler Resources (List)"u8);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
if (scheduler.Address == null || scheduler.Scheduler == null)
|
||||
return;
|
||||
|
||||
if (ImUtf8.InputText("##SchedulerListFilter"u8, ref _schedulerFilterList, "Filter..."u8))
|
||||
_schedulerFilterListU8 = CiByteString.FromString(_schedulerFilterList, out var t, MetaDataComputation.All, false)
|
||||
? t
|
||||
: CiByteString.Empty;
|
||||
ImUtf8.Text($"{_shownResourcesList} / {scheduler.Scheduler->NumResources}");
|
||||
using var table = ImUtf8.Table("##SchedulerListResources"u8, 10, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
var resource = scheduler.Scheduler->Begin;
|
||||
var total = 0;
|
||||
_shownResourcesList = 0;
|
||||
while (resource != null && total < (int)scheduler.Scheduler->NumResources)
|
||||
{
|
||||
if (_schedulerFilterList.Length is 0 || resource->Name.Buffer.IndexOf(_schedulerFilterListU8.Span) >= 0)
|
||||
{
|
||||
ImUtf8.DrawTableColumn($"[{total:D4}]");
|
||||
ImUtf8.DrawTableColumn($"{resource->Name.Unk1}");
|
||||
ImUtf8.DrawTableColumn(new CiByteString(resource->Name.Buffer, MetaDataComputation.None).Span);
|
||||
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
||||
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
||||
ImGui.TableNextColumn();
|
||||
var resourceHandle = *((ResourceHandle**)resource + 3);
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resourceHandle:X}");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
||||
ImGui.TableNextColumn();
|
||||
uint dataLength = 0;
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource->GetResourceData(&dataLength):X}");
|
||||
ImUtf8.DrawTableColumn($"{dataLength}");
|
||||
++_shownResourcesList;
|
||||
}
|
||||
|
||||
resource = resource->Previous;
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue