From 7e6ea5008c3f2ee678a8f0505354fb63676d49fd Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 30 Oct 2024 17:30:45 +0100 Subject: [PATCH 01/18] Maybe fix other issue with left rings and resource trees. --- Penumbra.GameData | 2 +- .../ResourceTree/ResolveContext.PathResolution.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Penumbra.GameData b/Penumbra.GameData index e9fc5930..e39a04c8 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit e9fc5930a9c035c1e1e3c87ee9bcc4f05eb3015b +Subproject commit e39a04c83b67246580492677414888357b5ebed8 diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs b/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs index 79f97881..b1cbb74d 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs @@ -36,17 +36,16 @@ internal partial record ResolveContext private Utf8GamePath ResolveEquipmentModelPath() { var path = IsEquipmentSlot(SlotIndex) - ? GamePaths.Equipment.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), Slot.ToSlot()) + ? GamePaths.Equipment.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()) : GamePaths.Accessory.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } private GenderRace ResolveModelRaceCode() - => ResolveEqdpRaceCode(Slot.ToSlot(), Equipment.Set); + => ResolveEqdpRaceCode(SlotIndex, Equipment.Set); - private unsafe GenderRace ResolveEqdpRaceCode(EquipSlot slot, PrimaryId primaryId) + private unsafe GenderRace ResolveEqdpRaceCode(uint slotIndex, PrimaryId primaryId) { - var slotIndex = slot.ToIndex(); if (!IsEquipmentOrAccessorySlot(slotIndex) || ModelType != ModelType.Human) return GenderRace.MidlanderMale; @@ -61,6 +60,7 @@ internal partial record ResolveContext var metaCache = Global.Collection.MetaCache; var entry = metaCache?.GetEqdpEntry(characterRaceCode, accessory, primaryId) ?? ExpandedEqdpFile.GetDefault(Global.MetaFileManager, characterRaceCode, accessory, primaryId); + var slot = slotIndex.ToEquipSlot(); if (entry.ToBits(slot).Item2) return characterRaceCode; @@ -272,7 +272,7 @@ internal partial record ResolveContext { var human = (Human*)CharacterBase; var equipment = ((CharacterArmor*)&human->Head)[slot.ToIndex()]; - return ResolveHumanExtraSkeletonData(ResolveEqdpRaceCode(slot, equipment.Set), type, equipment.Set); + return ResolveHumanExtraSkeletonData(ResolveEqdpRaceCode(slot.ToIndex(), equipment.Set), type, equipment.Set); } private (GenderRace RaceCode, string Slot, PrimaryId Set) ResolveHumanExtraSkeletonData(GenderRace raceCode, EstType type, From 2358eb378deebd960b16619f243e16fc9a86e845 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 30 Oct 2024 17:31:38 +0100 Subject: [PATCH 02/18] Fix issue with characters in login screen, maybe. --- .../PathResolving/CollectionResolver.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 313c4f8b..1705f871 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -1,6 +1,7 @@ using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using OtterGui; using OtterGui.Services; using Penumbra.Collections; using Penumbra.Collections.Manager; @@ -62,10 +63,11 @@ public sealed unsafe class CollectionResolver( try { - if (useCache && cache.TryGetValue(gameObject, out var data)) + // Login screen reuses the same actors and can not be cached. + if (LoginScreen(gameObject, out var data)) return data; - if (LoginScreen(gameObject, out data)) + if (useCache && cache.TryGetValue(gameObject, out data)) return data; if (Aesthetician(gameObject, out data)) @@ -116,16 +118,17 @@ public sealed unsafe class CollectionResolver( return true; } - var notYetReady = false; - var lobby = AgentLobby.Instance(); - if (lobby != null) + var notYetReady = false; + var lobby = AgentLobby.Instance(); + var characterList = CharaSelectCharacterList.Instance(); + if (lobby != null && characterList != null) { - var span = lobby->LobbyData.CharaSelectEntries.AsSpan(); // The lobby uses the first 8 cutscene actors. var idx = gameObject->ObjectIndex - ObjectIndex.CutsceneStart.Index; - if (idx >= 0 && idx < span.Length && span[idx].Value != null) + if (characterList->CharacterMapping.FindFirst(m => m.ClientObjectIndex == idx, out var mapping) + && lobby->LobbyData.CharaSelectEntries.FindFirst(e => e.Value->ContentId == mapping.ContentId, out var charaEntry)) { - var item = span[idx].Value; + var item = charaEntry.Value; var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId); Penumbra.Log.Verbose( $"Identified {identifier.Incognito(null)} in cutscene for actor {idx + 200} at 0x{(ulong)gameObject:X} of race {(gameObject->IsCharacter() ? ((Character*)gameObject)->DrawData.CustomizeData.Race.ToString() : "Unknown")}."); @@ -141,7 +144,7 @@ public sealed unsafe class CollectionResolver( var collection = collectionManager.Active.ByType(CollectionType.Yourself) ?? CollectionByAttributes(gameObject, ref notYetReady) ?? collectionManager.Active.Default; - ret = notYetReady ? collection.ToResolveData(gameObject) : cache.Set(collection, ActorIdentifier.Invalid, gameObject); + ret = collection.ToResolveData(gameObject); return true; } From c4f6038d1ef629515e830e316ef11dc4871868da Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 30 Oct 2024 20:40:10 +0100 Subject: [PATCH 03/18] Make temporary collection always respect ownership. --- .../PathResolving/CollectionResolver.cs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 1705f871..36c31af3 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -126,7 +126,7 @@ public sealed unsafe class CollectionResolver( // The lobby uses the first 8 cutscene actors. var idx = gameObject->ObjectIndex - ObjectIndex.CutsceneStart.Index; if (characterList->CharacterMapping.FindFirst(m => m.ClientObjectIndex == idx, out var mapping) - && lobby->LobbyData.CharaSelectEntries.FindFirst(e => e.Value->ContentId == mapping.ContentId, out var charaEntry)) + && lobby->LobbyData.CharaSelectEntries.FindFirst(e => e.Value->ContentId == mapping.ContentId, out var charaEntry)) { var item = charaEntry.Value; var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId); @@ -199,10 +199,24 @@ public sealed unsafe class CollectionResolver( /// Check both temporary and permanent character collections. Temporary first. private ModCollection? CollectionByIdentifier(ActorIdentifier identifier) - => tempCollections.Collections.TryGetCollection(identifier, out var collection) - || collectionManager.Active.Individuals.TryGetCollection(identifier, out collection) - ? collection - : null; + { + if (tempCollections.Collections.TryGetCollection(identifier, out var collection)) + return collection; + + // Always inherit ownership for temporary collections. + if (identifier.Type is IdentifierType.Owned) + { + var playerIdentifier = actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, + identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); + if (tempCollections.Collections.TryGetCollection(playerIdentifier, out collection)) + return collection; + } + + if (collectionManager.Active.Individuals.TryGetCollection(identifier, out collection)) + return collection; + + return null; + } /// Check for the Yourself collection. private ModCollection? CheckYourself(ActorIdentifier identifier, Actor actor) From ed717c69f9676a3314e0235829539ab3a819a5be Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 30 Oct 2024 20:40:10 +0100 Subject: [PATCH 04/18] Make temporary collection always respect ownership. --- .../Manager/IndividualCollections.Access.cs | 6 ++--- .../PathResolving/CollectionResolver.cs | 24 +++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Penumbra/Collections/Manager/IndividualCollections.Access.cs b/Penumbra/Collections/Manager/IndividualCollections.Access.cs index 6b90a333..d0a70630 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Access.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Access.cs @@ -48,8 +48,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa // Handle generic NPC var npcIdentifier = _actors.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, - ushort.MaxValue, - identifier.Kind, identifier.DataId); + ushort.MaxValue, identifier.Kind, identifier.DataId); if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection)) return true; @@ -58,8 +57,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa return false; identifier = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, - identifier.HomeWorld.Id, - ObjectKind.None, uint.MaxValue); + identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); return CheckWorlds(identifier, out collection); } case IdentifierType.Npc: return _individuals.TryGetValue(identifier, out collection); diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 1705f871..36c31af3 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -126,7 +126,7 @@ public sealed unsafe class CollectionResolver( // The lobby uses the first 8 cutscene actors. var idx = gameObject->ObjectIndex - ObjectIndex.CutsceneStart.Index; if (characterList->CharacterMapping.FindFirst(m => m.ClientObjectIndex == idx, out var mapping) - && lobby->LobbyData.CharaSelectEntries.FindFirst(e => e.Value->ContentId == mapping.ContentId, out var charaEntry)) + && lobby->LobbyData.CharaSelectEntries.FindFirst(e => e.Value->ContentId == mapping.ContentId, out var charaEntry)) { var item = charaEntry.Value; var identifier = actors.CreatePlayer(new ByteString(item->Name), item->HomeWorldId); @@ -199,10 +199,24 @@ public sealed unsafe class CollectionResolver( /// Check both temporary and permanent character collections. Temporary first. private ModCollection? CollectionByIdentifier(ActorIdentifier identifier) - => tempCollections.Collections.TryGetCollection(identifier, out var collection) - || collectionManager.Active.Individuals.TryGetCollection(identifier, out collection) - ? collection - : null; + { + if (tempCollections.Collections.TryGetCollection(identifier, out var collection)) + return collection; + + // Always inherit ownership for temporary collections. + if (identifier.Type is IdentifierType.Owned) + { + var playerIdentifier = actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, + identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); + if (tempCollections.Collections.TryGetCollection(playerIdentifier, out collection)) + return collection; + } + + if (collectionManager.Active.Individuals.TryGetCollection(identifier, out collection)) + return collection; + + return null; + } /// Check for the Yourself collection. private ModCollection? CheckYourself(ActorIdentifier identifier, Actor actor) From 7dfc564a4cbafd26633aeff3cf8cc37d4a2e2e61 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 4 Nov 2024 13:55:45 +0100 Subject: [PATCH 05/18] Add path resolving / est handling for kdb and bnmb files. --- .../Hooks/Resources/ResolvePathHooksBase.cs | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs b/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs index d55caf34..54066782 100644 --- a/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs +++ b/Penumbra/Interop/Hooks/Resources/ResolvePathHooksBase.cs @@ -36,7 +36,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable private readonly Hook _resolveMdlPathHook; private readonly Hook _resolveMtrlPathHook; private readonly Hook _resolvePapPathHook; + private readonly Hook _resolveKdbPathHook; private readonly Hook _resolvePhybPathHook; + private readonly Hook _resolveBnmbPathHook; private readonly Hook _resolveSklbPathHook; private readonly Hook _resolveSkpPathHook; private readonly Hook _resolveTmbPathHook; @@ -54,11 +56,10 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable _resolveMdlPathHook = Create($"{name}.{nameof(ResolveMdl)}", hooks, vTable[77], type, ResolveMdl, ResolveMdlHuman); _resolveSkpPathHook = Create($"{name}.{nameof(ResolveSkp)}", hooks, vTable[78], type, ResolveSkp, ResolveSkpHuman); _resolvePhybPathHook = Create($"{name}.{nameof(ResolvePhyb)}", hooks, vTable[79], type, ResolvePhyb, ResolvePhybHuman); - + _resolveKdbPathHook = Create($"{name}.{nameof(ResolveKdb)}", hooks, vTable[80], type, ResolveKdb, ResolveKdbHuman); _vFunc81Hook = Create( $"{name}.{nameof(VFunc81)}", hooks, vTable[81], type, null, VFunc81); - + _resolveBnmbPathHook = Create($"{name}.{nameof(ResolveBnmb)}", hooks, vTable[82], type, ResolveBnmb, ResolveBnmbHuman); _vFunc83Hook = Create( $"{name}.{nameof(VFunc83)}", hooks, vTable[83], type, null, VFunc83); - _resolvePapPathHook = Create( $"{name}.{nameof(ResolvePap)}", hooks, vTable[84], type, ResolvePap, ResolvePapHuman); _resolveTmbPathHook = Create( $"{name}.{nameof(ResolveTmb)}", hooks, vTable[85], ResolveTmb); _resolveMPapPathHook = Create( $"{name}.{nameof(ResolveMPap)}", hooks, vTable[87], ResolveMPap); @@ -83,7 +84,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable _resolveMdlPathHook.Enable(); _resolveMtrlPathHook.Enable(); _resolvePapPathHook.Enable(); + _resolveKdbPathHook.Enable(); _resolvePhybPathHook.Enable(); + _resolveBnmbPathHook.Enable(); _resolveSklbPathHook.Enable(); _resolveSkpPathHook.Enable(); _resolveTmbPathHook.Enable(); @@ -101,7 +104,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable _resolveMdlPathHook.Disable(); _resolveMtrlPathHook.Disable(); _resolvePapPathHook.Disable(); + _resolveKdbPathHook.Disable(); _resolvePhybPathHook.Disable(); + _resolveBnmbPathHook.Disable(); _resolveSklbPathHook.Disable(); _resolveSkpPathHook.Disable(); _resolveTmbPathHook.Disable(); @@ -119,7 +124,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable _resolveMdlPathHook.Dispose(); _resolveMtrlPathHook.Dispose(); _resolvePapPathHook.Dispose(); + _resolveKdbPathHook.Dispose(); _resolvePhybPathHook.Dispose(); + _resolveBnmbPathHook.Dispose(); _resolveSklbPathHook.Dispose(); _resolveSkpPathHook.Dispose(); _resolveTmbPathHook.Dispose(); @@ -149,9 +156,15 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable private nint ResolvePap(nint drawObject, nint pathBuffer, nint pathBufferSize, uint unkAnimationIndex, nint animationName) => ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, pathBuffer, pathBufferSize, unkAnimationIndex, animationName)); + private nint ResolveKdb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) + => ResolvePath(drawObject, _resolveKdbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); + private nint ResolvePhyb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) => ResolvePath(drawObject, _resolvePhybPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); + private nint ResolveBnmb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) + => ResolvePath(drawObject, _resolveBnmbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); + private nint ResolveSklb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) => ResolvePath(drawObject, _resolveSklbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); @@ -188,6 +201,15 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable return ret; } + private nint ResolveKdbHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) + { + var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true); + _parent.MetaState.EstCollection.Push(collection); + var ret = ResolvePath(collection, _resolveKdbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); + _parent.MetaState.EstCollection.Pop(); + return ret; + } + private nint ResolvePhybHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) { var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true); @@ -197,6 +219,15 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable return ret; } + private nint ResolveBnmbHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) + { + var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true); + _parent.MetaState.EstCollection.Push(collection); + var ret = ResolvePath(collection, _resolveBnmbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex)); + _parent.MetaState.EstCollection.Pop(); + return ret; + } + private nint ResolveSklbHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex) { var collection = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true); From c54141be5489753ce6fa4ad862478615ab25fbae Mon Sep 17 00:00:00 2001 From: Actions User Date: Mon, 4 Nov 2024 12:59:01 +0000 Subject: [PATCH 06/18] [CI] Updating repo.json for testing_1.3.0.1 --- repo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repo.json b/repo.json index cba274c8..686549c9 100644 --- a/repo.json +++ b/repo.json @@ -6,7 +6,7 @@ "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", "AssemblyVersion": "1.3.0.0", - "TestingAssemblyVersion": "1.3.0.0", + "TestingAssemblyVersion": "1.3.0.1", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 10, @@ -19,7 +19,7 @@ "LoadRequiredState": 2, "LoadSync": true, "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.1/Penumbra.zip", "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } From e3a1ae693813eb06d96d311958aabb5b3abfef55 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sun, 17 Nov 2024 00:50:14 +0100 Subject: [PATCH 07/18] Current state. --- OtterGui | 2 +- Penumbra.GameData | 2 +- .../Animation/ApricotListenerSoundPlay.cs | 14 ++++--- .../Interop/Hooks/Animation/SomePapLoad.cs | 2 +- .../Interop/Hooks/Meta/CalculateHeight.cs | 17 ++++---- Penumbra/Interop/Hooks/Meta/UpdateModel.cs | 2 +- .../PostProcessing/ShaderReplacementFixer.cs | 1 - .../PathResolving/CollectionResolver.cs | 2 +- Penumbra/Interop/ResourceTree/ResourceTree.cs | 2 +- Penumbra/Interop/Services/FontReloader.cs | 2 +- Penumbra/Interop/Services/RedrawService.cs | 4 +- Penumbra/Interop/VolatileOffsets.cs | 35 ++++++++++++++++ .../Manager/OptionEditor/ImcModGroupEditor.cs | 2 +- .../Manager/OptionEditor/ModGroupEditor.cs | 2 +- .../OptionEditor/MultiModGroupEditor.cs | 2 +- .../OptionEditor/SingleModGroupEditor.cs | 2 +- Penumbra/Penumbra.cs | 4 +- Penumbra/Services/MessageService.cs | 6 +-- Penumbra/UI/Tabs/Debug/DebugTab.cs | 3 ++ Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs | 41 ++++++++++++++----- 20 files changed, 104 insertions(+), 43 deletions(-) create mode 100644 Penumbra/Interop/VolatileOffsets.cs diff --git a/OtterGui b/OtterGui index 3e6b0857..8ba88eff 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 3e6b085749741f35dd6732c33d0720c6a51ebb97 +Subproject commit 8ba88eff15326bb28ed5e6157f5252c114d40b5f diff --git a/Penumbra.GameData b/Penumbra.GameData index e39a04c8..fb81a0b5 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit e39a04c83b67246580492677414888357b5ebed8 +Subproject commit fb81a0b55d3c68f2b26357fac3049c79fb0c22fb diff --git a/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs b/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs index 44eb7ebb..8838971c 100644 --- a/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs +++ b/Penumbra/Interop/Hooks/Animation/ApricotListenerSoundPlay.cs @@ -33,25 +33,27 @@ public sealed unsafe class ApricotListenerSoundPlayCaller : FastHook> 13) & 1) == 0) + var someIntermediate = *(nint*)(a1 + VolatileOffsets.ApricotListenerSoundPlayCaller.SomeIntermediate); + var flags = someIntermediate == nint.Zero + ? (ushort)0 + : *(ushort*)(someIntermediate + VolatileOffsets.ApricotListenerSoundPlayCaller.Flags); + if (((flags >> VolatileOffsets.ApricotListenerSoundPlayCaller.BitShift) & 1) == 0) return Task.Result.Original(a1, unused, timeOffset); Penumbra.Log.Excessive( $"[Apricot Listener Sound Play Caller] Invoked on 0x{a1:X} with {unused}, {timeOffset}."); // Fetch the IInstanceListenner (sixth argument to inlined call of SoundPlay) - var apricotIInstanceListenner = *(nint*)(someIntermediate + 0x270); + var apricotIInstanceListenner = *(nint*)(someIntermediate + VolatileOffsets.ApricotListenerSoundPlayCaller.IInstanceListenner); if (apricotIInstanceListenner == nint.Zero) return Task.Result.Original(a1, unused, timeOffset); // In some cases we can obtain the associated caster via vfunc 1. var newData = ResolveData.Invalid; - var gameObject = (*(delegate* unmanaged**)apricotIInstanceListenner)[1](apricotIInstanceListenner); + var gameObject = (*(delegate* unmanaged**)apricotIInstanceListenner)[VolatileOffsets.ApricotListenerSoundPlayCaller.CasterVFunc](apricotIInstanceListenner); if (gameObject != null) { newData = _collectionResolver.IdentifyCollection(gameObject, true); diff --git a/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs b/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs index 7339c397..f19e4ce2 100644 --- a/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs +++ b/Penumbra/Interop/Hooks/Animation/SomePapLoad.cs @@ -31,7 +31,7 @@ public sealed unsafe class SomePapLoad : FastHook private void Detour(nint a1, int a2, nint a3, int a4) { Penumbra.Log.Excessive($"[Some PAP Load] Invoked on 0x{a1:X} with {a2}, {a3}, {a4}."); - var timelinePtr = a1 + Offsets.TimeLinePtr; + var timelinePtr = a1 + VolatileOffsets.AnimationState.TimeLinePtr; if (timelinePtr != nint.Zero) { var actorIdx = (int)(*(*(ulong**)timelinePtr + 1) >> 3); diff --git a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs index e71d07dd..327e3d1e 100644 --- a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs +++ b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs @@ -1,7 +1,7 @@ +using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Object; using OtterGui.Services; using Penumbra.Interop.PathResolving; -using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character; namespace Penumbra.Interop.Hooks.Meta; @@ -13,19 +13,20 @@ public sealed unsafe class CalculateHeight : FastHook public CalculateHeight(HookManager hooks, CollectionResolver collectionResolver, MetaState metaState) { _collectionResolver = collectionResolver; - _metaState = metaState; - Task = hooks.CreateHook("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, !HookOverrides.Instance.Meta.CalculateHeight); + _metaState = metaState; + Task = hooks.CreateHook("Calculate Height", (nint)HeightContainer.MemberFunctionPointers.CalculateHeight, Detour, + !HookOverrides.Instance.Meta.CalculateHeight); } - public delegate ulong Delegate(Character* character); + public delegate ulong Delegate(HeightContainer* character); [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - private ulong Detour(Character* character) + private ulong Detour(HeightContainer* container) { - var collection = _collectionResolver.IdentifyCollection((GameObject*)character, true); + var collection = _collectionResolver.IdentifyCollection((GameObject*)container->OwnerObject, true); _metaState.RspCollection.Push(collection); - var ret = Task.Result.Original.Invoke(character); - Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)character:X} -> {ret}."); + var ret = Task.Result.Original.Invoke(container); + Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)container:X} -> {ret}."); _metaState.RspCollection.Pop(); return ret; } diff --git a/Penumbra/Interop/Hooks/Meta/UpdateModel.cs b/Penumbra/Interop/Hooks/Meta/UpdateModel.cs index 72beea0e..9189ce3b 100644 --- a/Penumbra/Interop/Hooks/Meta/UpdateModel.cs +++ b/Penumbra/Interop/Hooks/Meta/UpdateModel.cs @@ -25,7 +25,7 @@ public sealed unsafe class UpdateModel : FastHook { // Shortcut because this is called all the time. // Same thing is checked at the beginning of the original function. - if (*(int*)((nint)drawObject + Offsets.UpdateModelSkip) == 0) + if (*(int*)((nint)drawObject + VolatileOffsets.UpdateModel.ShortCircuit) == 0) return; Penumbra.Log.Excessive($"[Update Model] Invoked on {(nint)drawObject:X}."); diff --git a/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs b/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs index 80892b0f..40958eb4 100644 --- a/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs +++ b/Penumbra/Interop/Hooks/PostProcessing/ShaderReplacementFixer.cs @@ -401,7 +401,6 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic private void ModelRendererUnkFuncDetour(CSModelRenderer* modelRenderer, ModelRendererStructs.UnkPayload* unkPayload, uint unk2, uint unk3, uint unk4, uint unk5) { - // If we don't have any on-screen instances of modded iris.shpk or others, we don't need the slow path at all. if (!Enabled || GetTotalMaterialCountForModelRendererUnk() == 0) { _modelRendererUnkFuncHook.Original(modelRenderer, unkPayload, unk2, unk3, unk4, unk5); diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 36c31af3..50088008 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -240,7 +240,7 @@ public sealed unsafe class CollectionResolver( } // Only handle human models. - if (!IsModelHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId)) + if (!IsModelHuman((uint)actor.AsCharacter->ModelCharaId)) return null; if (actor.Customize->Data[0] == 0) diff --git a/Penumbra/Interop/ResourceTree/ResourceTree.cs b/Penumbra/Interop/ResourceTree/ResourceTree.cs index 89e0c62b..62f4febe 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTree.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTree.cs @@ -68,7 +68,7 @@ public class ResourceTree Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10), _ => [], }; - ModelId = character->CharacterData.ModelCharaId; + ModelId = character->ModelCharaId; CustomizeData = character->DrawData.CustomizeData; RaceCode = human != null ? (GenderRace)human->RaceSexId : GenderRace.Unknown; diff --git a/Penumbra/Interop/Services/FontReloader.cs b/Penumbra/Interop/Services/FontReloader.cs index 4f48f08f..3a2c7022 100644 --- a/Penumbra/Interop/Services/FontReloader.cs +++ b/Penumbra/Interop/Services/FontReloader.cs @@ -43,7 +43,7 @@ public unsafe class FontReloader : IService return; _atkModule = &atkModule->AtkModule; - _reloadFontsFunc = ((delegate* unmanaged*)_atkModule->VirtualTable)[Offsets.ReloadFontsVfunc]; + _reloadFontsFunc = ((delegate* unmanaged*)_atkModule->VirtualTable)[VolatileOffsets.FontReloader.ReloadFontsVFunc]; }); } } diff --git a/Penumbra/Interop/Services/RedrawService.cs b/Penumbra/Interop/Services/RedrawService.cs index 2cdc1137..8f20ca5e 100644 --- a/Penumbra/Interop/Services/RedrawService.cs +++ b/Penumbra/Interop/Services/RedrawService.cs @@ -38,10 +38,10 @@ public unsafe partial class RedrawService : IService // VFuncs that disable and enable draw, used only for GPose actors. private static void DisableDraw(IGameObject actor) - => ((delegate* unmanaged**)actor.Address)[0][Offsets.DisableDrawVfunc](actor.Address); + => ((delegate* unmanaged**)actor.Address)[0][VolatileOffsets.RedrawService.DisableDrawVFunc](actor.Address); private static void EnableDraw(IGameObject actor) - => ((delegate* unmanaged**)actor.Address)[0][Offsets.EnableDrawVfunc](actor.Address); + => ((delegate* unmanaged**)actor.Address)[0][VolatileOffsets.RedrawService.EnableDrawVFunc](actor.Address); // Check whether we currently are in GPose. // Also clear the name list. diff --git a/Penumbra/Interop/VolatileOffsets.cs b/Penumbra/Interop/VolatileOffsets.cs new file mode 100644 index 00000000..2c6e3180 --- /dev/null +++ b/Penumbra/Interop/VolatileOffsets.cs @@ -0,0 +1,35 @@ +namespace Penumbra.Interop; + +public static class VolatileOffsets +{ + public static class ApricotListenerSoundPlayCaller + { + public const int PlayTimeOffset = 0x254; + public const int SomeIntermediate = 0x1F8; + public const int Flags = 0x4A4; + public const int IInstanceListenner = 0x270; + public const int BitShift = 13; + public const int CasterVFunc = 1; + } + + public static class AnimationState + { + public const int TimeLinePtr = 0x50; + } + + public static class UpdateModel + { + public const int ShortCircuit = 0xA2C; + } + + public static class FontReloader + { + public const int ReloadFontsVFunc = 43; + } + + public static class RedrawService + { + public const int EnableDrawVFunc = 12; + public const int DisableDrawVFunc = 13; + } +} diff --git a/Penumbra/Mods/Manager/OptionEditor/ImcModGroupEditor.cs b/Penumbra/Mods/Manager/OptionEditor/ImcModGroupEditor.cs index dc94c881..f8760625 100644 --- a/Penumbra/Mods/Manager/OptionEditor/ImcModGroupEditor.cs +++ b/Penumbra/Mods/Manager/OptionEditor/ImcModGroupEditor.cs @@ -138,7 +138,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ protected override bool MoveOption(ImcModGroup group, int optionIdxFrom, int optionIdxTo) { - if (!group.OptionData.Move(optionIdxFrom, optionIdxTo)) + if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo)) return false; group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo); diff --git a/Penumbra/Mods/Manager/OptionEditor/ModGroupEditor.cs b/Penumbra/Mods/Manager/OptionEditor/ModGroupEditor.cs index 7f18852d..d01297db 100644 --- a/Penumbra/Mods/Manager/OptionEditor/ModGroupEditor.cs +++ b/Penumbra/Mods/Manager/OptionEditor/ModGroupEditor.cs @@ -90,7 +90,7 @@ public class ModGroupEditor( { var mod = group.Mod; var idxFrom = group.GetIndex(); - if (!mod.Groups.Move(idxFrom, groupIdxTo)) + if (!mod.Groups.Move(ref idxFrom, ref groupIdxTo)) return; saveService.SaveAllOptionGroups(mod, false, config.ReplaceNonAsciiOnImport); diff --git a/Penumbra/Mods/Manager/OptionEditor/MultiModGroupEditor.cs b/Penumbra/Mods/Manager/OptionEditor/MultiModGroupEditor.cs index 74362325..2446ae80 100644 --- a/Penumbra/Mods/Manager/OptionEditor/MultiModGroupEditor.cs +++ b/Penumbra/Mods/Manager/OptionEditor/MultiModGroupEditor.cs @@ -75,7 +75,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe protected override bool MoveOption(MultiModGroup group, int optionIdxFrom, int optionIdxTo) { - if (!group.OptionData.Move(optionIdxFrom, optionIdxTo)) + if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo)) return false; group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo); diff --git a/Penumbra/Mods/Manager/OptionEditor/SingleModGroupEditor.cs b/Penumbra/Mods/Manager/OptionEditor/SingleModGroupEditor.cs index 15a899a0..5fd785cf 100644 --- a/Penumbra/Mods/Manager/OptionEditor/SingleModGroupEditor.cs +++ b/Penumbra/Mods/Manager/OptionEditor/SingleModGroupEditor.cs @@ -48,7 +48,7 @@ public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveS protected override bool MoveOption(SingleModGroup group, int optionIdxFrom, int optionIdxTo) { - if (!group.OptionData.Move(optionIdxFrom, optionIdxTo)) + if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo)) return false; group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo); diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index b6b19ef2..41d8f668 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -1,6 +1,5 @@ using Dalamud.Plugin; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; using OtterGui; using OtterGui.Log; using OtterGui.Services; @@ -20,6 +19,7 @@ using OtterGui.Tasks; using Penumbra.UI; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; using Dalamud.Plugin.Services; +using Lumina.Excel.Sheets; using Penumbra.GameData.Data; using Penumbra.Interop.Hooks; using Penumbra.Interop.Hooks.ResourceLoading; @@ -111,7 +111,7 @@ public class Penumbra : IDalamudPlugin private void SetupApi() { _services.GetService(); - var itemSheet = _services.GetService().GetExcelSheet()!; + var itemSheet = _services.GetService().GetExcelSheet(); _communicatorService.ChangedItemHover.Subscribe(it => { if (it is IdentifiedItem { Item.Id.IsItem: true }) diff --git a/Penumbra/Services/MessageService.cs b/Penumbra/Services/MessageService.cs index a35a67f1..e610cb6a 100644 --- a/Penumbra/Services/MessageService.cs +++ b/Penumbra/Services/MessageService.cs @@ -4,7 +4,7 @@ using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface; using Dalamud.Interface.ImGuiNotification; using Dalamud.Plugin.Services; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using OtterGui.Log; using OtterGui.Services; using Penumbra.Mods.Manager; @@ -16,7 +16,7 @@ namespace Penumbra.Services; public class MessageService(Logger log, IUiBuilder builder, IChatGui chat, INotificationManager notificationManager) : OtterGui.Classes.MessageService(log, builder, chat, notificationManager), IService { - public void LinkItem(Item item) + public void LinkItem(in Item item) { // @formatter:off var payloadList = new List @@ -29,7 +29,7 @@ public class MessageService(Logger log, IUiBuilder builder, IChatGui chat, INoti new TextPayload($"{(char)SeIconChar.LinkMarker}"), new UIForegroundPayload(0), new UIGlowPayload(0), - new TextPayload(item.Name), + new TextPayload(item.Name.ExtractText()), new RawPayload([0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]), new RawPayload([0x02, 0x13, 0x02, 0xEC, 0x03]), }; diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index 7c6cd01e..47c2c16c 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -54,6 +54,9 @@ public class Diagnostics(ServiceManager provider) : IUiService return; using var table = ImRaii.Table("##data", 4, ImGuiTableFlags.RowBg); + if (!table) + return; + foreach (var type in typeof(ActorManager).Assembly.GetTypes() .Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncDataContainer)))) { diff --git a/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs b/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs index 7af1f884..e8ff9b9c 100644 --- a/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs +++ b/Penumbra/UI/Tabs/Debug/HookOverrideDrawer.cs @@ -34,28 +34,49 @@ public class HookOverrideDrawer(IDalamudPluginInterface pluginInterface) : IUiSe Penumbra.Log.Error($"Could not delete hook override file at {path}:\n{ex}"); } + bool? allVisible = null; + ImGui.SameLine(); + if (ImUtf8.Button("Disable All Visible Hooks"u8)) + allVisible = true; + ImGui.SameLine(); + if (ImUtf8.Button("Enable All VisibleHooks"u8)) + allVisible = false; + bool? all = null; ImGui.SameLine(); - if (ImUtf8.Button("Disable All Hooks"u8)) + if (ImUtf8.Button("Disable All Hooks")) all = true; ImGui.SameLine(); - if (ImUtf8.Button("Enable All Hooks"u8)) + if (ImUtf8.Button("Enable All Hooks")) all = false; foreach (var propertyField in typeof(HookOverrides).GetFields().Where(f => f is { IsStatic: false, FieldType.IsValueType: true })) { using var tree = ImUtf8.TreeNode(propertyField.Name); if (!tree) - continue; - - var property = propertyField.GetValue(_overrides); - foreach (var valueField in propertyField.FieldType.GetFields()) { - var value = valueField.GetValue(property) as bool? ?? false; - if (ImUtf8.Checkbox($"Disable {valueField.Name}", ref value) || all.HasValue) + if (all.HasValue) { - valueField.SetValue(property, all ?? value); - propertyField.SetValue(_overrides, property); + var property = propertyField.GetValue(_overrides); + foreach (var valueField in propertyField.FieldType.GetFields()) + { + valueField.SetValue(property, all.Value); + propertyField.SetValue(_overrides, property); + } + } + } + else + { + allVisible ??= all; + var property = propertyField.GetValue(_overrides); + foreach (var valueField in propertyField.FieldType.GetFields()) + { + var value = valueField.GetValue(property) as bool? ?? false; + if (ImUtf8.Checkbox($"Disable {valueField.Name}", ref value) || allVisible.HasValue) + { + valueField.SetValue(property, allVisible ?? value); + propertyField.SetValue(_overrides, property); + } } } } From 5599f12753624981a79609bbc17a283e24bd0dc6 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sun, 17 Nov 2024 14:28:33 +0100 Subject: [PATCH 08/18] Further fixes. --- Penumbra/Interop/Hooks/Meta/CalculateHeight.cs | 12 ++++++------ Penumbra/Interop/PathResolving/CollectionResolver.cs | 2 +- Penumbra/Interop/ResourceTree/ResourceTree.cs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs index 327e3d1e..0e85b3ae 100644 --- a/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs +++ b/Penumbra/Interop/Hooks/Meta/CalculateHeight.cs @@ -14,19 +14,19 @@ public sealed unsafe class CalculateHeight : FastHook { _collectionResolver = collectionResolver; _metaState = metaState; - Task = hooks.CreateHook("Calculate Height", (nint)HeightContainer.MemberFunctionPointers.CalculateHeight, Detour, + Task = hooks.CreateHook("Calculate Height", (nint)Character.MemberFunctionPointers.CalculateHeight, Detour, !HookOverrides.Instance.Meta.CalculateHeight); } - public delegate ulong Delegate(HeightContainer* character); + public delegate ulong Delegate(Character* character); [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - private ulong Detour(HeightContainer* container) + private ulong Detour(Character* character) { - var collection = _collectionResolver.IdentifyCollection((GameObject*)container->OwnerObject, true); + var collection = _collectionResolver.IdentifyCollection((GameObject*)character, true); _metaState.RspCollection.Push(collection); - var ret = Task.Result.Original.Invoke(container); - Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)container:X} -> {ret}."); + var ret = Task.Result.Original.Invoke(character); + Penumbra.Log.Excessive($"[Calculate Height] Invoked on {(nint)character:X} -> {ret}."); _metaState.RspCollection.Pop(); return ret; } diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 50088008..576b61bb 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -240,7 +240,7 @@ public sealed unsafe class CollectionResolver( } // Only handle human models. - if (!IsModelHuman((uint)actor.AsCharacter->ModelCharaId)) + if (!IsModelHuman((uint)actor.AsCharacter->ModelContainer.ModelCharaId)) return null; if (actor.Customize->Data[0] == 0) diff --git a/Penumbra/Interop/ResourceTree/ResourceTree.cs b/Penumbra/Interop/ResourceTree/ResourceTree.cs index 62f4febe..b50fc695 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTree.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTree.cs @@ -68,7 +68,7 @@ public class ResourceTree Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10), _ => [], }; - ModelId = character->ModelCharaId; + ModelId = character->ModelContainer.ModelCharaId; CustomizeData = character->DrawData.CustomizeData; RaceCode = human != null ? (GenderRace)human->RaceSexId : GenderRace.Unknown; From 83e5feb7dbbe452d8499562733dc9ba0edcee1bf Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sun, 17 Nov 2024 14:30:47 +0100 Subject: [PATCH 09/18] Update OtterGui. --- OtterGui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OtterGui b/OtterGui index 8ba88eff..95b8d177 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 8ba88eff15326bb28ed5e6157f5252c114d40b5f +Subproject commit 95b8d177883b03f804d77434f45e9de97fdb9adf From a864ac196550776a4870b7fc646591a4f1d55632 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sun, 17 Nov 2024 22:00:07 +0100 Subject: [PATCH 10/18] 1.3.0.2 --- .github/workflows/test_release.yml | 2 +- Penumbra/Penumbra.json | 2 +- repo.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_release.yml b/.github/workflows/test_release.yml index 0718ded2..549c967a 100644 --- a/.github/workflows/test_release.yml +++ b/.github/workflows/test_release.yml @@ -20,7 +20,7 @@ jobs: run: dotnet restore - name: Download Dalamud run: | - Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/latest.zip -OutFile latest.zip + Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -OutFile latest.zip Expand-Archive -Force latest.zip "$env:AppData\XIVLauncher\addon\Hooks\dev" - name: Build run: | diff --git a/Penumbra/Penumbra.json b/Penumbra/Penumbra.json index 805f4d85..4790da18 100644 --- a/Penumbra/Penumbra.json +++ b/Penumbra/Penumbra.json @@ -8,7 +8,7 @@ "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "Tags": [ "modding" ], - "DalamudApiLevel": 10, + "DalamudApiLevel": 11, "LoadPriority": 69420, "LoadState": 2, "LoadSync": true, diff --git a/repo.json b/repo.json index 686549c9..71d8fad4 100644 --- a/repo.json +++ b/repo.json @@ -10,7 +10,7 @@ "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 10, - "TestingDalamudApiLevel": 10, + "TestingDalamudApiLevel": 11, "IsHide": "False", "IsTestingExclusive": "False", "DownloadCount": 0, From 597380355a4a769de852a0e4e03656163f34fa56 Mon Sep 17 00:00:00 2001 From: Actions User Date: Sun, 17 Nov 2024 21:02:11 +0000 Subject: [PATCH 11/18] [CI] Updating repo.json for testing_1.3.0.2 --- repo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repo.json b/repo.json index 71d8fad4..651802a6 100644 --- a/repo.json +++ b/repo.json @@ -6,7 +6,7 @@ "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", "AssemblyVersion": "1.3.0.0", - "TestingAssemblyVersion": "1.3.0.1", + "TestingAssemblyVersion": "1.3.0.2", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 10, @@ -19,7 +19,7 @@ "LoadRequiredState": 2, "LoadSync": true, "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.1/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.2/Penumbra.zip", "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } From 7ab5299f7ae77c93e5f318529d1071ec3dfd4931 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 18 Nov 2024 00:28:27 +0100 Subject: [PATCH 12/18] Add SCD handling and crc cache visualization. --- Penumbra.sln | 3 + .../Hooks/ResourceLoading/ResourceLoader.cs | 8 +-- .../Hooks/ResourceLoading/TexMdlService.cs | 62 ++++++++++++++----- Penumbra/UI/Tabs/Debug/DebugTab.cs | 29 ++++++++- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/Penumbra.sln b/Penumbra.sln index 46609f85..94a04ef3 100644 --- a/Penumbra.sln +++ b/Penumbra.sln @@ -8,7 +8,10 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F89C9EAE-25C8-43BE-8108-5921E5A93502}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + .github\workflows\build.yml = .github\workflows\build.yml + .github\workflows\release.yml = .github\workflows\release.yml repo.json = repo.json + .github\workflows\test_release.yml = .github\workflows\test_release.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra.GameData\Penumbra.GameData.csproj", "{EE551E87-FDB3-4612-B500-DC870C07C605}" diff --git a/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs b/Penumbra/Interop/Hooks/ResourceLoading/ResourceLoader.cs index bcd09b37..442bac15 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 TexMdlService _texMdlService; + private readonly TexMdlScdService _texMdlScdService; private readonly PapHandler _papHandler; private readonly Configuration _config; private ResolveData _resolvedData = ResolveData.Invalid; public event Action? PapRequested; - public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlService texMdlService, Configuration config) + public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlScdService texMdlScdService, Configuration config) { _resources = resources; _fileReadService = fileReadService; - _texMdlService = texMdlService; + _texMdlScdService = texMdlScdService; _config = config; ResetResolvePath(); @@ -140,7 +140,7 @@ public unsafe class ResourceLoader : IDisposable, IService return; } - _texMdlService.AddCrc(type, resolvedPath); + _texMdlScdService.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/TexMdlService.cs index d4a2dfba..9c17e0cf 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/TexMdlService.cs @@ -10,7 +10,7 @@ using ResourceHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle.Re namespace Penumbra.Interop.Hooks.ResourceLoading; -public unsafe class TexMdlService : IDisposable, IRequiredService +public unsafe class TexMdlScdService : IDisposable, IRequiredService { /// /// We need to be able to obtain the requested LoD level. @@ -42,7 +42,7 @@ public unsafe class TexMdlService : IDisposable, IRequiredService private readonly LodService _lodService; - public TexMdlService(IGameInteropProvider interop) + public TexMdlScdService(IGameInteropProvider interop) { interop.InitializeFromAttributes(this); _lodService = new LodService(interop); @@ -52,6 +52,7 @@ public unsafe class TexMdlService : IDisposable, IRequiredService _loadMdlFileExternHook.Enable(); if (!HookOverrides.Instance.ResourceLoading.TexResourceHandleOnLoad) _textureOnLoadHook.Enable(); + _soundOnLoadHook.Enable(); } /// Add CRC64 if the given file is a model or texture file and has an associated path. @@ -59,8 +60,9 @@ public unsafe class TexMdlService : IDisposable, IRequiredService { _ = type switch { - ResourceType.Mdl when path.HasValue => _customMdlCrc.Add(path.Value.Crc64), - ResourceType.Tex when path.HasValue => _customTexCrc.Add(path.Value.Crc64), + ResourceType.Mdl when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Mdl), + ResourceType.Tex when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Tex), + ResourceType.Scd when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Scd), _ => false, }; } @@ -70,15 +72,16 @@ public unsafe class TexMdlService : IDisposable, IRequiredService _checkFileStateHook.Dispose(); _loadMdlFileExternHook.Dispose(); _textureOnLoadHook.Dispose(); + _soundOnLoadHook.Dispose(); } /// /// We need to keep a list of all CRC64 hash values of our replaced Mdl and Tex files, /// i.e. CRC32 of filename in the lower bytes, CRC32 of parent path in the upper bytes. /// - private readonly HashSet _customMdlCrc = []; - - private readonly HashSet _customTexCrc = []; + private readonly Dictionary _customFileCrc = []; + public IReadOnlyDictionary CustomCache + => _customFileCrc; private delegate nint CheckFileStatePrototype(nint unk1, ulong crc64); @@ -86,12 +89,34 @@ public unsafe class TexMdlService : IDisposable, IRequiredService private readonly Hook _checkFileStateHook = null!; private readonly ThreadLocal _texReturnData = new(() => default); + private readonly ThreadLocal _scdReturnData = new(() => default); private delegate void UpdateCategoryDelegate(TextureResourceHandle* resourceHandle); [Signature(Sigs.TexHandleUpdateCategory)] private readonly UpdateCategoryDelegate _updateCategory = null!; + private delegate byte SoundOnLoadDelegate(ResourceHandle* handle, SeFileDescriptor* descriptor, byte unk); + + [Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 8B 79 ?? 48 8B DA 8B D7")] + private readonly delegate* unmanaged _loadScdFileLocal = null!; + + [Signature("40 56 57 41 54 48 81 EC 90 00 00 00 80 3A 0B 45 0F B6 E0 48 8B F2", DetourName = nameof(OnScdLoadDetour))] + private readonly Hook _soundOnLoadHook = null!; + + private byte OnScdLoadDetour(ResourceHandle* handle, SeFileDescriptor* descriptor, byte unk) + { + var ret = _soundOnLoadHook.Original(handle, descriptor, unk); + if (!_scdReturnData.Value) + return ret; + + // Function failed on a replaced scd, call local. + _scdReturnData.Value = false; + ret = _loadScdFileLocal(handle, descriptor, unk); + _updateCategory((TextureResourceHandle*)handle); + return ret; + } + /// /// The function that checks a files CRC64 to determine whether it is 'protected'. /// We use it to check against our stored CRC64s and if it corresponds, we return the custom flag for models. @@ -100,14 +125,17 @@ public unsafe class TexMdlService : IDisposable, IRequiredService /// private nint CheckFileStateDetour(nint ptr, ulong crc64) { - if (_customMdlCrc.Contains(crc64)) - return CustomFileFlag; - - if (_customTexCrc.Contains(crc64)) - { - _texReturnData.Value = true; - return nint.Zero; - } + if (_customFileCrc.TryGetValue(crc64, out var type)) + switch (type) + { + case ResourceType.Mdl: return CustomFileFlag; + case ResourceType.Tex: + _texReturnData.Value = true; + return nint.Zero; + case ResourceType.Scd: + _scdReturnData.Value = true; + return nint.Zero; + } var ret = _checkFileStateHook.Original(ptr, crc64); Penumbra.Log.Excessive($"[CheckFileState] Called on 0x{ptr:X} with CRC {crc64:X16}, returned 0x{ret:X}."); @@ -128,10 +156,10 @@ public unsafe class TexMdlService : IDisposable, IRequiredService private delegate byte TexResourceHandleOnLoadPrototype(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2); - [Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnLoadDetour))] + [Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnTexLoadDetour))] private readonly Hook _textureOnLoadHook = null!; - private byte OnLoadDetour(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2) + private byte OnTexLoadDetour(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2) { var ret = _textureOnLoadHook.Original(handle, descriptor, unk2); if (!_texReturnData.Value) diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index 47c2c16c..9184ffe8 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -102,6 +102,7 @@ public class DebugTab : Window, ITab, IUiService private readonly CrashHandlerPanel _crashHandlerPanel; private readonly TexHeaderDrawer _texHeaderDrawer; private readonly HookOverrideDrawer _hookOverrides; + private readonly TexMdlScdService _texMdlScdService; public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects, IClientState clientState, @@ -112,7 +113,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) + HookOverrideDrawer hookOverrides, TexMdlScdService texMdlScdService) : base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse) { IsOpen = true; @@ -150,6 +151,7 @@ public class DebugTab : Window, ITab, IUiService _crashHandlerPanel = crashHandlerPanel; _texHeaderDrawer = texHeaderDrawer; _hookOverrides = hookOverrides; + _texMdlScdService = texMdlScdService; _objects = objects; _clientState = clientState; } @@ -183,6 +185,7 @@ public class DebugTab : Window, ITab, IUiService DrawDebugCharacterUtility(); DrawShaderReplacementFixer(); DrawData(); + DrawCrcCache(); DrawResourceProblems(); _hookOverrides.Draw(); DrawPlayerModelInfo(); @@ -1021,6 +1024,30 @@ public class DebugTab : Window, ITab, IUiService DrawDebugResidentResources(); } + private unsafe void DrawCrcCache() + { + var header = ImUtf8.CollapsingHeader("CRC Cache"u8); + if (!header) + return; + + using var table = ImUtf8.Table("table"u8, 2); + if (!table) + return; + + using var font = ImRaii.PushFont(UiBuilder.MonoFont); + ImUtf8.TableSetupColumn("Hash"u8, ImGuiTableColumnFlags.WidthFixed, 18 * UiBuilder.MonoFont.GetCharAdvance('0')); + ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, 5 * UiBuilder.MonoFont.GetCharAdvance('0')); + ImGui.TableHeadersRow(); + + foreach (var (hash, type) in _texMdlScdService.CustomCache) + { + ImGui.TableNextColumn(); + ImUtf8.Text($"{hash:X16}"); + ImGui.TableNextColumn(); + ImUtf8.Text($"{type}"); + } + } + /// Draw resources with unusual reference count. private unsafe void DrawResourceProblems() { From 41718d8f8fd9106136691f14588fab33b3073269 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 18 Nov 2024 00:28:36 +0100 Subject: [PATCH 13/18] Fix screen actor indices. --- Penumbra.GameData | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Penumbra.GameData b/Penumbra.GameData index fb81a0b5..79d8d782 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit fb81a0b55d3c68f2b26357fac3049c79fb0c22fb +Subproject commit 79d8d782b3b454a41f7f87f398806ec4d08d485f From 0928d712c91e7ea893c8088d51af63221be486fe Mon Sep 17 00:00:00 2001 From: Actions User Date: Sun, 17 Nov 2024 23:30:41 +0000 Subject: [PATCH 14/18] [CI] Updating repo.json for testing_1.3.0.3 --- repo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repo.json b/repo.json index 651802a6..77f5012e 100644 --- a/repo.json +++ b/repo.json @@ -6,7 +6,7 @@ "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", "AssemblyVersion": "1.3.0.0", - "TestingAssemblyVersion": "1.3.0.2", + "TestingAssemblyVersion": "1.3.0.3", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 10, @@ -19,7 +19,7 @@ "LoadRequiredState": 2, "LoadSync": true, "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.2/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.3/Penumbra.zip", "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } From 8a53313c33d0a42edfbbdf09a141525f7db14794 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 18 Nov 2024 20:14:06 +0100 Subject: [PATCH 15/18] Add .atch file debugging. --- Penumbra.GameData | 2 +- Penumbra/UI/Tabs/Debug/AtchDrawer.cs | 56 ++++++++++++++++++++++++++++ Penumbra/UI/Tabs/Debug/DebugTab.cs | 29 +++++++++++++- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 Penumbra/UI/Tabs/Debug/AtchDrawer.cs diff --git a/Penumbra.GameData b/Penumbra.GameData index 79d8d782..1c82c086 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 79d8d782b3b454a41f7f87f398806ec4d08d485f +Subproject commit 1c82c086704e2f1b3608644a9b1d70628fbe0ca9 diff --git a/Penumbra/UI/Tabs/Debug/AtchDrawer.cs b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs new file mode 100644 index 00000000..f6f6c50e --- /dev/null +++ b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs @@ -0,0 +1,56 @@ +using ImGuiNET; +using OtterGui; +using OtterGui.Text; +using Penumbra.GameData.Files; + +namespace Penumbra.UI.Tabs.Debug; + +public static class AtchDrawer +{ + public static void Draw(AtchFile file) + { + using (ImUtf8.Group()) + { + ImUtf8.Text("Entries: "u8); + ImUtf8.Text("States: "u8); + } + + ImGui.SameLine(); + using (ImUtf8.Group()) + { + ImUtf8.Text($"{file.Entries.Count}"); + if (file.Entries.Count == 0) + { + ImUtf8.Text("0"u8); + return; + } + + ImUtf8.Text($"{file.Entries[0].States.Count}"); + } + + foreach (var (entry, index) in file.Entries.WithIndex()) + { + using var id = ImUtf8.PushId(index); + using var tree = ImUtf8.TreeNode(entry.Name.Span); + if (tree) + { + ImUtf8.TreeNode(entry.Accessory ? "Accessory"u8 : "Weapon"u8, ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + foreach (var (state, i) in entry.States.WithIndex()) + { + id.Push(i); + using var t = ImUtf8.TreeNode(state.Bone.Span); + if (t) + { + ImUtf8.TreeNode($"Scale: {state.Scale}", ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + ImUtf8.TreeNode($"Offset: {state.Offset.X} | {state.Offset.Y} | {state.Offset.Z}", + ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + ImUtf8.TreeNode($"Rotation: {state.Rotation.X} | {state.Rotation.Y} | {state.Rotation.Z}", + ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + } + + id.Pop(); + } + } + } + } +} diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index 9184ffe8..cdaaadaa 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -98,6 +98,7 @@ public class DebugTab : Window, ITab, IUiService 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; @@ -105,7 +106,7 @@ public class DebugTab : Window, ITab, IUiService private readonly TexMdlScdService _texMdlScdService; public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects, - IClientState clientState, + IClientState clientState, IDataManager dataManager, ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources, ResourceManagerService resourceManager, CollectionResolver collectionResolver, @@ -154,6 +155,7 @@ public class DebugTab : Window, ITab, IUiService _texMdlScdService = texMdlScdService; _objects = objects; _clientState = clientState; + _dataManager = dataManager; } public ReadOnlySpan Label @@ -665,11 +667,36 @@ public class DebugTab : Window, ITab, IUiService DrawEmotes(); DrawStainTemplates(); + DrawAtch(); } private string _emoteSearchFile = string.Empty; private string _emoteSearchName = string.Empty; + + private AtchFile? _atchFile; + + private void DrawAtch() + { + try + { + _atchFile ??= new AtchFile(_dataManager.GetFile("chara/xls/attachOffset/c0101.atch")!.Data); + } + catch + { + // ignored + } + + if (_atchFile == null) + return; + + using var mainTree = ImUtf8.TreeNode("Atch File C0101"u8); + if (!mainTree) + return; + + AtchDrawer.Draw(_atchFile); + } + private void DrawEmotes() { using var mainTree = TreeNode("Emotes"); From 3beef61c6f04e6bc40ffb40be998d8cf14546cee Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 20 Nov 2024 10:44:09 +0100 Subject: [PATCH 16/18] Some debug vis improvements, disable .atch file modding for the moment until modular .atch file modding is implemented. --- .../Interop/PathResolving/PathResolver.cs | 4 ++ Penumbra/UI/Tabs/Debug/AtchDrawer.cs | 2 +- Penumbra/UI/Tabs/Debug/DebugTab.cs | 51 +++++++++++++------ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Penumbra/Interop/PathResolving/PathResolver.cs b/Penumbra/Interop/PathResolving/PathResolver.cs index 63bbc8d8..a7af42e3 100644 --- a/Penumbra/Interop/PathResolving/PathResolver.cs +++ b/Penumbra/Interop/PathResolving/PathResolver.cs @@ -52,6 +52,10 @@ public class PathResolver : IDisposable, IService if (resourceType is ResourceType.Lvb or ResourceType.Lgb or ResourceType.Sgb) return (null, ResolveData.Invalid); + // Prevent .atch loading to prevent crashes on outdated .atch files. TODO: handle atch modding differently. + if (resourceType is ResourceType.Atch) + return (null, ResolveData.Invalid); + return category switch { // Only Interface collection. diff --git a/Penumbra/UI/Tabs/Debug/AtchDrawer.cs b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs index f6f6c50e..3e407e99 100644 --- a/Penumbra/UI/Tabs/Debug/AtchDrawer.cs +++ b/Penumbra/UI/Tabs/Debug/AtchDrawer.cs @@ -31,7 +31,7 @@ public static class AtchDrawer foreach (var (entry, index) in file.Entries.WithIndex()) { using var id = ImUtf8.PushId(index); - using var tree = ImUtf8.TreeNode(entry.Name.Span); + using var tree = ImUtf8.TreeNode($"{index:D3}: {entry.Name.Span}"); if (tree) { ImUtf8.TreeNode(entry.Accessory ? "Accessory"u8 : "Weapon"u8, ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index cdaaadaa..28911b05 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -42,6 +42,7 @@ using Penumbra.Api.IpcTester; using Penumbra.Interop.Hooks.PostProcessing; using Penumbra.Interop.Hooks.ResourceLoading; using Penumbra.GameData.Files.StainMapStructs; +using Penumbra.String.Classes; using Penumbra.UI.AdvancedWindow.Materials; namespace Penumbra.UI.Tabs.Debug; @@ -196,7 +197,7 @@ public class DebugTab : Window, ITab, IUiService } - private void DrawCollectionCaches() + private unsafe void DrawCollectionCaches() { if (!ImGui.CollapsingHeader( $"Collections ({_collectionManager.Caches.Count}/{_collectionManager.Storage.Count - 1} Caches)###Collections")) @@ -207,25 +208,35 @@ public class DebugTab : Window, ITab, IUiService if (collection.HasCache) { using var color = PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value()); - using var node = TreeNode($"{collection.AnonymizedName} (Change Counter {collection.ChangeCounter})"); + using var node = TreeNode($"{collection.Name} (Change Counter {collection.ChangeCounter})###{collection.Name}"); if (!node) continue; color.Pop(); - foreach (var (mod, paths, manips) in collection._cache!.ModData.Data.OrderBy(t => t.Item1.Name)) + using (var resourceNode = ImUtf8.TreeNode("Custom Resources"u8)) { - using var id = mod is TemporaryMod t ? PushId(t.Priority.Value) : PushId(((Mod)mod).ModPath.Name); - using var node2 = TreeNode(mod.Name.Text); - if (!node2) - continue; - - foreach (var path in paths) - - TreeNode(path.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); - - foreach (var manip in manips) - TreeNode(manip.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + if (resourceNode) + foreach (var (path, resource) in collection._cache!.CustomResources) + ImUtf8.TreeNode($"{path} -> 0x{(ulong)resource.ResourceHandle:X}", + ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); } + + using var modNode = ImUtf8.TreeNode("Enabled Mods"u8); + if (modNode) + foreach (var (mod, paths, manips) in collection._cache!.ModData.Data.OrderBy(t => t.Item1.Name)) + { + using var id = mod is TemporaryMod t ? PushId(t.Priority.Value) : PushId(((Mod)mod).ModPath.Name); + using var node2 = TreeNode(mod.Name.Text); + if (!node2) + continue; + + foreach (var path in paths) + + TreeNode(path.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + + foreach (var manip in manips) + TreeNode(manip.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + } } else { @@ -1051,17 +1062,27 @@ public class DebugTab : Window, ITab, IUiService DrawDebugResidentResources(); } + private string _crcInput = string.Empty; + private FullPath _crcPath = FullPath.Empty; + private unsafe void DrawCrcCache() { var header = ImUtf8.CollapsingHeader("CRC Cache"u8); if (!header) return; + if (ImUtf8.InputText("##crcInput"u8, ref _crcInput, "Input path for CRC..."u8)) + _crcPath = new FullPath(_crcInput); + + using var font = ImRaii.PushFont(UiBuilder.MonoFont); + ImUtf8.Text($" CRC32: {_crcPath.InternalName.CiCrc32:X8}"); + ImUtf8.Text($"CI CRC32: {_crcPath.InternalName.Crc32:X8}"); + ImUtf8.Text($" CRC64: {_crcPath.Crc64:X16}"); + using var table = ImUtf8.Table("table"u8, 2); if (!table) return; - using var font = ImRaii.PushFont(UiBuilder.MonoFont); ImUtf8.TableSetupColumn("Hash"u8, ImGuiTableColumnFlags.WidthFixed, 18 * UiBuilder.MonoFont.GetCharAdvance('0')); ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, 5 * UiBuilder.MonoFont.GetCharAdvance('0')); ImGui.TableHeadersRow(); From 688b84141f3ea1964f7f589503d3af516b1531d4 Mon Sep 17 00:00:00 2001 From: Actions User Date: Wed, 20 Nov 2024 09:46:01 +0000 Subject: [PATCH 17/18] [CI] Updating repo.json for testing_1.3.0.4 --- repo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repo.json b/repo.json index 77f5012e..02437b14 100644 --- a/repo.json +++ b/repo.json @@ -6,7 +6,7 @@ "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", "AssemblyVersion": "1.3.0.0", - "TestingAssemblyVersion": "1.3.0.3", + "TestingAssemblyVersion": "1.3.0.4", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 10, @@ -19,7 +19,7 @@ "LoadRequiredState": 2, "LoadSync": true, "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.3/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.3.0.4/Penumbra.zip", "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.3.0.0/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } From ce75471e5129068ba765cbff8cdad5626866c31d Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 20 Nov 2024 18:08:24 +0100 Subject: [PATCH 18/18] Fix issue with resetting GEQP parameters on reload (again?) --- Penumbra.GameData | 2 +- Penumbra.String | 2 +- Penumbra/Meta/Manipulations/MetaDictionary.cs | 11 +++++++++++ Penumbra/Mods/Editor/ModMetaEditor.cs | 3 ++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Penumbra.GameData b/Penumbra.GameData index 1c82c086..c855c17c 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 1c82c086704e2f1b3608644a9b1d70628fbe0ca9 +Subproject commit c855c17cffd7d270c3f013e01767cd052c24c462 diff --git a/Penumbra.String b/Penumbra.String index bd52d080..dd83f972 160000 --- a/Penumbra.String +++ b/Penumbra.String @@ -1 +1 @@ -Subproject commit bd52d080b72d67263dc47068e461f17c93bdc779 +Subproject commit dd83f97299ac33cfacb1064bde4f4d1f6a260936 diff --git a/Penumbra/Meta/Manipulations/MetaDictionary.cs b/Penumbra/Meta/Manipulations/MetaDictionary.cs index 70d4fd47..da061bec 100644 --- a/Penumbra/Meta/Manipulations/MetaDictionary.cs +++ b/Penumbra/Meta/Manipulations/MetaDictionary.cs @@ -79,6 +79,17 @@ public class MetaDictionary _globalEqp.Clear(); } + public void ClearForDefault() + { + Count = _globalEqp.Count; + _imc.Clear(); + _eqp.Clear(); + _eqdp.Clear(); + _est.Clear(); + _rsp.Clear(); + _gmp.Clear(); + } + public bool Equals(MetaDictionary other) => Count == other.Count && _imc.SetEquals(other._imc) diff --git a/Penumbra/Mods/Editor/ModMetaEditor.cs b/Penumbra/Mods/Editor/ModMetaEditor.cs index 64c585ea..217ba93d 100644 --- a/Penumbra/Mods/Editor/ModMetaEditor.cs +++ b/Penumbra/Mods/Editor/ModMetaEditor.cs @@ -69,7 +69,8 @@ public class ModMetaEditor( public static bool DeleteDefaultValues(MetaFileManager metaFileManager, MetaDictionary dict) { var clone = dict.Clone(); - dict.Clear(); + dict.ClearForDefault(); + var count = 0; foreach (var (key, value) in clone.Imc) {