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
|
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="C:\Users\erikn\source\repos\acdream\references\DatReaderWriter\DatReaderWriter\DatReaderWriter.csproj" />
|
||||
<ProjectReference Include="..\..\src\AcDream.Content\AcDream.Content.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -3,18 +3,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AcDream.Content.Vfx;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Options;
|
||||
using DatReaderWriter.Types;
|
||||
using SysEnv = System.Environment;
|
||||
using DatPhysicsScript = DatReaderWriter.DBObjs.PhysicsScript;
|
||||
using RetailBlockingHook = AcDream.Core.Vfx.RetailCreateBlockingParticleHook;
|
||||
|
||||
string datDir = SysEnv.GetEnvironmentVariable("ACDREAM_DAT_DIR")
|
||||
?? Path.Combine(SysEnv.GetFolderPath(SysEnv.SpecialFolder.UserProfile),
|
||||
"Documents", "Asheron's Call");
|
||||
Console.WriteLine($"datDir = {datDir}");
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var physicsScripts = new RetailPhysicsScriptLoader(dats);
|
||||
|
||||
uint[] roots = { 0x33000453u, 0x33000428u, 0x3300042Cu, 0x33000429u, 0x3300042Du };
|
||||
|
||||
|
|
@ -35,7 +38,8 @@ foreach (var root in roots)
|
|||
Console.WriteLine($"{pad}PES 0x{pesId:X8} (already visited — cycle skip)");
|
||||
return;
|
||||
}
|
||||
if (!dats.TryGet<DatPhysicsScript>(pesId, out var ps) || ps is null)
|
||||
DatPhysicsScript? ps = physicsScripts.LoadPhysicsScript(pesId);
|
||||
if (ps is null)
|
||||
{
|
||||
Console.WriteLine($"{pad}PES 0x{pesId:X8} NOT FOUND");
|
||||
return;
|
||||
|
|
@ -52,13 +56,18 @@ foreach (var root in roots)
|
|||
Console.WriteLine($"{head} -> PES=0x{call.PES:X8} pause={call.Pause:F3}");
|
||||
WalkPes(call.PES, depth + 2, rootForReport);
|
||||
break;
|
||||
case RetailBlockingHook blocking:
|
||||
uint blockingEmitterId = (uint)blocking.EmitterInfoId;
|
||||
Console.WriteLine($"{head} EmitterInfoId=0x{blockingEmitterId:X8} PartIdx={blocking.PartIndex} EmitterId={blocking.EmitterId} (blocking)");
|
||||
DumpEmitter(blockingEmitterId, pad + " ", rootForReport);
|
||||
break;
|
||||
case CreateParticleHook cp:
|
||||
uint eid = (uint)cp.EmitterInfoId;
|
||||
Console.WriteLine($"{head} EmitterInfoId=0x{eid:X8} PartIdx={cp.PartIndex} EmitterId={cp.EmitterId}");
|
||||
DumpEmitter(eid, pad + " ", rootForReport);
|
||||
break;
|
||||
case CreateBlockingParticleHook _:
|
||||
Console.WriteLine($"{head} (package schema omits retail's inherited CreateParticle payload)");
|
||||
Console.WriteLine($"{head} (unexpected package header-only shape)");
|
||||
break;
|
||||
case SoundHook sh:
|
||||
Console.WriteLine($"{head} sound=0x{(uint)sh.Id:X8}");
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Chorizite.DatReaderWriter" Version="2.1.7" />
|
||||
<ProjectReference Include="..\..\src\AcDream.Content\AcDream.Content.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue