Merge branch 'main' into claude/eloquent-hugle-42119e
# Conflicts: # .gitignore
This commit is contained in:
commit
093cdb6d57
38 changed files with 5852 additions and 216 deletions
|
|
@ -271,6 +271,33 @@ public static class RenderingDiagnostics
|
|||
public static bool ProbeLightEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_LIGHT") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// A7.L1 (2026-07-06) per-cell light SET-COMPOSITION probe — the apparatus the
|
||||
/// <c>[light]</c> counts could not provide (the #176/#177 discriminator: the bug
|
||||
/// lived in set MEMBERSHIP, not counts). When true, the scoped
|
||||
/// <c>LightManager.BuildPointLightSnapshot</c> emits ONE rate-limited
|
||||
/// <c>[indoor-light]</c> line describing the visible-cell-scoped point-light pool
|
||||
/// (see <see cref="EmitIndoorLight"/>):
|
||||
/// <code>
|
||||
/// [indoor-light] visibleCells=<N> pool=<M> cellLess=<K> registered=<R>
|
||||
/// droppedNonVisible=<R-M> byCell=[0x<id>:<count>,...]
|
||||
/// </code>
|
||||
/// This validates the A7 fix's load-bearing assumption end-to-end:
|
||||
/// <list type="bullet">
|
||||
/// <item><description><c>cellLess==pool</c> (every pool light is CellId 0) ⇒
|
||||
/// cell tagging FAILED (ParentCellId not flowing) — scoping is a silent no-op.</description></item>
|
||||
/// <item><description><c>pool==cellLess</c> while <c>registered</c> is large in a
|
||||
/// LIT room ⇒ tagged CellIds never match the visible set (wrong id form) — the
|
||||
/// room would go dark.</description></item>
|
||||
/// <item><description><c>droppedNonVisible>0</c> with <c>byCell</c> tracking the
|
||||
/// visible rooms ⇒ scoping WORKING (the under-room/through-floor lights are the
|
||||
/// dropped ones).</description></item>
|
||||
/// </list>
|
||||
/// Output-only, inert when off. Initial state from <c>ACDREAM_PROBE_INDOOR_LIGHT=1</c>.
|
||||
/// </summary>
|
||||
public static bool ProbeIndoorLightEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_INDOOR_LIGHT") == "1";
|
||||
|
||||
// Cell-change gate for EmitVis. The probe fires once per distinct root cell
|
||||
// so launch.log stays readable under motion (the per-frame call is a no-op
|
||||
// when the root is unchanged). Sentinel 0 = "no root yet" — the first real
|
||||
|
|
@ -451,6 +478,66 @@ public static class RenderingDiagnostics
|
|||
}
|
||||
}
|
||||
|
||||
// Wall-clock rate-limit gate for EmitIndoorLight (shares the 1 s interval).
|
||||
private static long _lastIndoorLightEmitTicks;
|
||||
|
||||
/// <summary>
|
||||
/// A7.L1 — emit ONE rate-limited <c>[indoor-light]</c> line describing the
|
||||
/// visible-cell-scoped point-light pool: the SET COMPOSITION the <c>[light]</c>
|
||||
/// counts can't show. Cheap no-op when <see cref="ProbeIndoorLightEnabled"/> is
|
||||
/// false; otherwise fires at most once per second. Called from the scoped
|
||||
/// <c>LightManager.BuildPointLightSnapshot</c> (visibleCells != null path).
|
||||
/// </summary>
|
||||
/// <param name="visibleCellCount">Size of the portal-flood visible-cell set this frame.</param>
|
||||
/// <param name="allRegistered">Every registered light (<c>LightManager._all</c>).</param>
|
||||
/// <param name="scopedSnapshot">The visible-cell-scoped point-light pool just built.</param>
|
||||
public static void EmitIndoorLight(int visibleCellCount,
|
||||
IReadOnlyList<AcDream.Core.Lighting.LightSource> allRegistered,
|
||||
IReadOnlyList<AcDream.Core.Lighting.LightSource> scopedSnapshot)
|
||||
{
|
||||
if (!ProbeIndoorLightEnabled) return;
|
||||
|
||||
long now = DateTime.UtcNow.Ticks;
|
||||
if (_lastIndoorLightEmitTicks != 0 && (now - _lastIndoorLightEmitTicks) < LightEmitIntervalTicks)
|
||||
return;
|
||||
_lastIndoorLightEmitTicks = now;
|
||||
|
||||
int registeredLitPoints = 0;
|
||||
foreach (var l in allRegistered)
|
||||
if (l.IsLit && l.Kind != AcDream.Core.Lighting.LightKind.Directional) registeredLitPoints++;
|
||||
|
||||
int pool = scopedSnapshot.Count;
|
||||
int cellLess = 0;
|
||||
var hist = new Dictionary<uint, int>();
|
||||
foreach (var l in scopedSnapshot)
|
||||
{
|
||||
if (l.CellId == 0) cellLess++;
|
||||
hist.TryGetValue(l.CellId, out var c);
|
||||
hist[l.CellId] = c + 1;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(220);
|
||||
sb.Append("[indoor-light] visibleCells=").Append(visibleCellCount);
|
||||
sb.Append(" pool=").Append(pool);
|
||||
sb.Append(" cellLess=").Append(cellLess);
|
||||
sb.Append(" registered=").Append(registeredLitPoints);
|
||||
// Lights excluded by visibility scoping (retail: cells not in visible_cell_table
|
||||
// contribute nothing) — the through-floor/under-room lights kept out of the pool.
|
||||
sb.Append(" droppedNonVisible=").Append(registeredLitPoints - pool);
|
||||
sb.Append(" byCell=[");
|
||||
const int MaxCells = 12;
|
||||
int shown = 0;
|
||||
foreach (var kv in hist)
|
||||
{
|
||||
if (shown >= MaxCells) { sb.Append(",..."); break; }
|
||||
if (shown > 0) sb.Append(',');
|
||||
sb.Append("0x").Append(kv.Key.ToString("X8")).Append(':').Append(kv.Value);
|
||||
shown++;
|
||||
}
|
||||
sb.Append(']');
|
||||
Console.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
private static bool _probeEnvCellEnabled =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_ENVCELL") == "1";
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue