fix #131+#132: landscape translucents drawn AFTER the #124 look-ins (FlushAlphaList deferral)
The user's screenshot pair re-attributed both reports to ONE mechanism -
a compositing gap in the #124 look-in sub-pass:
- #131: the portal swirl (a TRANSLUCENT MESH, not only particles) stood
exactly in front of the hall's doorway. The slice drew it BEFORE the
look-in sub-pass; translucents write no depth, so the hall's interior
- drawn into its far-Z-punched aperture - overpainted the swirl.
Outdoors the look-ins are the post-stage merge path, so the swirl
survives ("stepping out it pops into existence").
- #132: the candle/lantern flame is an attached emitter in the slice's
Scene-particle pass - same pre-look-in placement, same erasure
whenever "the opening through a house" sat behind it; against a wall
nothing overdraws it. Background-dependence explained exactly.
Retail cannot exhibit this class: every alpha draw of the landscape
stage is collected and flushed ONCE after LScape::draw
(D3DPolyRender::FlushAlphaList, PView::DrawCells pc:432722) - i.e.
after all building look-ins.
Port (the two-phase split): DrawLandscapeThroughOutsideView now runs
EARLY per slice (sky, terrain, outdoor STATIC meshes - the look-in
punches need their depth to mark against, the #117 lesson), then the
#124 look-ins, then LATE per slice (outside-stage dynamics' meshes +
ALL attached scene particles + weather + SkyPostScene), then the #131
unattached pass. New RetailPViewLandscapeLateSliceContext carries the
dynamics survivors + the particle-owner set (statics + dynamics cone
survivors). GameWindow's slice handler split accordingly. Outdoor
roots: no look-ins live in the stage, so the net order is unchanged
(zero behavior change outdoors).
Register: AP-34 added - the two-phase split vs retail's single
deferred flush, with the residuals recorded (outdoor-root slice
particles still draw before merged building interiors - the unreported
outdoor sibling; building exteriors' own translucent batches draw
early).
The earlier #131 unattached-emitter pass (1d3f9a8) remains - it fixes
an independent hole (that class had NO indoor pass at all) - and now
runs at the end of the late phase.
Suites: App 259+1skip / Core 1439+2skip / UI 420 / Net 294 green.
Awaiting the user gate: swirl through the doorway, candle flame with
the opening behind it, far-building interiors (#124).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
1d3f9a8c97
commit
20d17304d7
4 changed files with 177 additions and 40 deletions
|
|
@ -4619,35 +4619,59 @@ cell classification is a future port.
|
|||
`[outstage]` (per-slice routing + cone verdicts) + `[outstage-pt]`
|
||||
(slice id set, attached matched count, unattached count).
|
||||
|
||||
**FIX 1 INSUFFICIENT (user screenshots, same evening):** the swirl is
|
||||
the portal's TRANSLUCENT MESH, not (only) unattached particles. The
|
||||
real mechanism — shared with #132 — is the #124 look-in ordering: the
|
||||
slice drew the portal mesh (and all scene particles) BEFORE the look-in
|
||||
sub-pass; translucents write no depth, so the far building's interior
|
||||
(drawn into its far-Z-punched aperture) overpainted them wherever a
|
||||
look-in opening sat behind them on screen. Both screenshots show the
|
||||
swirl exactly in front of the hall's doorway. Retail cannot have this
|
||||
bug: all landscape-stage alpha draws are deferred into ONE flush after
|
||||
LScape::draw (`D3DPolyRender::FlushAlphaList`, DrawCells pc:432722).
|
||||
|
||||
**FIX 2 (the FlushAlphaList deferral, same commit family as #124):**
|
||||
the landscape stage is now TWO phases per frame — EARLY per slice: sky,
|
||||
terrain, outdoor static meshes (the look-in punches need their depth, the
|
||||
#117 lesson); then the #124 look-ins; then LATE per slice: outside-stage
|
||||
dynamics' meshes + ALL attached scene particles + weather + the
|
||||
unattached pass. Outdoor roots keep their existing order (no look-ins in
|
||||
the stage; net order unchanged). Residual (documented, AP-34): under
|
||||
OUTDOOR roots slice particles still draw before merged building
|
||||
interiors (the outdoor sibling of this bug, unreported); building
|
||||
exteriors' own translucent batches draw early.
|
||||
|
||||
**Gate:** stand inside, look out the doorway at the town portal — the
|
||||
swirl renders through the door.
|
||||
swirl renders through the door; the candle flame (#132) stays visible
|
||||
with the through-opening behind it.
|
||||
|
||||
---
|
||||
|
||||
## #132 — Candle flame disappears when the through-opening background is behind it
|
||||
|
||||
**Status:** OPEN
|
||||
**Status:** FIX SHIPPED (shared mechanism with #131 fix 2) — awaiting user visual gate
|
||||
**Severity:** LOW-MEDIUM
|
||||
**Filed:** 2026-06-12 (user report, #124 gate session)
|
||||
**Component:** render — cell-particle compositing vs aperture pixels
|
||||
**Component:** render — slice particles drawn before the #124 look-ins
|
||||
|
||||
**Symptom (user, axiom):** "I have a candle, when I look at the candle
|
||||
when a wall is behind it it shows, but if I turn a bit and the opening
|
||||
through a house is behind it candle light disappears."
|
||||
|
||||
**Reading:** BACKGROUND-dependent disappearance — the candle (and its
|
||||
owner static) stays in view; only what is behind it changes. That rules
|
||||
out viewcone/owner culling (which keys on the candle's own position)
|
||||
and points at per-pixel state in the aperture region: depth left by the
|
||||
punch/seal/look-in machinery at those pixels, draw order of the cell
|
||||
particle pass vs the aperture passes, or blend state. Candidate overlap
|
||||
with the #124 look-in sub-pass (new pre-clear content in exactly those
|
||||
pixels) — check whether the symptom predates `77cef4c` by looking at a
|
||||
candle in front of a doorway WITHOUT a through-house view.
|
||||
**Root cause (= #131's fix-2 mechanism):** the candle/lantern's flame
|
||||
is an attached emitter drawn in the landscape slice's Scene-particle
|
||||
pass, which ran BEFORE the #124 look-in sub-pass. Particles write no
|
||||
depth; whenever a look-in opening ("the opening through a house") sat
|
||||
behind the flame on screen, the far building's interior — drawn into
|
||||
its far-Z-punched aperture — overpainted the flame. Against a plain
|
||||
wall (no look-in aperture behind), nothing overdraws it → visible.
|
||||
Background-dependence explained exactly.
|
||||
|
||||
**Next:** repro at the spot + `ACDREAM_PROBE_OUTSTAGE` lines for the
|
||||
same frame; then a depth-state walkthrough of the aperture pixels for
|
||||
the cell-particle pass.
|
||||
**Fix:** the landscape stage's two-phase split (see #131 FIX 2): all
|
||||
scene particles moved to the LATE phase, after the look-ins.
|
||||
|
||||
**Gate:** the candle at the original spot — flame stays visible when
|
||||
the through-opening is behind it.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ accepted-divergence entries (#96, #49, #50).
|
|||
|
||||
---
|
||||
|
||||
## 3. Documented approximation (AP) — 33 rows
|
||||
## 3. Documented approximation (AP) — 34 rows
|
||||
|
||||
| # | Divergence | Where (file:line) | Why it is safe / justified | Risk if assumption breaks | Retail oracle |
|
||||
|---|---|---|---|---|---|
|
||||
|
|
@ -129,6 +129,7 @@ accepted-divergence entries (#96, #49, #50).
|
|||
| AP-31 | Scenery placement drift + the 0xA9B1 road-edge tree — WB-upstream divergences from retail, ACCEPTED (**#49/#50**, 2026-05-11) | `src/AcDream.Core/World/SceneryGenerator.cs` (via `WbSceneryAdapter`) | Piecemeal patching against WB upstream is net-negative (the `e279c46` road-check attempt over-suppressed scenery elsewhere, reverted `677a726`); visible impact = a handful of trees a few meters off | The same WB-upstream class could hide a *larger* placement divergence elsewhere; revisit only via a coherent ACME-style per-vertex filter port | `CLandBlock::get_land_scenes`; ACME GameScene.cs:1074 per-vertex road filter |
|
||||
| AP-32 | Cell shells DRAW +0.02 m above the dat EnvCell origin (`ShellDrawLiftZ`, z-fight vs coplanar terrain); retail draws at the origin verbatim. Split invariant: PHYSICS + visibility graph UNLIFTED (f35cb8b, **#119**-residual), every DRAW-space consumer of portal/cell geometry LIFTED (OutsideView color gate via `Build(drawLiftZ)`, seal/punch fans — **#130**) | `src/AcDream.App/Rendering/GameWindow.cs:5604` (const at `PortalVisibilityBuilder.ShellDrawLiftZ`) | Shell floors coplanar with terrain z-fight in our z-buffered frame; the 2 cm lift is the documented stand-in | A new draw-space consumer of portal/cell polygons that forgets the lift re-opens a 2 cm seam at horizontal aperture edges (the #130 top-edge strip, ~7 px at 2.4 m); a visibility consumer that picks up the LIFTED transform re-opens the #119-residual horizontal-portal side-cull | retail draws cell geometry at the dat EnvCell origin (no lift) |
|
||||
| AP-33 | Interior-root look-in statics (**#124** sub-pass) draw WHOLE — no per-part viewcone check; retail viewconeCheck's each part vs the installed view. Look-in DYNAMICS are not drawn at all (deferred; retail draws objects per overlapped cell in the landscape stage) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs` (`DrawBuildingLookIns`) | The main viewcone has no entries for look-in cells; over-include is the safe direction (z-correct, repainted outside apertures by the root's shells); look-in cell counts are small (~1-3 cells) | Statics: a few wasted draws only. Dynamics: an NPC inside a far building seen through two openings is invisible where retail shows it | `viewconeCheck` 0x0054c250; nested `DrawCells` objects pc:432878 |
|
||||
| AP-34 | Landscape-stage alpha deferral is a TWO-PHASE slice split (statics-early / dynamics+particles+weather-late around the **#124** look-ins), not retail's single deferred alpha flush. Residual: under OUTDOOR roots slice particles still draw before merged building interiors (the unreported outdoor sibling of **#131**/**#132**); building exteriors' own translucent batches draw early | `src/AcDream.App/Rendering/RetailPViewRenderer.cs` (`DrawLandscapeThroughOutsideView` late loop) | The MDI dispatcher draws translucency inside each Draw call; a faithful FlushAlphaList port needs a global deferred alpha list across all landscape draws — the split covers the interior-root cases the user can see (#131 portal swirl, #132 candle flame) | Translucent landscape content drawn early and screen-overlapped by content drawn later in the stage gets overpainted (no depth self-protection) — the portal-swirl/candle-flame class re-appears in the residual configurations | `D3DPolyRender::FlushAlphaList` (DrawCells pc:432722) |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -7827,6 +7827,21 @@ public sealed class GameWindow : IDisposable
|
|||
renderWeather: playerSeenOutside,
|
||||
kf,
|
||||
environOverrideActive),
|
||||
// #131/#132: the late phase — dynamics meshes + scene
|
||||
// particles + weather AFTER the look-ins (FlushAlphaList
|
||||
// deferral).
|
||||
DrawLandscapeSliceLate = lateCtx =>
|
||||
DrawRetailPViewLandscapeSliceLate(
|
||||
lateCtx,
|
||||
camera,
|
||||
frustum,
|
||||
camPos,
|
||||
playerLb,
|
||||
animatedIds,
|
||||
renderSky,
|
||||
renderWeather: playerSeenOutside,
|
||||
kf,
|
||||
environOverrideActive),
|
||||
// T1: retail's depth discipline (PView::DrawCells, Ghidra 0x005a4840).
|
||||
// INTERIOR roots: one FULL depth clear between the outside stage and
|
||||
// the interior stage, then SEALS re-stamp every outside-leading
|
||||
|
|
@ -9652,8 +9667,60 @@ public sealed class GameWindow : IDisposable
|
|||
animatedEntityIds: animatedIds);
|
||||
}
|
||||
|
||||
// #131/#132: scene particles + weather MOVED to the LATE phase
|
||||
// (DrawRetailPViewLandscapeSliceLate) — they must composite AFTER the
|
||||
// #124 look-ins (retail's FlushAlphaList deferral, DrawCells
|
||||
// pc:432722); drawn here they were overpainted by far-building
|
||||
// interiors wherever a look-in aperture sat behind them.
|
||||
|
||||
if (scissor)
|
||||
_gl!.Disable(EnableCap.ScissorTest);
|
||||
|
||||
DisableClipDistances();
|
||||
}
|
||||
|
||||
// #131/#132: the LATE landscape phase — per slice, invoked by the renderer
|
||||
// AFTER the #124 look-in sub-pass, still pre-clear. Outside-stage
|
||||
// dynamics' meshes (a translucent portal swirl blends over a far interior
|
||||
// instead of being overpainted by it — translucents write no depth to
|
||||
// protect themselves) + ALL attached scene particles (statics' flames
|
||||
// included — the #132 candle) + weather. Retail equivalent: alpha draws
|
||||
// collected during LScape::draw flush ONCE after it
|
||||
// (D3DPolyRender::FlushAlphaList, PView::DrawCells pc:432722).
|
||||
private void DrawRetailPViewLandscapeSliceLate(
|
||||
AcDream.App.Rendering.RetailPViewLandscapeLateSliceContext lateCtx,
|
||||
ICamera camera,
|
||||
FrustumPlanes? frustum,
|
||||
System.Numerics.Vector3 camPos,
|
||||
uint? playerLb,
|
||||
HashSet<uint>? animatedIds,
|
||||
bool renderSky,
|
||||
bool renderWeather,
|
||||
AcDream.Core.World.SkyKeyframe kf,
|
||||
bool environOverrideActive)
|
||||
{
|
||||
var slice = lateCtx.Slice;
|
||||
bool scissor = BeginDoorwayScissor(true, slice.NdcAabb);
|
||||
|
||||
_gl!.BindBufferBase(BufferTargetARB.UniformBuffer,
|
||||
ClipFrame.TerrainClipUboBinding, _clipFrame!.TerrainUbo);
|
||||
|
||||
// Outside-stage dynamics' meshes — viewcone pre-filtered by the
|
||||
// renderer, never hard-clipped (T3).
|
||||
DisableClipDistances();
|
||||
if (lateCtx.Dynamics.Count > 0)
|
||||
{
|
||||
var dynamicsEntry = (playerLb ?? 0u, System.Numerics.Vector3.Zero, System.Numerics.Vector3.Zero,
|
||||
lateCtx.Dynamics,
|
||||
(IReadOnlyDictionary<uint, AcDream.Core.World.WorldEntity>?)null);
|
||||
_wbDrawDispatcher!.Draw(camera, new[] { dynamicsEntry }, frustum,
|
||||
neverCullLandblockId: playerLb,
|
||||
visibleCellIds: null,
|
||||
animatedEntityIds: animatedIds);
|
||||
}
|
||||
|
||||
_outdoorSceneParticleEntityIds.Clear();
|
||||
foreach (var entity in sliceCtx.OutdoorEntities)
|
||||
foreach (var entity in lateCtx.ParticleOwners)
|
||||
_outdoorSceneParticleEntityIds.Add(ParticleEntityKey(entity));
|
||||
|
||||
// #131 [outstage-pt] probe: the slice Scene-particle id set + how many
|
||||
|
|
@ -9677,7 +9744,6 @@ public sealed class GameWindow : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
DisableClipDistances();
|
||||
if (_outdoorSceneParticleEntityIds.Count > 0
|
||||
&& _particleSystem is not null
|
||||
&& _particleRenderer is not null)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ public sealed class RetailPViewRenderer
|
|||
private readonly List<PortalVisibilityFrame> _lookInFrames = new();
|
||||
private readonly HashSet<uint> _lookInPrepareScratch = new();
|
||||
|
||||
// #131/#132: the late landscape phase's scene-particle owner survivors
|
||||
// (statics + outside-stage dynamics passing the slice cone).
|
||||
private readonly List<WorldEntity> _lateParticleOwnerScratch = new();
|
||||
|
||||
// T2 (BR-4): retail has NO distance constant on the flood-admission chain
|
||||
// (DrawBuilding → portal walk → ConstructView: viewconeCheck + side test +
|
||||
// GetClip + GetVisible only). The old 48 m seed cap is replaced by the
|
||||
|
|
@ -365,6 +369,18 @@ public sealed class RetailPViewRenderer
|
|||
if (clipAssembly.OutsideViewSlices.Length == 0)
|
||||
return;
|
||||
|
||||
// #131/#132 (the FlushAlphaList deferral): retail collects ALL alpha
|
||||
// draws of the landscape stage and flushes them ONCE after LScape::draw
|
||||
// (D3DPolyRender::FlushAlphaList, DrawCells pc:432722) — so translucent
|
||||
// landscape content (portal swirl meshes, flame particles) composites
|
||||
// AFTER the building look-ins. Our dispatcher draws translucency inside
|
||||
// each Draw call, so the stage is split in TWO phases instead: EARLY =
|
||||
// sky + terrain + outdoor STATIC meshes (the look-in punches need their
|
||||
// depth to mark against, the #117 lesson); then the look-ins; then
|
||||
// LATE = outside-stage dynamics' meshes + ALL scene particles +
|
||||
// weather. Content drawn early and overlapped by a look-in aperture
|
||||
// was otherwise overpainted by the far interior (translucents write no
|
||||
// depth to protect themselves) — the portal-swirl/candle-flame class.
|
||||
int probeSliceIndex = 0;
|
||||
foreach (var slice in clipAssembly.OutsideViewSlices)
|
||||
{
|
||||
|
|
@ -386,19 +402,6 @@ public sealed class RetailPViewRenderer
|
|||
if (viewcone.SphereVisibleInOutsideSlice(probeSliceIndex, c, r))
|
||||
_outdoorStaticScratch.Add(e);
|
||||
}
|
||||
// #118: outside-stage dynamics ride the landscape pass like retail's
|
||||
// per-landcell DrawSortCell (DrawBlock 0x005a17c0, pc:430124) — drawn
|
||||
// BEFORE the depth clear + seals so the seal PROTECTS their pixels in
|
||||
// the aperture instead of z-killing them. Same per-slice cone test as
|
||||
// the statics above. Empty under outdoor roots (see DrawInside).
|
||||
foreach (var e in _outsideStageDynamics)
|
||||
{
|
||||
EntitySphere(e, out var c, out float r);
|
||||
if (viewcone.SphereVisibleInOutsideSlice(probeSliceIndex, c, r))
|
||||
_outdoorStaticScratch.Add(e);
|
||||
}
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeOutStageEnabled)
|
||||
EmitOutStageProbe(probeSliceIndex, viewcone);
|
||||
probeSliceIndex++;
|
||||
ctx.DrawLandscapeSlice(new RetailPViewLandscapeSliceContext(slice, _outdoorStaticScratch));
|
||||
}
|
||||
|
|
@ -409,19 +412,49 @@ public sealed class RetailPViewRenderer
|
|||
// retail's LScape::draw placement (DrawCells pc:432719 vs 432732/432785).
|
||||
DrawBuildingLookIns(ctx, partition);
|
||||
|
||||
// LATE phase (per slice): outside-stage dynamics' meshes (#118 — drawn
|
||||
// pre-clear so the seal protects their aperture pixels; AFTER the
|
||||
// look-ins so a translucent portal mesh blends over a far interior
|
||||
// instead of being overpainted) + the scene-particle owners (statics +
|
||||
// dynamics cone survivors — flames ride here for the same reason).
|
||||
probeSliceIndex = 0;
|
||||
foreach (var slice in clipAssembly.OutsideViewSlices)
|
||||
{
|
||||
_clipFrame.SetTerrainClip(slice.Planes);
|
||||
UploadClipFrame(ctx.SetTerrainClipUbo);
|
||||
_entities.ClearClipRouting();
|
||||
|
||||
_outdoorStaticScratch.Clear(); // late: dynamics survivors
|
||||
_lateParticleOwnerScratch.Clear(); // late: statics + dynamics survivors
|
||||
foreach (var e in partition.OutdoorStatic)
|
||||
{
|
||||
EntitySphere(e, out var c, out float r);
|
||||
if (viewcone.SphereVisibleInOutsideSlice(probeSliceIndex, c, r))
|
||||
_lateParticleOwnerScratch.Add(e);
|
||||
}
|
||||
foreach (var e in _outsideStageDynamics)
|
||||
{
|
||||
EntitySphere(e, out var c, out float r);
|
||||
if (viewcone.SphereVisibleInOutsideSlice(probeSliceIndex, c, r))
|
||||
{
|
||||
_outdoorStaticScratch.Add(e);
|
||||
_lateParticleOwnerScratch.Add(e);
|
||||
}
|
||||
}
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeOutStageEnabled)
|
||||
EmitOutStageProbe(probeSliceIndex, viewcone);
|
||||
probeSliceIndex++;
|
||||
ctx.DrawLandscapeSliceLate?.Invoke(new RetailPViewLandscapeLateSliceContext(
|
||||
slice, _outdoorStaticScratch, _lateParticleOwnerScratch));
|
||||
}
|
||||
|
||||
// #131: UNATTACHED emitters (AttachedObjectId == 0 — portal swirls,
|
||||
// campfires, ground effects anchored at a position) have no owner id
|
||||
// to ride any of the id-filtered particle passes. The outdoor root
|
||||
// has the dedicated T3 pass for them; an INTERIOR root had NO pass
|
||||
// at all — the portal swirl vanished exactly when viewed through a
|
||||
// doorway. Draw them ONCE per frame (not per slice — alpha particles
|
||||
// must not double-draw, the #121 lesson), still inside the landscape
|
||||
// stage: drawn after the clear they would z-fail against the doorway
|
||||
// seal; here they composite against the slice depth, and anything on
|
||||
// screen outside the apertures is overpainted by the root's shells
|
||||
// after the clear. Mutually exclusive with the outdoor T3 pass
|
||||
// (this method's caller is the interior path when slices exist;
|
||||
// GameWindow gates the T3 pass on IsOutdoorNode).
|
||||
// at all. Draw them ONCE per frame (not per slice — alpha particles
|
||||
// must not double-draw, the #121 lesson), at the END of the landscape
|
||||
// stage: after the clear they would z-fail against the doorway seal.
|
||||
if (!ctx.RootCell.IsOutdoorNode)
|
||||
ctx.DrawUnattachedSceneParticles?.Invoke();
|
||||
|
||||
|
|
@ -903,6 +936,11 @@ public sealed class RetailPViewDrawContext : IRetailPViewCellDrawContext
|
|||
IReadOnlyDictionary<uint, WorldEntity>? AnimatedById)> LandblockEntries { get; init; }
|
||||
public required Action<uint> SetTerrainClipUbo { get; init; }
|
||||
public required Action<RetailPViewLandscapeSliceContext> DrawLandscapeSlice { get; init; }
|
||||
|
||||
/// <summary>#131/#132: the LATE landscape phase, per slice, after the #124
|
||||
/// look-ins — outside-stage dynamics' meshes + all scene particles +
|
||||
/// weather (the FlushAlphaList deferral; see DrawLandscapeThroughOutsideView).</summary>
|
||||
public Action<RetailPViewLandscapeLateSliceContext>? DrawLandscapeSliceLate { get; init; }
|
||||
/// <summary>T1: one full-buffer depth clear between the outside stage and the
|
||||
/// interior stage (retail PView::DrawCells, Ghidra 0x005a4840). Null for outdoor
|
||||
/// roots — outdoors the interiors must depth-test against terrain + exteriors and
|
||||
|
|
@ -933,6 +971,14 @@ public readonly record struct RetailPViewLandscapeSliceContext(
|
|||
ClipViewSlice Slice,
|
||||
IReadOnlyList<WorldEntity> OutdoorEntities);
|
||||
|
||||
/// <summary>#131/#132: the late landscape phase's per-slice payload —
|
||||
/// outside-stage dynamics to mesh-draw, plus the full scene-particle owner
|
||||
/// set (statics + dynamics cone survivors) the attached-emitter filter keys on.</summary>
|
||||
public readonly record struct RetailPViewLandscapeLateSliceContext(
|
||||
ClipViewSlice Slice,
|
||||
IReadOnlyList<WorldEntity> Dynamics,
|
||||
IReadOnlyList<WorldEntity> ParticleOwners);
|
||||
|
||||
public readonly record struct RetailPViewCellSliceContext(
|
||||
uint CellId,
|
||||
ClipViewSlice Slice,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue