feat(world): Phase A8 R1 — tag WorldEntity.IsBuildingShell at LandblockLoader
Adds a bool flag at the WorldEntity data layer set by LandblockLoader from the source dat array: LandBlockInfo.Buildings → true (cottage walls, inn walls, smithy walls); LandBlockInfo.Objects → false (trees, lampposts, rocks, hitching posts). Retail anchor: CLandBlock::init_buildings reads a separate BuildInfo** array from objects (acclient.h:31893 num_buildings / buildings field; acclient_2013_pseudo_c.txt:313854 init_buildings entry). WorldBuilder preserves the same distinction via SceneryInstance.IsBuilding (StaticObjectRenderManager.cs:334). Today acdream's loader reads both arrays into the same WorldEntity pool with no tag, destroying the distinction (the comment at GameWindow.cs:5175 already acknowledges this gap for scenery suppression). This commit closes the gap. Render-time consumption arrives in R2 (EntitySet partition refactor). Two new LandblockLoader tests lock the tagging behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d2db8d5b22
commit
ed72704f7b
4 changed files with 71 additions and 0 deletions
|
|
@ -5133,6 +5133,7 @@ public sealed class GameWindow : IDisposable
|
||||||
Position = e.Position + worldOffset,
|
Position = e.Position + worldOffset,
|
||||||
Rotation = e.Rotation,
|
Rotation = e.Rotation,
|
||||||
MeshRefs = meshRefs,
|
MeshRefs = meshRefs,
|
||||||
|
IsBuildingShell = e.IsBuildingShell, // Phase A8: preserve dat-level tag
|
||||||
};
|
};
|
||||||
hydrated.Add(entity);
|
hydrated.Add(entity);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ public static class LandblockLoader
|
||||||
Position = building.Frame.Origin,
|
Position = building.Frame.Origin,
|
||||||
Rotation = building.Frame.Orientation,
|
Rotation = building.Frame.Orientation,
|
||||||
MeshRefs = Array.Empty<MeshRef>(),
|
MeshRefs = Array.Empty<MeshRef>(),
|
||||||
|
IsBuildingShell = true, // Phase A8: tag at source array boundary
|
||||||
};
|
};
|
||||||
buildingEntity.RefreshAabb(); // A.5 T18: populate cached AABB at construction
|
buildingEntity.RefreshAabb(); // A.5 T18: populate cached AABB at construction
|
||||||
result.Add(buildingEntity);
|
result.Add(buildingEntity);
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,25 @@ public sealed class WorldEntity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint? ParentCellId { get; init; }
|
public uint? ParentCellId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True when this entity originates from <c>LandBlockInfo.Buildings[]</c>
|
||||||
|
/// (the dat array that carries building shells: cottage walls, smithy walls,
|
||||||
|
/// inn walls — every solid building enclosure). False for entities from
|
||||||
|
/// <c>LandBlockInfo.Objects[]</c> (rocks, fences, lampposts, tree clusters —
|
||||||
|
/// outdoor scenery placeholders). The two arrays are conflated through
|
||||||
|
/// hydration today but the dat itself carries the distinction; retail
|
||||||
|
/// (<c>CLandBlock::init_buildings</c>) and WorldBuilder
|
||||||
|
/// (<c>SceneryInstance.IsBuilding</c>) both preserve it.
|
||||||
|
///
|
||||||
|
/// <para>
|
||||||
|
/// Read at draw time by <c>WbDrawDispatcher</c>'s <c>IndoorPass</c>
|
||||||
|
/// partition so building shells render unconditionally when the camera
|
||||||
|
/// is inside their building (they ARE the indoor walls), not stencil-gated
|
||||||
|
/// as outdoor scenery would be.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public bool IsBuildingShell { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uniform scale applied to this entity's mesh by the scenery pipeline.
|
/// Uniform scale applied to this entity's mesh by the scenery pipeline.
|
||||||
/// For scenery objects this is spawn.Scale (typically 0.8–1.3). For stabs
|
/// For scenery objects this is spawn.Scale (typically 0.8–1.3). For stabs
|
||||||
|
|
|
||||||
|
|
@ -162,4 +162,54 @@ public class LandblockLoaderTests
|
||||||
Assert.Single(entities);
|
Assert.Single(entities);
|
||||||
Assert.Equal(1u, entities[0].Id);
|
Assert.Equal(1u, entities[0].Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildEntitiesFromInfo_TagsBuildingsWithIsBuildingShellTrue()
|
||||||
|
{
|
||||||
|
var info = new LandBlockInfo
|
||||||
|
{
|
||||||
|
Buildings =
|
||||||
|
{
|
||||||
|
new BuildingInfo
|
||||||
|
{
|
||||||
|
ModelId = 0x02000123u, // Setup id
|
||||||
|
Frame = new Frame
|
||||||
|
{
|
||||||
|
Origin = new Vector3(10f, 20f, 30f),
|
||||||
|
Orientation = Quaternion.Identity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var entities = LandblockLoader.BuildEntitiesFromInfo(info);
|
||||||
|
|
||||||
|
Assert.Single(entities);
|
||||||
|
Assert.True(entities[0].IsBuildingShell);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildEntitiesFromInfo_TagsObjectsWithIsBuildingShellFalse()
|
||||||
|
{
|
||||||
|
var info = new LandBlockInfo
|
||||||
|
{
|
||||||
|
Objects =
|
||||||
|
{
|
||||||
|
new Stab
|
||||||
|
{
|
||||||
|
Id = 0x01000123u, // GfxObj id
|
||||||
|
Frame = new Frame
|
||||||
|
{
|
||||||
|
Origin = new Vector3(10f, 20f, 30f),
|
||||||
|
Orientation = Quaternion.Identity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var entities = LandblockLoader.BuildEntitiesFromInfo(info);
|
||||||
|
|
||||||
|
Assert.Single(entities);
|
||||||
|
Assert.False(entities[0].IsBuildingShell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue