diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs
index eb5ab46a..db9c19cb 100644
--- a/Penumbra/Collections/ModCollection.cs
+++ b/Penumbra/Collections/ModCollection.cs
@@ -57,6 +57,7 @@ public partial class ModCollection
public int ChangeCounter { get; private set; }
public uint ImcChangeCounter { get; set; }
+ public uint AtchChangeCounter { get; set; }
/// Increment the number of changes in the effective file list.
public int IncrementCounter()
diff --git a/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs b/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs
index 442bac15..47f96d98 100644
--- a/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs
+++ b/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs
@@ -15,18 +15,18 @@ public unsafe class ResourceLoader : IDisposable, IService
{
private readonly ResourceService _resources;
private readonly FileReadService _fileReadService;
- private readonly TexMdlScdService _texMdlScdService;
+ private readonly RsfService _rsfService;
private readonly PapHandler _papHandler;
private readonly Configuration _config;
private ResolveData _resolvedData = ResolveData.Invalid;
public event Action? PapRequested;
- public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlScdService texMdlScdService, Configuration config)
+ public ResourceLoader(ResourceService resources, FileReadService fileReadService, RsfService rsfService, Configuration config)
{
_resources = resources;
_fileReadService = fileReadService;
- _texMdlScdService = texMdlScdService;
+ _rsfService = rsfService;
_config = config;
ResetResolvePath();
@@ -140,7 +140,7 @@ public unsafe class ResourceLoader : IDisposable, IService
return;
}
- _texMdlScdService.AddCrc(type, resolvedPath);
+ _rsfService.AddCrc(type, resolvedPath);
// Replace the hash and path with the correct one for the replacement.
hash = ComputeHash(resolvedPath.Value.InternalName, parameters);
var oldPath = path;
diff --git a/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs b/Penumbra/Interop/Hooks/ResourceLoading/RsfService.cs
similarity index 96%
rename from Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs
rename to Penumbra/Interop/Hooks/ResourceLoading/RsfService.cs
index b43f1ed5..7ac1563f 100644
--- a/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs
+++ b/Penumbra/Interop/Hooks/ResourceLoading/RsfService.cs
@@ -11,7 +11,7 @@ using TextureResourceHandle = Penumbra.Interop.Structs.TextureResourceHandle;
namespace Penumbra.Interop.Hooks.ResourceLoading;
-public unsafe class TexMdlScdService : IDisposable, IRequiredService
+public unsafe class RsfService : IDisposable, IRequiredService
{
///
/// We need to be able to obtain the requested LoD level.
@@ -43,7 +43,7 @@ public unsafe class TexMdlScdService : IDisposable, IRequiredService
private readonly LodService _lodService;
- public TexMdlScdService(IGameInteropProvider interop)
+ public RsfService(IGameInteropProvider interop)
{
interop.InitializeFromAttributes(this);
_lodService = new LodService(interop);
diff --git a/Penumbra/Interop/PathResolving/PathDataHandler.cs b/Penumbra/Interop/PathResolving/PathDataHandler.cs
index 9410ff98..5439151f 100644
--- a/Penumbra/Interop/PathResolving/PathDataHandler.cs
+++ b/Penumbra/Interop/PathResolving/PathDataHandler.cs
@@ -44,6 +44,11 @@ public static class PathDataHandler
public static FullPath CreateAvfx(CiByteString path, ModCollection collection)
=> CreateBase(path, collection);
+ /// Create the encoding path for an ATCH file.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static FullPath CreateAtch(CiByteString path, ModCollection collection)
+ => new($"|{collection.LocalId.Id}_{collection.AtchChangeCounter}_{DiscriminatorString}|{path}");
+
/// Create the encoding path for a MTRL file.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static FullPath CreateMtrl(CiByteString path, ModCollection collection, Utf8GamePath originalPath)
diff --git a/Penumbra/Interop/Processing/ImcFilePostProcessor.cs b/Penumbra/Interop/Processing/ImcFilePostProcessor.cs
index 33a3941a..a3233cfb 100644
--- a/Penumbra/Interop/Processing/ImcFilePostProcessor.cs
+++ b/Penumbra/Interop/Processing/ImcFilePostProcessor.cs
@@ -1,3 +1,4 @@
+using Dalamud.Game.ClientState.JobGauge.Types;
using Penumbra.Api.Enums;
using Penumbra.Collections.Manager;
using Penumbra.Interop.PathResolving;
@@ -24,7 +25,7 @@ public sealed class ImcFilePostProcessor(CollectionStorage collections) : IFileP
return;
file.Replace(resource);
- Penumbra.Log.Information(
+ Penumbra.Log.Verbose(
$"[ResourceLoader] Loaded {originalGamePath} from file and replaced with IMC from collection {collection.AnonymizedName}.");
}
}
diff --git a/Penumbra/UI/ResourceWatcher/Record.cs b/Penumbra/UI/ResourceWatcher/Record.cs
index b69d9944..7338e5a9 100644
--- a/Penumbra/UI/ResourceWatcher/Record.cs
+++ b/Penumbra/UI/ResourceWatcher/Record.cs
@@ -3,6 +3,7 @@ using Penumbra.Collections;
using Penumbra.Enums;
using Penumbra.Interop.Structs;
using Penumbra.String;
+using Penumbra.String.Classes;
namespace Penumbra.UI.ResourceWatcher;
@@ -24,14 +25,16 @@ internal unsafe struct Record
public ModCollection? Collection;
public ResourceHandle* Handle;
public ResourceTypeFlag ResourceType;
- public ResourceCategoryFlag Category;
+ public ulong Crc64;
public uint RefCount;
+ public ResourceCategoryFlag Category;
public RecordType RecordType;
public OptionalBool Synchronously;
public OptionalBool ReturnValue;
public OptionalBool CustomLoad;
public LoadState LoadState;
+
public static Record CreateRequest(CiByteString path, bool sync)
=> new()
{
@@ -49,6 +52,7 @@ internal unsafe struct Record
CustomLoad = OptionalBool.Null,
AssociatedGameObject = string.Empty,
LoadState = LoadState.None,
+ Crc64 = 0,
};
public static Record CreateDefaultLoad(CiByteString path, ResourceHandle* handle, ModCollection collection, string associatedGameObject)
@@ -70,15 +74,16 @@ internal unsafe struct Record
CustomLoad = false,
AssociatedGameObject = associatedGameObject,
LoadState = handle->LoadState,
+ Crc64 = 0,
};
}
- public static Record CreateLoad(CiByteString path, CiByteString originalPath, ResourceHandle* handle, ModCollection collection,
+ public static Record CreateLoad(FullPath path, CiByteString originalPath, ResourceHandle* handle, ModCollection collection,
string associatedGameObject)
=> new()
{
Time = DateTime.UtcNow,
- Path = path.IsOwned ? path : path.Clone(),
+ Path = path.InternalName.IsOwned ? path.InternalName : path.InternalName.Clone(),
OriginalPath = originalPath.IsOwned ? originalPath : originalPath.Clone(),
Collection = collection,
Handle = handle,
@@ -91,6 +96,7 @@ internal unsafe struct Record
CustomLoad = true,
AssociatedGameObject = associatedGameObject,
LoadState = handle->LoadState,
+ Crc64 = path.Crc64,
};
public static Record CreateDestruction(ResourceHandle* handle)
@@ -112,6 +118,7 @@ internal unsafe struct Record
CustomLoad = OptionalBool.Null,
AssociatedGameObject = string.Empty,
LoadState = handle->LoadState,
+ Crc64 = 0,
};
}
@@ -132,5 +139,6 @@ internal unsafe struct Record
CustomLoad = custom,
AssociatedGameObject = string.Empty,
LoadState = handle->LoadState,
+ Crc64 = 0,
};
}
diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
index 6f1ce9cf..d432e97e 100644
--- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
+++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs
@@ -250,7 +250,7 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService
var record = manipulatedPath == null
? Record.CreateDefaultLoad(path.Path, handle, data.ModCollection, Name(data))
- : Record.CreateLoad(manipulatedPath.Value.InternalName, path.Path, handle, data.ModCollection, Name(data));
+ : Record.CreateLoad(manipulatedPath.Value, path.Path, handle, data.ModCollection, Name(data));
if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record))
_newRecords.Enqueue(record);
}
diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs
index 2bb71b87..88b7120d 100644
--- a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs
+++ b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs
@@ -29,7 +29,8 @@ internal sealed class ResourceWatcherTable : Table
new HandleColumn { Label = "Resource" },
new LoadStateColumn { Label = "State" },
new RefCountColumn { Label = "#Ref" },
- new DateColumn { Label = "Time" }
+ new DateColumn { Label = "Time" },
+ new Crc64Column { Label = "Crc64" }
)
{ }
@@ -144,6 +145,21 @@ internal sealed class ResourceWatcherTable : Table
=> ImGui.TextUnformatted($"{item.Time.ToLongTimeString()}.{item.Time.Millisecond:D4}");
}
+ private sealed class Crc64Column : ColumnString
+ {
+ public override float Width
+ => UiBuilder.MonoFont.GetCharAdvance('0') * 17;
+
+ public override unsafe string ToName(Record item)
+ => item.Crc64 != 0 ? $"{item.Crc64:X16}" : string.Empty;
+
+ public override unsafe void DrawColumn(Record item, int _)
+ {
+ using var font = ImRaii.PushFont(UiBuilder.MonoFont, item.Handle != null);
+ ImUtf8.Text(ToName(item));
+ }
+ }
+
private sealed class CollectionColumn : ColumnString
{
diff --git a/Penumbra/UI/Tabs/Debug/AtchDrawer.cs b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs
index 3e407e99..d9058083 100644
--- a/Penumbra/UI/Tabs/Debug/AtchDrawer.cs
+++ b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs
@@ -2,6 +2,7 @@ using ImGuiNET;
using OtterGui;
using OtterGui.Text;
using Penumbra.GameData.Files;
+using Penumbra.GameData.Files.AtchStructs;
namespace Penumbra.UI.Tabs.Debug;
@@ -18,27 +19,27 @@ public static class AtchDrawer
ImGui.SameLine();
using (ImUtf8.Group())
{
- ImUtf8.Text($"{file.Entries.Count}");
- if (file.Entries.Count == 0)
+ ImUtf8.Text($"{file.Points.Count}");
+ if (file.Points.Count == 0)
{
ImUtf8.Text("0"u8);
return;
}
- ImUtf8.Text($"{file.Entries[0].States.Count}");
+ ImUtf8.Text($"{file.Points[0].Entries.Length}");
}
- foreach (var (entry, index) in file.Entries.WithIndex())
+ foreach (var (entry, index) in file.Points.WithIndex())
{
using var id = ImUtf8.PushId(index);
- using var tree = ImUtf8.TreeNode($"{index:D3}: {entry.Name.Span}");
+ using var tree = ImUtf8.TreeNode($"{index:D3}: {entry.Type.ToName()}");
if (tree)
{
ImUtf8.TreeNode(entry.Accessory ? "Accessory"u8 : "Weapon"u8, ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose();
- foreach (var (state, i) in entry.States.WithIndex())
+ foreach (var (state, i) in entry.Entries.WithIndex())
{
id.Push(i);
- using var t = ImUtf8.TreeNode(state.Bone.Span);
+ using var t = ImUtf8.TreeNode(state.Bone);
if (t)
{
ImUtf8.TreeNode($"Scale: {state.Scale}", ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose();
diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs
index 28911b05..fc735d04 100644
--- a/Penumbra/UI/Tabs/Debug/DebugTab.cs
+++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs
@@ -104,7 +104,7 @@ public class DebugTab : Window, ITab, IUiService
private readonly CrashHandlerPanel _crashHandlerPanel;
private readonly TexHeaderDrawer _texHeaderDrawer;
private readonly HookOverrideDrawer _hookOverrides;
- private readonly TexMdlScdService _texMdlScdService;
+ private readonly RsfService _rsfService;
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
IClientState clientState, IDataManager dataManager,
@@ -115,7 +115,7 @@ 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, TexMdlScdService texMdlScdService)
+ HookOverrideDrawer hookOverrides, RsfService rsfService)
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
{
IsOpen = true;
@@ -153,7 +153,7 @@ public class DebugTab : Window, ITab, IUiService
_crashHandlerPanel = crashHandlerPanel;
_texHeaderDrawer = texHeaderDrawer;
_hookOverrides = hookOverrides;
- _texMdlScdService = texMdlScdService;
+ _rsfService = rsfService;
_objects = objects;
_clientState = clientState;
_dataManager = dataManager;
@@ -1087,7 +1087,7 @@ public class DebugTab : Window, ITab, IUiService
ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, 5 * UiBuilder.MonoFont.GetCharAdvance('0'));
ImGui.TableHeadersRow();
- foreach (var (hash, type) in _texMdlScdService.CustomCache)
+ foreach (var (hash, type) in _rsfService.CustomCache)
{
ImGui.TableNextColumn();
ImUtf8.Text($"{hash:X16}");