feat(vfx): decode retail hooks and typed tables
Replace the incomplete package path with one DatCollection-backed compatibility seam for PhysicsScripts and Animations. Preserve CreateBlockingParticle's inherited payload and following cursor, route every production and audit consumer through the corrected loaders, and apply retail's post-UnPack StartTime ordering. Add exact stored-order PhysicsScriptTable upper-threshold resolution, high-byte DID and embedded-ID validation, plus live effect profiles with Setup-to-PhysicsDesc precedence across top-level and attached entity lifetimes. Keep blocking execution deferred and narrow TS-11 accordingly. Pin synthetic malformed/cursor/order fixtures, installed-DAT blocking and recall audits, high-index IDs, IEEE boundaries, profile teardown, and ordinary decoder parity; synchronize architecture, inventory, milestones, roadmap, research, and memory. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
8dd996053d
commit
363e046112
31 changed files with 1102 additions and 73 deletions
|
|
@ -3,6 +3,8 @@ using System.Buffers.Binary;
|
|||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using AcDream.Content.Vfx;
|
||||
using AcDream.Core.Vfx;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Lib.IO;
|
||||
|
|
@ -15,6 +17,8 @@ string datDir = System.Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
|
|||
?? @"C:\Turbine\Asheron's Call";
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var physicsScripts = new RetailPhysicsScriptLoader(dats);
|
||||
var animations = new RetailAnimationLoader(dats);
|
||||
Console.WriteLine($"DAT metadata audit: {datDir}");
|
||||
var failures = new List<string>();
|
||||
var representativePes = new HashSet<uint>();
|
||||
|
|
@ -203,6 +207,17 @@ if (!blockingPes.SequenceEqual(expectedBlockingPes))
|
|||
failures.Add($"raw blocking-PES inventory changed: got {string.Join(",", blockingPes.Select(x => $"0x{x:X8}"))}");
|
||||
if (blockingAnimations.Count != 0)
|
||||
failures.Add($"expected no raw blocking Animation hooks, got {string.Join(",", blockingAnimations.Select(x => $"0x{x:X8}"))}");
|
||||
foreach (uint id in expectedBlockingPes)
|
||||
{
|
||||
DatPhysicsScript? script = physicsScripts.LoadPhysicsScript(id);
|
||||
if (script is null)
|
||||
{
|
||||
failures.Add($"retail loader could not parse blocking PES 0x{id:X8}");
|
||||
continue;
|
||||
}
|
||||
if (!script.ScriptData.Any(entry => entry.Hook is RetailCreateBlockingParticleHook))
|
||||
failures.Add($"blocking PES 0x{id:X8} did not retain the retail payload shape");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
if (failures.Count == 0)
|
||||
|
|
@ -304,7 +319,7 @@ static void CollectAnimationIds(MotionData motion, HashSet<uint> ids, string ind
|
|||
|
||||
void DumpAnimation(uint id, HashSet<uint> pesRoots)
|
||||
{
|
||||
DatAnimation? animation = SafeGet<DatAnimation>(id);
|
||||
DatAnimation? animation = animations.LoadAnimation(id);
|
||||
if (animation is null) return;
|
||||
Console.WriteLine($"Animation 0x{id:X8}: frames={animation.PartFrames.Count}");
|
||||
for (int frameIndex = 0; frameIndex < animation.PartFrames.Count; frameIndex++)
|
||||
|
|
@ -320,7 +335,7 @@ void DumpAnimation(uint id, HashSet<uint> pesRoots)
|
|||
void DumpPhysicsScript(uint id, HashSet<uint> visited, string indent)
|
||||
{
|
||||
if (!visited.Add(id)) return;
|
||||
DatPhysicsScript? script = SafeGet<DatPhysicsScript>(id);
|
||||
DatPhysicsScript? script = physicsScripts.LoadPhysicsScript(id);
|
||||
if (script is null) return;
|
||||
Console.WriteLine($"{indent}PES 0x{id:X8}: hooks={script.ScriptData.Count}");
|
||||
if (expectedPhysicsScripts.TryGetValue(id, out var expected))
|
||||
|
|
@ -338,10 +353,13 @@ void DumpPhysicsScript(uint id, HashSet<uint> visited, string indent)
|
|||
static string DescribeHook(AnimationHook hook) => hook switch
|
||||
{
|
||||
CallPESHook call => $"CallPES PES=0x{call.PES:X8} pause={call.Pause:R}",
|
||||
RetailCreateBlockingParticleHook blocking => $"CreateBlockingParticle emitter=0x{(uint)blocking.EmitterInfoId:X8} part={blocking.PartIndex} logical={blocking.EmitterId} "
|
||||
+ $"offset=({blocking.Offset.Origin.X:R},{blocking.Offset.Origin.Y:R},{blocking.Offset.Origin.Z:R}) "
|
||||
+ $"quat=({blocking.Offset.Orientation.X:R},{blocking.Offset.Orientation.Y:R},{blocking.Offset.Orientation.Z:R},{blocking.Offset.Orientation.W:R})",
|
||||
CreateParticleHook create => $"CreateParticle emitter=0x{(uint)create.EmitterInfoId:X8} part={create.PartIndex} logical={create.EmitterId} "
|
||||
+ $"offset=({create.Offset.Origin.X:R},{create.Offset.Origin.Y:R},{create.Offset.Origin.Z:R}) "
|
||||
+ $"quat=({create.Offset.Orientation.X:R},{create.Offset.Orientation.Y:R},{create.Offset.Orientation.Z:R},{create.Offset.Orientation.W:R})",
|
||||
CreateBlockingParticleHook => "CreateBlockingParticle (package omits inherited payload)",
|
||||
CreateBlockingParticleHook => "CreateBlockingParticle (unexpected package header-only shape)",
|
||||
_ => hook.HookType.ToString(),
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue