mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
RT: Fix Facewear
This commit is contained in:
parent
243593e30f
commit
75e3ef72f3
2 changed files with 31 additions and 15 deletions
|
|
@ -16,20 +16,26 @@ namespace Penumbra.Interop.ResourceTree;
|
|||
|
||||
internal partial record ResolveContext
|
||||
{
|
||||
private static bool IsEquipmentOrAccessorySlot(uint slotIndex)
|
||||
=> slotIndex is < 10 or 16 or 17;
|
||||
|
||||
private static bool IsEquipmentSlot(uint slotIndex)
|
||||
=> slotIndex is < 5 or 16 or 17;
|
||||
|
||||
private Utf8GamePath ResolveModelPath()
|
||||
{
|
||||
// Correctness:
|
||||
// Resolving a model path through the game's code can use EQDP metadata for human equipment models.
|
||||
return ModelType switch
|
||||
{
|
||||
ModelType.Human when SlotIndex < 10 => ResolveEquipmentModelPath(),
|
||||
ModelType.Human when IsEquipmentOrAccessorySlot(SlotIndex) => ResolveEquipmentModelPath(),
|
||||
_ => ResolveModelPathNative(),
|
||||
};
|
||||
}
|
||||
|
||||
private Utf8GamePath ResolveEquipmentModelPath()
|
||||
{
|
||||
var path = SlotIndex < 5
|
||||
var path = IsEquipmentSlot(SlotIndex)
|
||||
? GamePaths.Equipment.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), Slot)
|
||||
: GamePaths.Accessory.Mdl.Path(Equipment.Set, ResolveModelRaceCode(), Slot);
|
||||
return Utf8GamePath.FromString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty;
|
||||
|
|
@ -41,7 +47,7 @@ internal partial record ResolveContext
|
|||
private unsafe GenderRace ResolveEqdpRaceCode(EquipSlot slot, PrimaryId primaryId)
|
||||
{
|
||||
var slotIndex = slot.ToIndex();
|
||||
if (slotIndex >= 10 || ModelType != ModelType.Human)
|
||||
if (!IsEquipmentOrAccessorySlot(slotIndex) || ModelType != ModelType.Human)
|
||||
return GenderRace.MidlanderMale;
|
||||
|
||||
var characterRaceCode = (GenderRace)((Human*)CharacterBase)->RaceSexId;
|
||||
|
|
@ -82,7 +88,7 @@ internal partial record ResolveContext
|
|||
// Resolving a material path through the game's code can dereference null pointers for materials that involve IMC metadata.
|
||||
return ModelType switch
|
||||
{
|
||||
ModelType.Human when SlotIndex is < 10 or 16 && mtrlFileName[8] != (byte)'b'
|
||||
ModelType.Human when IsEquipmentOrAccessorySlot(SlotIndex) && mtrlFileName[8] != (byte)'b'
|
||||
=> ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
||||
ModelType.DemiHuman => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
||||
ModelType.Weapon => ResolveWeaponMaterialPath(modelPath, imc, mtrlFileName),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Penumbra.Interop.Hooks.PostProcessing;
|
|||
using Penumbra.UI;
|
||||
using CustomizeData = FFXIVClientStructs.FFXIV.Client.Game.Character.CustomizeData;
|
||||
using CustomizeIndex = Dalamud.Game.ClientState.Objects.Enums.CustomizeIndex;
|
||||
using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.ModelType;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
|
|
@ -44,8 +45,8 @@ public class ResourceTree
|
|||
PlayerRelated = playerRelated;
|
||||
CollectionName = collectionName;
|
||||
AnonymizedCollectionName = anonymizedCollectionName;
|
||||
Nodes = new List<ResourceNode>();
|
||||
FlatNodes = new HashSet<ResourceNode>();
|
||||
Nodes = [];
|
||||
FlatNodes = [];
|
||||
}
|
||||
|
||||
public void ProcessPostfix(Action<ResourceNode, ResourceNode?> action)
|
||||
|
|
@ -59,13 +60,13 @@ public class ResourceTree
|
|||
var character = (Character*)GameObjectAddress;
|
||||
var model = (CharacterBase*)DrawObjectAddress;
|
||||
var modelType = model->GetModelType();
|
||||
var human = modelType == CharacterBase.ModelType.Human ? (Human*)model : null;
|
||||
var human = modelType == ModelType.Human ? (Human*)model : null;
|
||||
var equipment = modelType switch
|
||||
{
|
||||
CharacterBase.ModelType.Human => new ReadOnlySpan<CharacterArmor>(&human->Head, 10),
|
||||
CharacterBase.ModelType.DemiHuman => new ReadOnlySpan<CharacterArmor>(
|
||||
ModelType.Human => new ReadOnlySpan<CharacterArmor>(&human->Head, 12),
|
||||
ModelType.DemiHuman => new ReadOnlySpan<CharacterArmor>(
|
||||
Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10),
|
||||
_ => ReadOnlySpan<CharacterArmor>.Empty,
|
||||
_ => [],
|
||||
};
|
||||
ModelId = character->CharacterData.ModelCharaId;
|
||||
CustomizeData = character->DrawData.CustomizeData;
|
||||
|
|
@ -75,9 +76,18 @@ public class ResourceTree
|
|||
|
||||
for (var i = 0u; i < model->SlotCount; ++i)
|
||||
{
|
||||
var slotContext = i < equipment.Length
|
||||
var slotContext = modelType switch
|
||||
{
|
||||
ModelType.Human => i switch
|
||||
{
|
||||
< 10 => globalContext.CreateContext(model, i, i.ToEquipSlot(), equipment[(int)i]),
|
||||
16 or 17 => globalContext.CreateContext(model, i, EquipSlot.Head, equipment[(int)(i - 6)]),
|
||||
_ => globalContext.CreateContext(model, i),
|
||||
},
|
||||
_ => i < equipment.Length
|
||||
? globalContext.CreateContext(model, i, i.ToEquipSlot(), equipment[(int)i])
|
||||
: globalContext.CreateContext(model, i);
|
||||
: globalContext.CreateContext(model, i),
|
||||
};
|
||||
|
||||
var imc = (ResourceHandle*)model->IMCArray[i];
|
||||
var imcNode = slotContext.CreateNodeFromImc(imc);
|
||||
|
|
@ -117,7 +127,7 @@ public class ResourceTree
|
|||
|
||||
var subObject = (CharacterBase*)baseSubObject;
|
||||
|
||||
if (subObject->GetModelType() != CharacterBase.ModelType.Weapon)
|
||||
if (subObject->GetModelType() != ModelType.Weapon)
|
||||
continue;
|
||||
|
||||
var weapon = (Weapon*)subObject;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue