mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
ResourceTree: Handle monster MTRL
This commit is contained in:
parent
60551c8739
commit
cb43fed9d3
1 changed files with 21 additions and 8 deletions
|
|
@ -78,20 +78,21 @@ internal partial record ResolveContext
|
||||||
|
|
||||||
private unsafe Utf8GamePath ResolveMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
|
private unsafe Utf8GamePath ResolveMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
|
||||||
{
|
{
|
||||||
// Safety:
|
// Safety and correctness:
|
||||||
// Resolving a material path through the game's code can dereference null pointers for equipment materials.
|
// Resolving a material path through the game's code can dereference null pointers for materials that involve IMC metadata.
|
||||||
return ModelType switch
|
return ModelType switch
|
||||||
{
|
{
|
||||||
ModelType.Human when SlotIndex < 10 && mtrlFileName[8] != (byte)'b' => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
ModelType.Human when SlotIndex < 10 && mtrlFileName[8] != (byte)'b' => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
||||||
ModelType.DemiHuman => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
ModelType.DemiHuman => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
|
||||||
ModelType.Weapon => ResolveWeaponMaterialPath(modelPath, imc, mtrlFileName),
|
ModelType.Weapon => ResolveWeaponMaterialPath(modelPath, imc, mtrlFileName),
|
||||||
|
ModelType.Monster => ResolveMonsterMaterialPath(modelPath, imc, mtrlFileName),
|
||||||
_ => ResolveMaterialPathNative(mtrlFileName),
|
_ => ResolveMaterialPathNative(mtrlFileName),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe Utf8GamePath ResolveEquipmentMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
|
private unsafe Utf8GamePath ResolveEquipmentMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
|
||||||
{
|
{
|
||||||
var variant = ResolveMaterialVariant(imc);
|
var variant = ResolveMaterialVariant(imc, Equipment.Variant);
|
||||||
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
|
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
|
||||||
|
|
||||||
Span<byte> pathBuffer = stackalloc byte[260];
|
Span<byte> pathBuffer = stackalloc byte[260];
|
||||||
|
|
@ -113,7 +114,7 @@ internal partial record ResolveContext
|
||||||
var setIdLow = Equipment.Set.Id % 100;
|
var setIdLow = Equipment.Set.Id % 100;
|
||||||
if (setIdLow > 50)
|
if (setIdLow > 50)
|
||||||
{
|
{
|
||||||
var variant = ResolveMaterialVariant(imc);
|
var variant = ResolveMaterialVariant(imc, Equipment.Variant);
|
||||||
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
|
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
|
||||||
|
|
||||||
var mirroredSetId = (ushort)(Equipment.Set.Id - 50);
|
var mirroredSetId = (ushort)(Equipment.Set.Id - 50);
|
||||||
|
|
@ -137,18 +138,30 @@ internal partial record ResolveContext
|
||||||
return ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName);
|
return ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe byte ResolveMaterialVariant(ResourceHandle* imc)
|
private unsafe Utf8GamePath ResolveMonsterMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
|
||||||
|
{
|
||||||
|
// TODO: Submit this (Monster->Variant) to ClientStructs
|
||||||
|
var variant = ResolveMaterialVariant(imc, ((byte*)CharacterBase.Value)[0x8F4]);
|
||||||
|
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
|
||||||
|
|
||||||
|
Span<byte> pathBuffer = stackalloc byte[260];
|
||||||
|
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, fileName);
|
||||||
|
|
||||||
|
return Utf8GamePath.FromSpan(pathBuffer, out var path) ? path.Clone() : Utf8GamePath.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe byte ResolveMaterialVariant(ResourceHandle* imc, Variant variant)
|
||||||
{
|
{
|
||||||
var imcFileData = imc->GetDataSpan();
|
var imcFileData = imc->GetDataSpan();
|
||||||
if (imcFileData.IsEmpty)
|
if (imcFileData.IsEmpty)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Warning($"IMC resource handle with path {GetResourceHandlePath(imc, false)} doesn't have a valid data span");
|
Penumbra.Log.Warning($"IMC resource handle with path {GetResourceHandlePath(imc, false)} doesn't have a valid data span");
|
||||||
return Equipment.Variant.Id;
|
return variant.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entry = ImcFile.GetEntry(imcFileData, Slot, Equipment.Variant, out var exists);
|
var entry = ImcFile.GetEntry(imcFileData, Slot, variant, out var exists);
|
||||||
if (!exists)
|
if (!exists)
|
||||||
return Equipment.Variant.Id;
|
return variant.Id;
|
||||||
|
|
||||||
return entry.MaterialId;
|
return entry.MaterialId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue