feat(app): Phase B.3 — wire PhysicsEngine into streaming pipeline
Populates the collision engine with TerrainSurface + CellSurface entries when landblocks stream in, removes them when they stream out. CellSurface vertices are transformed from cell-local to world space using EnvCell.Position orientation + origin. Phase B.2 (player movement mode) will call PhysicsEngine.Resolve() to get collision-validated positions before sending them to the server. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
88d446d11d
commit
9bd4d1eed8
2 changed files with 68 additions and 2 deletions
|
|
@ -34,6 +34,9 @@ public sealed class GameWindow : IDisposable
|
|||
private int _streamingRadius = 2; // default 5×5
|
||||
private uint? _lastLivePlayerLandblockId;
|
||||
|
||||
// Phase B.3: physics engine — populated from the streaming pipeline.
|
||||
private readonly AcDream.Core.Physics.PhysicsEngine _physicsEngine = new();
|
||||
|
||||
// Phase A.1 hotfix: DatCollection is NOT thread-safe. The streaming worker
|
||||
// thread and the render thread both read dats (BuildLandblockForStreaming
|
||||
// on the worker; ApplyLoadedTerrain + live-spawn handlers on the render
|
||||
|
|
@ -282,7 +285,12 @@ public sealed class GameWindow : IDisposable
|
|||
drainCompletions: _streamer.DrainCompletions,
|
||||
applyTerrain: ApplyLoadedTerrain,
|
||||
state: _worldState,
|
||||
radius: _streamingRadius);
|
||||
radius: _streamingRadius,
|
||||
removeTerrain: id =>
|
||||
{
|
||||
_terrain?.RemoveLandblock(id);
|
||||
_physicsEngine.RemoveLandblock(id);
|
||||
});
|
||||
|
||||
// Phase 4.7: optional live-mode startup. Connect to the ACE server,
|
||||
// enter the world as the first character on the account, and stream
|
||||
|
|
@ -1211,6 +1219,60 @@ public sealed class GameWindow : IDisposable
|
|||
_worldState.SetLandblockAabb(lb.LandblockId, aabbMin, aabbMax);
|
||||
}
|
||||
|
||||
// Phase B.3: populate the physics engine with terrain + indoor cell
|
||||
// surfaces for this landblock. Runs under _datLock (same lock as the
|
||||
// rest of ApplyLoadedTerrainLocked) so dat reads are safe.
|
||||
{
|
||||
var terrainSurface = new AcDream.Core.Physics.TerrainSurface(lb.Heightmap.Height, _heightTable);
|
||||
|
||||
var cellSurfaces = new List<AcDream.Core.Physics.CellSurface>();
|
||||
var lbInfo = _dats.Get<DatReaderWriter.DBObjs.LandBlockInfo>(
|
||||
(lb.LandblockId & 0xFFFF0000u) | 0xFFFEu);
|
||||
if (lbInfo is not null && lbInfo.NumCells > 0)
|
||||
{
|
||||
uint firstCellId = (lb.LandblockId & 0xFFFF0000u) | 0x0100u;
|
||||
for (uint offset = 0; offset < lbInfo.NumCells; offset++)
|
||||
{
|
||||
uint envCellId = firstCellId + offset;
|
||||
var envCell = _dats.Get<DatReaderWriter.DBObjs.EnvCell>(envCellId);
|
||||
if (envCell is null) continue;
|
||||
if (envCell.EnvironmentId == 0) continue;
|
||||
|
||||
var environment = _dats.Get<DatReaderWriter.DBObjs.Environment>(
|
||||
0x0D000000u | envCell.EnvironmentId);
|
||||
if (environment is null) continue;
|
||||
if (!environment.Cells.TryGetValue(envCell.CellStructure, out var cellStruct)) continue;
|
||||
|
||||
// Transform CellStruct vertices from cell-local to world space.
|
||||
var rot = envCell.Position.Orientation;
|
||||
var cellOriginWorld = envCell.Position.Origin + origin;
|
||||
var worldVerts = new Dictionary<ushort, System.Numerics.Vector3>(
|
||||
cellStruct.VertexArray.Vertices.Count);
|
||||
foreach (var (vid, vtx) in cellStruct.VertexArray.Vertices)
|
||||
{
|
||||
var localPos = vtx.Origin;
|
||||
var worldPos = System.Numerics.Vector3.Transform(localPos, rot) + cellOriginWorld;
|
||||
worldVerts[(ushort)vid] = worldPos;
|
||||
}
|
||||
|
||||
// Extract polygon vertex-id lists from PhysicsPolygons.
|
||||
// PhysicsPolygons is Dictionary<ushort, Polygon>; iterate Values.
|
||||
var polyVids = new List<List<short>>(cellStruct.PhysicsPolygons.Count);
|
||||
foreach (var poly in cellStruct.PhysicsPolygons.Values)
|
||||
{
|
||||
var vids = new List<short>(poly.VertexIds.Count);
|
||||
foreach (var vid in poly.VertexIds)
|
||||
vids.Add(vid);
|
||||
polyVids.Add(vids);
|
||||
}
|
||||
|
||||
cellSurfaces.Add(new AcDream.Core.Physics.CellSurface(envCellId, worldVerts, polyVids));
|
||||
}
|
||||
}
|
||||
|
||||
_physicsEngine.AddLandblock(lb.LandblockId, terrainSurface, cellSurfaces, origin.X, origin.Y);
|
||||
}
|
||||
|
||||
// Upload every GfxObj referenced by this landblock's entities.
|
||||
// EnsureUploaded is idempotent so duplicates across landblocks are free.
|
||||
if (_staticMesh is not null)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue