From c6de7ddebd7af3b52ecb5ebebe86efef07597b1e Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 27 Feb 2025 13:08:41 +0100 Subject: [PATCH] Improve GamePaths and parsing, add support for identifying skeletons and phybs. --- Penumbra.GameData | 2 +- Penumbra/Import/Models/ModelManager.cs | 12 ++++---- .../ResolveContext.PathResolution.cs | 14 ++++----- .../Interop/ResourceTree/ResolveContext.cs | 12 ++++---- Penumbra/Interop/ResourceTree/ResourceTree.cs | 8 ++--- Penumbra/Meta/Manipulations/Eqdp.cs | 2 +- Penumbra/Meta/Manipulations/Eqp.cs | 2 +- Penumbra/Meta/Manipulations/Est.cs | 8 ++--- .../Manipulations/GlobalEqpManipulation.cs | 10 +++---- Penumbra/Meta/Manipulations/Gmp.cs | 2 +- Penumbra/Meta/Manipulations/Imc.cs | 24 +++++---------- Penumbra/Mods/ItemSwap/CustomizationSwap.cs | 10 +++---- Penumbra/Mods/ItemSwap/EquipmentSwap.cs | 30 +++++++------------ Penumbra/Mods/ItemSwap/ItemSwap.cs | 4 +-- .../Materials/MtrlTab.ShaderPackage.cs | 2 +- .../UI/AdvancedWindow/Meta/AtchMetaDrawer.cs | 4 +-- .../UI/AdvancedWindow/ModEditWindow.Meta.cs | 2 +- 17 files changed, 65 insertions(+), 83 deletions(-) diff --git a/Penumbra.GameData b/Penumbra.GameData index f42c7fc9..bc339208 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit f42c7fc9de98e9fc72680dee7805251fd938af26 +Subproject commit bc339208d1d453582eb146533c572823146a4592 diff --git a/Penumbra/Import/Models/ModelManager.cs b/Penumbra/Import/Models/ModelManager.cs index 0c19bc0a..19d06a52 100644 --- a/Penumbra/Import/Models/ModelManager.cs +++ b/Penumbra/Import/Models/ModelManager.cs @@ -63,7 +63,7 @@ public sealed class ModelManager(IFramework framework, MetaFileManager metaFileM if (info.FileType is not FileType.Model) return []; - var baseSkeleton = GamePaths.Skeleton.Sklb.Path(info.GenderRace, "base", 1); + var baseSkeleton = GamePaths.Sklb.Customization(info.GenderRace, "base", 1); return info.ObjectType switch { @@ -79,9 +79,9 @@ public sealed class ModelManager(IFramework framework, MetaFileManager metaFileM ObjectType.Character when info.BodySlot is BodySlot.Face or BodySlot.Ear => [baseSkeleton, ..ResolveEstSkeleton(EstType.Face, info, estManipulations)], ObjectType.Character => throw new Exception($"Currently unsupported human model type \"{info.BodySlot}\"."), - ObjectType.DemiHuman => [GamePaths.DemiHuman.Sklb.Path(info.PrimaryId)], - ObjectType.Monster => [GamePaths.Monster.Sklb.Path(info.PrimaryId)], - ObjectType.Weapon => [GamePaths.Weapon.Sklb.Path(info.PrimaryId)], + ObjectType.DemiHuman => [GamePaths.Sklb.DemiHuman(info.PrimaryId)], + ObjectType.Monster => [GamePaths.Sklb.Monster(info.PrimaryId)], + ObjectType.Weapon => [GamePaths.Sklb.Weapon(info.PrimaryId)], _ => [], }; } @@ -105,7 +105,7 @@ public sealed class ModelManager(IFramework framework, MetaFileManager metaFileM if (targetId == EstEntry.Zero) return []; - return [GamePaths.Skeleton.Sklb.Path(info.GenderRace, type.ToName(), targetId.AsId)]; + return [GamePaths.Sklb.Customization(info.GenderRace, type.ToName(), targetId.AsId)]; } /// Try to resolve the absolute path to a .mtrl from the potentially-partial path provided by a model. @@ -137,7 +137,7 @@ public sealed class ModelManager(IFramework framework, MetaFileManager metaFileM var resolvedPath = info.ObjectType switch { - ObjectType.Character => GamePaths.Character.Mtrl.Path( + ObjectType.Character => GamePaths.Mtrl.Customization( info.GenderRace, info.BodySlot, info.PrimaryId, relativePath, out _, out _, info.Variant), _ => absolutePath, }; diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs b/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs index b1ca24b0..b6d04769 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.PathResolution.cs @@ -43,8 +43,8 @@ internal partial record ResolveContext private Utf8GamePath ResolveEquipmentModelPath() { var path = IsEquipmentSlot(SlotIndex) - ? GamePaths.Equipment.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()) - : GamePaths.Accessory.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()); + ? GamePaths.Mdl.Equipment(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()) + : GamePaths.Mdl.Accessory(Equipment.Set, ResolveModelRaceCode(), SlotIndex.ToEquipSlot()); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } @@ -122,7 +122,7 @@ internal partial record ResolveContext var setIdHigh = Equipment.Set.Id / 100; // All MCH (20??) weapons' materials C are one and the same if (setIdHigh is 20 && mtrlFileName[14] == (byte)'c') - return Utf8GamePath.FromString(GamePaths.Weapon.Mtrl.Path(2001, 1, 1, "c"), out var path) ? path : Utf8GamePath.Empty; + return Utf8GamePath.FromString(GamePaths.Mtrl.Weapon(2001, 1, 1, "c"), out var path) ? path : Utf8GamePath.Empty; // Some offhands share materials with the corresponding mainhand if (ItemData.AdaptOffhandImc(Equipment.Set, out var mirroredSetId)) @@ -230,7 +230,7 @@ internal partial record ResolveContext if (set == 0) return Utf8GamePath.Empty; - var path = GamePaths.Skeleton.Sklb.Path(raceCode, slot, set); + var path = GamePaths.Sklb.Customization(raceCode, slot, set); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } @@ -300,7 +300,7 @@ internal partial record ResolveContext if (set.Id is 0) return Utf8GamePath.Empty; - var path = GamePaths.Skeleton.Skp.Path(raceCode, slot, set); + var path = GamePaths.Skp.Customization(raceCode, slot, set); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } @@ -328,7 +328,7 @@ internal partial record ResolveContext if (set.Id is 0) return Utf8GamePath.Empty; - var path = GamePaths.Skeleton.Phyb.Path(raceCode, slot, set); + var path = GamePaths.Phyb.Customization(raceCode, slot, set); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } @@ -354,7 +354,7 @@ internal partial record ResolveContext if (decal is 0) return Utf8GamePath.Empty; - var path = GamePaths.Equipment.Decal.Path(decal); + var path = GamePaths.Tex.EquipDecal(decal); return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty; } } diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.cs b/Penumbra/Interop/ResourceTree/ResolveContext.cs index 81904819..ea4506c7 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.cs @@ -355,13 +355,10 @@ internal unsafe partial record ResolveContext( if (sklbHandle is null) return null; - if (!Utf8GamePath.FromString(GamePaths.Skeleton.Sklb.MaterialAnimationSkeletonPath, out var path)) - return null; - - if (Global.Nodes.TryGetValue((path, (nint)sklbHandle), out var cached)) + if (Global.Nodes.TryGetValue((GamePaths.Sklb.MaterialAnimationSkeletonUtf8, (nint)sklbHandle), out var cached)) return cached; - var node = CreateNode(ResourceType.Sklb, 0, (ResourceHandle*)sklbHandle, path); + var node = CreateNode(ResourceType.Sklb, 0, (ResourceHandle*)sklbHandle, GamePaths.Sklb.MaterialAnimationSkeletonUtf8); node.ForceInternal = true; return node; @@ -455,11 +452,12 @@ internal unsafe partial record ResolveContext( internal ResourceNode.UiData GuessUiDataFromPath(Utf8GamePath gamePath) { + const string customization = "Customization: "; foreach (var obj in Global.Identifier.Identify(gamePath.ToString())) { var name = obj.Key; - if (obj.Value is IdentifiedCustomization) - name = name[14..].Trim(); + if (name.StartsWith(customization)) + name = name.AsSpan(14).Trim().ToString(); if (name is not "Unknown") return new ResourceNode.UiData(name, obj.Value.GetIcon().ToFlag()); } diff --git a/Penumbra/Interop/ResourceTree/ResourceTree.cs b/Penumbra/Interop/ResourceTree/ResourceTree.cs index 5e3f52d4..7be8694a 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTree.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTree.cs @@ -207,8 +207,8 @@ public class ResourceTree( var decalId = (byte)(human->Customize[(int)CustomizeIndex.Facepaint] & 0x7F); var decalPath = decalId is not 0 - ? GamePaths.Human.Decal.FaceDecalPath(decalId) - : GamePaths.Tex.TransparentPath; + ? GamePaths.Tex.FaceDecal(decalId) + : GamePaths.Tex.Transparent; if (genericContext.CreateNodeFromTex(human->Decal, decalPath) is { } decalNode) { if (globalContext.WithUiData) @@ -223,8 +223,8 @@ public class ResourceTree( var hasLegacyDecal = (human->Customize[(int)CustomizeIndex.FaceFeatures] & 0x80) != 0; var legacyDecalPath = hasLegacyDecal - ? GamePaths.Human.Decal.LegacyDecalPath - : GamePaths.Tex.TransparentPath; + ? GamePaths.Tex.LegacyDecal + : GamePaths.Tex.Transparent; if (genericContext.CreateNodeFromTex(human->LegacyBodyDecal, legacyDecalPath) is { } legacyDecalNode) { legacyDecalNode.ForceProtected = !hasLegacyDecal; diff --git a/Penumbra/Meta/Manipulations/Eqdp.cs b/Penumbra/Meta/Manipulations/Eqdp.cs index 3a804d0c..285f2309 100644 --- a/Penumbra/Meta/Manipulations/Eqdp.cs +++ b/Penumbra/Meta/Manipulations/Eqdp.cs @@ -16,7 +16,7 @@ public readonly record struct EqdpIdentifier(PrimaryId SetId, EquipSlot Slot, Ge => GenderRace.Split().Item1; public void AddChangedItems(ObjectIdentification identifier, IDictionary changedItems) - => identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(SetId, GenderRace, Slot)); + => identifier.Identify(changedItems, GamePaths.Mdl.Equipment(SetId, GenderRace, Slot)); public MetaIndex FileIndex() => CharacterUtilityData.EqdpIdx(GenderRace, Slot.IsAccessory()); diff --git a/Penumbra/Meta/Manipulations/Eqp.cs b/Penumbra/Meta/Manipulations/Eqp.cs index f758126c..c71f2f4d 100644 --- a/Penumbra/Meta/Manipulations/Eqp.cs +++ b/Penumbra/Meta/Manipulations/Eqp.cs @@ -9,7 +9,7 @@ namespace Penumbra.Meta.Manipulations; public readonly record struct EqpIdentifier(PrimaryId SetId, EquipSlot Slot) : IMetaIdentifier, IComparable { public void AddChangedItems(ObjectIdentification identifier, IDictionary changedItems) - => identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(SetId, GenderRace.MidlanderMale, Slot)); + => identifier.Identify(changedItems, GamePaths.Mdl.Equipment(SetId, GenderRace.MidlanderMale, Slot)); public MetaIndex FileIndex() => MetaIndex.Eqp; diff --git a/Penumbra/Meta/Manipulations/Est.cs b/Penumbra/Meta/Manipulations/Est.cs index cfe9b7d4..007cd02f 100644 --- a/Penumbra/Meta/Manipulations/Est.cs +++ b/Penumbra/Meta/Manipulations/Est.cs @@ -30,17 +30,17 @@ public readonly record struct EstIdentifier(PrimaryId SetId, EstType Slot, Gende { case EstType.Hair: changedItems.TryAdd( - $"Customization: {GenderRace.Split().Item2.ToName()} {GenderRace.Split().Item1.ToName()} Hair (Hair) {SetId}", null); + $"Customization: {GenderRace.Split().Item2.ToName()} {GenderRace.Split().Item1.ToName()} Hair {SetId}", null); break; case EstType.Face: changedItems.TryAdd( - $"Customization: {GenderRace.Split().Item2.ToName()} {GenderRace.Split().Item1.ToName()} Face (Face) {SetId}", null); + $"Customization: {GenderRace.Split().Item2.ToName()} {GenderRace.Split().Item1.ToName()} Face {SetId}", null); break; case EstType.Body: - identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(SetId, GenderRace, EquipSlot.Body)); + identifier.Identify(changedItems, GamePaths.Mdl.Equipment(SetId, GenderRace, EquipSlot.Body)); break; case EstType.Head: - identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(SetId, GenderRace, EquipSlot.Head)); + identifier.Identify(changedItems, GamePaths.Mdl.Equipment(SetId, GenderRace, EquipSlot.Head)); break; } } diff --git a/Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs b/Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs index ec59762b..6a1ceaea 100644 --- a/Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs +++ b/Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs @@ -74,11 +74,11 @@ public readonly struct GlobalEqpManipulation : IMetaIdentifier { var path = Type switch { - GlobalEqpType.DoNotHideEarrings => GamePaths.Accessory.Mdl.Path(Condition, GenderRace.MidlanderMale, EquipSlot.Ears), - GlobalEqpType.DoNotHideNecklace => GamePaths.Accessory.Mdl.Path(Condition, GenderRace.MidlanderMale, EquipSlot.Neck), - GlobalEqpType.DoNotHideBracelets => GamePaths.Accessory.Mdl.Path(Condition, GenderRace.MidlanderMale, EquipSlot.Wrists), - GlobalEqpType.DoNotHideRingR => GamePaths.Accessory.Mdl.Path(Condition, GenderRace.MidlanderMale, EquipSlot.RFinger), - GlobalEqpType.DoNotHideRingL => GamePaths.Accessory.Mdl.Path(Condition, GenderRace.MidlanderMale, EquipSlot.LFinger), + GlobalEqpType.DoNotHideEarrings => GamePaths.Mdl.Accessory(Condition, GenderRace.MidlanderMale, EquipSlot.Ears), + GlobalEqpType.DoNotHideNecklace => GamePaths.Mdl.Accessory(Condition, GenderRace.MidlanderMale, EquipSlot.Neck), + GlobalEqpType.DoNotHideBracelets => GamePaths.Mdl.Accessory(Condition, GenderRace.MidlanderMale, EquipSlot.Wrists), + GlobalEqpType.DoNotHideRingR => GamePaths.Mdl.Accessory(Condition, GenderRace.MidlanderMale, EquipSlot.RFinger), + GlobalEqpType.DoNotHideRingL => GamePaths.Mdl.Accessory(Condition, GenderRace.MidlanderMale, EquipSlot.LFinger), GlobalEqpType.DoNotHideHrothgarHats => string.Empty, GlobalEqpType.DoNotHideVieraHats => string.Empty, _ => string.Empty, diff --git a/Penumbra/Meta/Manipulations/Gmp.cs b/Penumbra/Meta/Manipulations/Gmp.cs index 1f41adfb..8cd07bfd 100644 --- a/Penumbra/Meta/Manipulations/Gmp.cs +++ b/Penumbra/Meta/Manipulations/Gmp.cs @@ -9,7 +9,7 @@ namespace Penumbra.Meta.Manipulations; public readonly record struct GmpIdentifier(PrimaryId SetId) : IMetaIdentifier, IComparable { public void AddChangedItems(ObjectIdentification identifier, IDictionary changedItems) - => identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(SetId, GenderRace.MidlanderMale, EquipSlot.Head)); + => identifier.Identify(changedItems, GamePaths.Mdl.Equipment(SetId, GenderRace.MidlanderMale, EquipSlot.Head)); public MetaIndex FileIndex() => MetaIndex.Gmp; diff --git a/Penumbra/Meta/Manipulations/Imc.cs b/Penumbra/Meta/Manipulations/Imc.cs index cba6c379..6e893043 100644 --- a/Penumbra/Meta/Manipulations/Imc.cs +++ b/Penumbra/Meta/Manipulations/Imc.cs @@ -34,14 +34,14 @@ public readonly record struct ImcIdentifier( { var path = ObjectType switch { - ObjectType.Equipment when allVariants => GamePaths.Equipment.Mdl.Path(PrimaryId, GenderRace.MidlanderMale, EquipSlot), - ObjectType.Equipment => GamePaths.Equipment.Mtrl.Path(PrimaryId, GenderRace.MidlanderMale, EquipSlot, Variant, "a"), - ObjectType.Accessory when allVariants => GamePaths.Accessory.Mdl.Path(PrimaryId, GenderRace.MidlanderMale, EquipSlot), - ObjectType.Accessory => GamePaths.Accessory.Mtrl.Path(PrimaryId, GenderRace.MidlanderMale, EquipSlot, Variant, "a"), - ObjectType.Weapon => GamePaths.Weapon.Mtrl.Path(PrimaryId, SecondaryId.Id, Variant, "a"), - ObjectType.DemiHuman => GamePaths.DemiHuman.Mtrl.Path(PrimaryId, SecondaryId.Id, EquipSlot, Variant, + ObjectType.Equipment when allVariants => GamePaths.Mdl.Equipment(PrimaryId, GenderRace.MidlanderMale, EquipSlot), + ObjectType.Equipment => GamePaths.Mtrl.Equipment(PrimaryId, GenderRace.MidlanderMale, EquipSlot, Variant, "a"), + ObjectType.Accessory when allVariants => GamePaths.Mdl.Accessory(PrimaryId, GenderRace.MidlanderMale, EquipSlot), + ObjectType.Accessory => GamePaths.Mtrl.Accessory(PrimaryId, GenderRace.MidlanderMale, EquipSlot, Variant, "a"), + ObjectType.Weapon => GamePaths.Mtrl.Weapon(PrimaryId, SecondaryId.Id, Variant, "a"), + ObjectType.DemiHuman => GamePaths.Mtrl.DemiHuman(PrimaryId, SecondaryId.Id, EquipSlot, Variant, "a"), - ObjectType.Monster => GamePaths.Monster.Mtrl.Path(PrimaryId, SecondaryId.Id, Variant, "a"), + ObjectType.Monster => GamePaths.Mtrl.Monster(PrimaryId, SecondaryId.Id, Variant, "a"), _ => string.Empty, }; if (path.Length == 0) @@ -51,15 +51,7 @@ public readonly record struct ImcIdentifier( } public string GamePathString() - => ObjectType switch - { - ObjectType.Accessory => GamePaths.Accessory.Imc.Path(PrimaryId), - ObjectType.Equipment => GamePaths.Equipment.Imc.Path(PrimaryId), - ObjectType.DemiHuman => GamePaths.DemiHuman.Imc.Path(PrimaryId, SecondaryId.Id), - ObjectType.Monster => GamePaths.Monster.Imc.Path(PrimaryId, SecondaryId.Id), - ObjectType.Weapon => GamePaths.Weapon.Imc.Path(PrimaryId, SecondaryId.Id), - _ => string.Empty, - }; + => GamePaths.Imc.Path(ObjectType, PrimaryId, SecondaryId); public Utf8GamePath GamePath() => Utf8GamePath.FromString(GamePathString(), out var p) ? p : Utf8GamePath.Empty; diff --git a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs index cd36de93..c5406f66 100644 --- a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs +++ b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs @@ -17,8 +17,8 @@ public static class CustomizationSwap if (idFrom.Id > byte.MaxValue) throw new Exception($"The Customization ID {idFrom} is too large for {slot}."); - var mdlPathFrom = GamePaths.Character.Mdl.Path(race, slot, idFrom, slot.ToCustomizationType()); - var mdlPathTo = GamePaths.Character.Mdl.Path(race, slot, idTo, slot.ToCustomizationType()); + var mdlPathFrom = GamePaths.Mdl.Customization(race, slot, idFrom, slot.ToCustomizationType()); + var mdlPathTo = GamePaths.Mdl.Customization(race, slot, idTo, slot.ToCustomizationType()); var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo); var range = slot == BodySlot.Tail @@ -47,8 +47,8 @@ public static class CustomizationSwap ref string fileName, ref bool dataWasChanged) { variant = slot is BodySlot.Face or BodySlot.Ear ? Variant.None.Id : variant; - var mtrlFromPath = GamePaths.Character.Mtrl.Path(race, slot, idFrom, fileName, out var gameRaceFrom, out var gameSetIdFrom, variant); - var mtrlToPath = GamePaths.Character.Mtrl.Path(race, slot, idTo, fileName, out var gameRaceTo, out var gameSetIdTo, variant); + var mtrlFromPath = GamePaths.Mtrl.Customization(race, slot, idFrom, fileName, out var gameRaceFrom, out var gameSetIdFrom, variant); + var mtrlToPath = GamePaths.Mtrl.Customization(race, slot, idTo, fileName, out var gameRaceTo, out var gameSetIdTo, variant); var newFileName = fileName; newFileName = ItemSwap.ReplaceRace(newFileName, gameRaceTo, race, gameRaceTo != race); @@ -60,7 +60,7 @@ public static class CustomizationSwap var actualMtrlFromPath = mtrlFromPath; if (newFileName != fileName) { - actualMtrlFromPath = GamePaths.Character.Mtrl.Path(race, slot, idFrom, newFileName, out _, out _, variant); + actualMtrlFromPath = GamePaths.Mtrl.Customization(race, slot, idFrom, newFileName, out _, out _, variant); fileName = newFileName; dataWasChanged = true; } diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index 8c80c91c..5c67df52 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -107,7 +107,7 @@ public static class EquipmentSwap foreach (var child in eqp.ChildSwaps.SelectMany(c => c.WithChildren()).OfType>()) { affectedItems.UnionWith(identifier - .Identify(GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, child.SwapFromIdentifier.Slot)) + .Identify(GamePaths.Mdl.Equipment(idFrom, GenderRace.MidlanderMale, child.SwapFromIdentifier.Slot)) .Select(kvp => kvp.Value).OfType().Select(i => i.Item)); } } @@ -223,11 +223,9 @@ public static class EquipmentSwap public static FileSwap CreateMdl(MetaFileManager manager, Func redirections, EquipSlot slotFrom, EquipSlot slotTo, GenderRace gr, PrimaryId idFrom, PrimaryId idTo, byte mtrlTo) { - var mdlPathFrom = slotFrom.IsAccessory() - ? GamePaths.Accessory.Mdl.Path(idFrom, gr, slotFrom) - : GamePaths.Equipment.Mdl.Path(idFrom, gr, slotFrom); - var mdlPathTo = slotTo.IsAccessory() ? GamePaths.Accessory.Mdl.Path(idTo, gr, slotTo) : GamePaths.Equipment.Mdl.Path(idTo, gr, slotTo); - var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo); + var mdlPathFrom = GamePaths.Mdl.Gear(idFrom, gr, slotFrom); + var mdlPathTo = GamePaths.Mdl.Gear(idTo, gr, slotTo); + var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo); foreach (ref var fileName in mdl.AsMdl()!.Materials.AsSpan()) { @@ -264,9 +262,7 @@ public static class EquipmentSwap } else { - items = identifier.Identify(slotFrom.IsEquipment() - ? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom) - : GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)) + items = identifier.Identify(GamePaths.Mdl.Gear(idFrom, GenderRace.MidlanderMale, slotFrom)) .Select(kvp => kvp.Value).OfType().Select(i => i.Item) .ToHashSet(); variants = Enumerable.Range(0, imc.Count + 1).Select(i => (Variant)i).ToArray(); @@ -324,7 +320,7 @@ public static class EquipmentSwap if (decalId == 0) return null; - var decalPath = GamePaths.Equipment.Decal.Path(decalId); + var decalPath = GamePaths.Tex.EquipDecal(decalId); return FileSwap.CreateSwap(manager, ResourceType.Tex, redirections, decalPath, decalPath); } @@ -337,9 +333,9 @@ public static class EquipmentSwap if (vfxId == 0) return null; - var vfxPathFrom = GamePaths.Equipment.Avfx.Path(idFrom, vfxId); + var vfxPathFrom = GamePaths.Avfx.Path(slotFrom, idFrom, vfxId); vfxPathFrom = ItemSwap.ReplaceType(vfxPathFrom, slotFrom, slotTo, idFrom); - var vfxPathTo = GamePaths.Equipment.Avfx.Path(idTo, vfxId); + var vfxPathTo = GamePaths.Avfx.Path(slotTo, idTo, vfxId); var avfx = FileSwap.CreateSwap(manager, ResourceType.Avfx, redirections, vfxPathFrom, vfxPathTo); foreach (ref var filePath in avfx.AsAvfx()!.Textures.AsSpan()) @@ -402,14 +398,10 @@ public static class EquipmentSwap if (!fileName.Contains($"{prefix}{idTo.Id:D4}")) return null; - var folderTo = slotTo.IsAccessory() - ? GamePaths.Accessory.Mtrl.FolderPath(idTo, variantTo) - : GamePaths.Equipment.Mtrl.FolderPath(idTo, variantTo); + var folderTo = GamePaths.Mtrl.GearFolder(slotTo, idTo, variantTo); var pathTo = $"{folderTo}{fileName}"; - var folderFrom = slotFrom.IsAccessory() - ? GamePaths.Accessory.Mtrl.FolderPath(idFrom, variantTo) - : GamePaths.Equipment.Mtrl.FolderPath(idFrom, variantTo); + var folderFrom = GamePaths.Mtrl.GearFolder(slotFrom, idFrom, variantTo); var newFileName = ItemSwap.ReplaceId(fileName, prefix, idTo, idFrom); newFileName = ItemSwap.ReplaceSlot(newFileName, slotTo, slotFrom, slotTo != slotFrom); var pathFrom = $"{folderFrom}{newFileName}"; @@ -457,7 +449,7 @@ public static class EquipmentSwap public static FileSwap CreateShader(MetaFileManager manager, Func redirections, ref string shaderName, ref bool dataWasChanged) { - var path = $"shader/sm5/shpk/{shaderName}"; + var path = GamePaths.Shader(shaderName); return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path); } diff --git a/Penumbra/Mods/ItemSwap/ItemSwap.cs b/Penumbra/Mods/ItemSwap/ItemSwap.cs index 03abfc45..0049fa12 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwap.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwap.cs @@ -132,14 +132,14 @@ public static class ItemSwap public static FileSwap CreatePhyb(MetaFileManager manager, Func redirections, EstType type, GenderRace race, EstEntry estEntry) { - var phybPath = GamePaths.Skeleton.Phyb.Path(race, type.ToName(), estEntry.AsId); + var phybPath = GamePaths.Phyb.Customization(race, type.ToName(), estEntry.AsId); return FileSwap.CreateSwap(manager, ResourceType.Phyb, redirections, phybPath, phybPath); } public static FileSwap CreateSklb(MetaFileManager manager, Func redirections, EstType type, GenderRace race, EstEntry estEntry) { - var sklbPath = GamePaths.Skeleton.Sklb.Path(race, type.ToName(), estEntry.AsId); + var sklbPath = GamePaths.Sklb.Customization(race, type.ToName(), estEntry.AsId); return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath); } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs index ae57a122..a13dd96b 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs @@ -124,7 +124,7 @@ public partial class MtrlTab private FullPath FindAssociatedShpk(out string defaultPath, out Utf8GamePath defaultGamePath) { - defaultPath = GamePaths.Shader.ShpkPath(Mtrl.ShaderPackage.Name); + defaultPath = GamePaths.Shader(Mtrl.ShaderPackage.Name); if (!Utf8GamePath.FromString(defaultPath, out defaultGamePath)) return FullPath.Empty; diff --git a/Penumbra/UI/AdvancedWindow/Meta/AtchMetaDrawer.cs b/Penumbra/UI/AdvancedWindow/Meta/AtchMetaDrawer.cs index 66db0932..80b10607 100644 --- a/Penumbra/UI/AdvancedWindow/Meta/AtchMetaDrawer.cs +++ b/Penumbra/UI/AdvancedWindow/Meta/AtchMetaDrawer.cs @@ -55,7 +55,7 @@ public sealed class AtchMetaDrawer : MetaDrawer, ISer if (filePath.Length == 0 || !File.Exists(filePath)) throw new FileNotFoundException(); - var gr = GamePaths.ParseRaceCode(filePath); + var gr = Parser.ParseRaceCode(filePath); if (gr is GenderRace.Unknown) throw new Exception($"Could not identify race code from path {filePath}."); var text = File.ReadAllBytes(filePath); @@ -277,7 +277,7 @@ public sealed class AtchMetaDrawer : MetaDrawer, ISer if (!ret) return false; - index = Math.Clamp(index, (ushort)0, (ushort)(currentAtchPoint!.Entries.Length - 1)); + index = Math.Clamp(index, (ushort)0, (ushort)(currentAtchPoint.Entries.Length - 1)); identifier = identifier with { EntryIndex = index }; return true; } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs index 1356340c..c9a1d059 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs @@ -68,7 +68,7 @@ public partial class ModEditWindow { _dragDropManager.CreateImGuiSource("atchDrag", f => f.Extensions.Contains(".atch"), f => { - var gr = GamePaths.ParseRaceCode(f.Files.FirstOrDefault() ?? string.Empty); + var gr = Parser.ParseRaceCode(f.Files.FirstOrDefault() ?? string.Empty); if (gr is GenderRace.Unknown) return false;