Add some migration things.

This commit is contained in:
Ottermandias 2024-07-08 14:55:49 +02:00
parent 0d939b12f4
commit 56e284a99e
17 changed files with 515 additions and 80 deletions

View file

@ -35,7 +35,7 @@ public sealed unsafe class LoadAreaVfx : FastHook<LoadAreaVfx.Delegate>
var last = _state.SetAnimationData(newData);
_crashHandler.LogAnimation(newData.AssociatedGameObject, newData.ModCollection, AnimationInvocationType.LoadAreaVfx);
var ret = Task.Result.Original(vfxId, pos, caster, unk1, unk2, unk3);
Penumbra.Log.Information(
Penumbra.Log.Excessive(
$"[Load Area VFX] Invoked with {vfxId}, [{pos[0]} {pos[1]} {pos[2]}], 0x{(nint)caster:X}, {unk1}, {unk2}, {unk3} -> 0x{ret:X}.");
_state.RestoreAnimationData(last);
return ret;

View file

@ -94,9 +94,6 @@ public unsafe class ResourceLoader : IDisposable, IService
CompareHash(ComputeHash(path.Path, parameters), hash, path);
if (path.ToString() == "vfx/common/eff/abi_cnj022g.avfx")
;
// If no replacements are being made, we still want to be able to trigger the event.
var (resolvedPath, data) = _incMode.Value
? (null, ResolveData.Invalid)

View file

@ -81,11 +81,12 @@ 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 < 10 && mtrlFileName[8] != (byte)'b' => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
ModelType.DemiHuman => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
ModelType.Weapon => ResolveWeaponMaterialPath(modelPath, imc, mtrlFileName),
ModelType.Monster => ResolveMonsterMaterialPath(modelPath, imc, mtrlFileName),
_ => ResolveMaterialPathNative(mtrlFileName),
ModelType.Human when SlotIndex is < 10 or 16 && mtrlFileName[8] != (byte)'b'
=> ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
ModelType.DemiHuman => ResolveEquipmentMaterialPath(modelPath, imc, mtrlFileName),
ModelType.Weapon => ResolveWeaponMaterialPath(modelPath, imc, mtrlFileName),
ModelType.Monster => ResolveMonsterMaterialPath(modelPath, imc, mtrlFileName),
_ => ResolveMaterialPathNative(mtrlFileName),
};
}
@ -96,7 +97,7 @@ internal partial record ResolveContext
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
Span<byte> pathBuffer = stackalloc byte[260];
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, fileName);
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, fileName);
return Utf8GamePath.FromSpan(pathBuffer, out var path) ? path.Clone() : Utf8GamePath.Empty;
}
@ -126,7 +127,7 @@ internal partial record ResolveContext
WriteZeroPaddedNumber(mirroredFileName[4..8], mirroredSetId);
Span<byte> pathBuffer = stackalloc byte[260];
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, mirroredFileName);
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, mirroredFileName);
var weaponPosition = pathBuffer.IndexOf("/weapon/w"u8);
if (weaponPosition >= 0)
@ -145,7 +146,7 @@ internal partial record ResolveContext
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
Span<byte> pathBuffer = stackalloc byte[260];
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, fileName);
pathBuffer = AssembleMaterialPath(pathBuffer, modelPath.Path.Span, variant, fileName);
return Utf8GamePath.FromSpan(pathBuffer, out var path) ? path.Clone() : Utf8GamePath.Empty;
}
@ -166,7 +167,8 @@ internal partial record ResolveContext
return entry.MaterialId;
}
private static Span<byte> AssembleMaterialPath(Span<byte> materialPathBuffer, ReadOnlySpan<byte> modelPath, byte variant, ReadOnlySpan<byte> mtrlFileName)
private static Span<byte> AssembleMaterialPath(Span<byte> materialPathBuffer, ReadOnlySpan<byte> modelPath, byte variant,
ReadOnlySpan<byte> mtrlFileName)
{
var modelPosition = modelPath.IndexOf("/model/"u8);
if (modelPosition < 0)
@ -187,8 +189,8 @@ internal partial record ResolveContext
{
for (var i = destination.Length; i-- > 0;)
{
destination[i] = (byte)('0' + number % 10);
number /= 10;
destination[i] = (byte)('0' + number % 10);
number /= 10;
}
}
@ -197,13 +199,17 @@ internal partial record ResolveContext
ByteString? path;
try
{
Penumbra.Log.Information($"{(nint)CharacterBase:X} {ModelType} {SlotIndex} 0x{(ulong)mtrlFileName:X}");
Penumbra.Log.Information($"{new ByteString(mtrlFileName)}");
path = CharacterBase->ResolveMtrlPathAsByteString(SlotIndex, mtrlFileName);
}
catch (AccessViolationException)
{
Penumbra.Log.Error($"Access violation during attempt to resolve material path\nDraw object: {(nint)CharacterBase:X} (of type {ModelType})\nSlot index: {SlotIndex}\nMaterial file name: {(nint)mtrlFileName:X} ({new string((sbyte*)mtrlFileName)})");
Penumbra.Log.Error(
$"Access violation during attempt to resolve material path\nDraw object: {(nint)CharacterBase:X} (of type {ModelType})\nSlot index: {SlotIndex}\nMaterial file name: {(nint)mtrlFileName:X} ({new string((sbyte*)mtrlFileName)})");
return Utf8GamePath.Empty;
}
return Utf8GamePath.FromByteString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty;
}
@ -235,30 +241,23 @@ internal partial record ResolveContext
var characterRaceCode = (GenderRace)human->RaceSexId;
switch (partialSkeletonIndex)
{
case 0:
return (characterRaceCode, "base", 1);
case 0: return (characterRaceCode, "base", 1);
case 1:
var faceId = human->FaceId;
var tribe = human->Customize[(int)Dalamud.Game.ClientState.Objects.Enums.CustomizeIndex.Tribe];
var modelType = human->Customize[(int)Dalamud.Game.ClientState.Objects.Enums.CustomizeIndex.ModelType];
if (faceId < 201)
{
faceId -= tribe switch
{
0xB when modelType == 4 => 100,
0xE | 0xF => 100,
_ => 0,
};
}
return ResolveHumanExtraSkeletonData(characterRaceCode, EstType.Face, faceId);
case 2:
return ResolveHumanExtraSkeletonData(characterRaceCode, EstType.Hair, human->HairId);
case 3:
return ResolveHumanEquipmentSkeletonData(EquipSlot.Head, EstType.Head);
case 4:
return ResolveHumanEquipmentSkeletonData(EquipSlot.Body, EstType.Body);
default:
return (0, string.Empty, 0);
case 2: return ResolveHumanExtraSkeletonData(characterRaceCode, EstType.Hair, human->HairId);
case 3: return ResolveHumanEquipmentSkeletonData(EquipSlot.Head, EstType.Head);
case 4: return ResolveHumanEquipmentSkeletonData(EquipSlot.Body, EstType.Body);
default: return (0, string.Empty, 0);
}
}
@ -269,7 +268,8 @@ internal partial record ResolveContext
return ResolveHumanExtraSkeletonData(ResolveEqdpRaceCode(slot, equipment.Set), type, equipment.Set);
}
private (GenderRace RaceCode, string Slot, PrimaryId Set) ResolveHumanExtraSkeletonData(GenderRace raceCode, EstType type, PrimaryId primary)
private (GenderRace RaceCode, string Slot, PrimaryId Set) ResolveHumanExtraSkeletonData(GenderRace raceCode, EstType type,
PrimaryId primary)
{
var metaCache = Global.Collection.MetaCache;
var skeletonSet = metaCache?.GetEstEntry(type, raceCode, primary) ?? default;

View file

@ -73,11 +73,11 @@ public class ResourceTree
var genericContext = globalContext.CreateContext(model);
for (var i = 0; i < model->SlotCount; ++i)
for (var i = 0u; i < model->SlotCount; ++i)
{
var slotContext = i < equipment.Length
? globalContext.CreateContext(model, (uint)i, ((uint)i).ToEquipSlot(), equipment[i])
: globalContext.CreateContext(model, (uint)i);
? globalContext.CreateContext(model, i, i.ToEquipSlot(), equipment[(int)i])
: globalContext.CreateContext(model, i);
var imc = (ResourceHandle*)model->IMCArray[i];
var imcNode = slotContext.CreateNodeFromImc(imc);