Skip to content

feat: scene content stats — debug widget, creator Scene Stats panel & MCP tools - #9457

Merged
dalkia merged 44 commits into
devfrom
feat/current-scene-content-stats-debug
Aug 7, 2026
Merged

feat: scene content stats — debug widget, creator Scene Stats panel & MCP tools#9457
dalkia merged 44 commits into
devfrom
feat/current-scene-content-stats-debug

Conversation

@dalkia

@dalkia dalkia commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Description

What does this PR change?

image

Adds per-scene content statistics to a new "Scene content" debug widget so creators and devs can see, at a glance, how close the scene they are standing in is to its limits. It lives next to the existing "Current scene" widget (which keeps the runtime tick/FPS/traffic metrics) as a separate widget, so watching performance does not pay for content counting and vice versa — the counting pass only runs while a consumer is showing the stats. Rows with a documented scene limitation are formatted current / cap (percent%), the whole value colored white (< 80%) or orange (≥ 80%) — the docs define these as soft limits ("reported as warnings by the Creator Hub... treat them as strong recommendations"), so exceeding one warns but never shows red. Rows without a documented limit are shown as plain counts:

  • Entities — live CRDT entities (EntitiesMap.Count) (capped)
  • Triangles — summed from primitive mesh renderers + GLTF container renderers (capped)
  • Meshes (bodies) — renderer count, primitive + GLTF; 100 copies of one mesh count as 100 bodies (capped)
  • Textures — unique textures probed from common shader properties (capped)
  • Geometries — unique Mesh instances; low relative to bodies signals efficient instancing
  • Materials — unique instances, deduped across SDK materials and GLTF-embedded materials
  • Colliders — primitive colliders + GLTF invisible/decoded-visible colliders
  • External Videos/Audios — media players in the scene, one per VideoPlayer / AudioStream component

Intentionally omitted — Content size. An earlier revision showed a "Content size" row that summed runtime memory of unique meshes + textures (Profiler.GetRuntimeMemorySizeLong) against the 15MB/parcel budget. It was removed: the deployed-size budget is validated at deploy time (catalyst) and by the SDK tooling, so it is not this client widget's responsibility — and runtime memory is a different quantity anyway (decompressed textures dwarf their deployed size, so the row showed red on deploy-compliant scenes).

Caps are hardcoded from the documented Decentraland scene limitations, scaled by parcel count n — four of the five formulas on that page: triangles n×10000, entities n×200, bodies n×300, textures log2(n+1)×10. Materials is deliberately shown uncapped even though the docs give it a formula (log2(n+1)×20) — see Why shader variants? below. Geometries, colliders and external videos/audios have no cap and are shown as plain counts: geometries only had a formula in the legacy SDK6-era docs (dropped from the current page), and colliders/media were never documented. All caps live in one SceneContentCaps struct in SceneContentStatsFormatter.cs.

Agent/automation surface — three MCP tools. The embedded MCP server gains read-only tools documented in docs/mcp-automation.md:

  • get_scene_content_stats — the same stats as structured JSON (values + the documented caps for the scene's parcel count + a fresh flag), plus a shaderVariants count (shader + enabled keywords, deduped scene-wide). It sets its own collection-demand flag and waits for the scene world to complete a counting pass (CollectionCount stamp), so it works with every stats UI closed — agents can assert budgets programmatically instead of reading screenshots. materials is reported without a cap for the same reason the UI drops it. Covered by GetSceneContentStatsToolShould.
  • get_scene_content_breakdown — content grouped by source model (GLTF src + one primitives row), ranked by triangles/materials/shaderVariants/drawCalls/visibleTriangles: per source the summed triangles, instances, renderers, unique materials, shader variants, a pre-batching draw-call estimate, and the visible-from-this-POV subset (post-culling per Renderer.isVisible) — answers "what should I optimize" and "what does this viewpoint pay for". Filled by the same counting pass via a one-shot flag; costs nothing unless requested.
  • get_performance_stats — samples real frame times over its own short window (default 2 s) and reports render FPS avg/min/max, hiccup frames (>50 ms) and the scene's tick FPS vs target. Together the three close the loop: position the camera, measure FPS, rank the visible content that produces it.

Why shader variants? (and why materials is uncapped). URP's SRP Batcher bins draws by shader variant, not by material — many materials sharing few variants render cheaply, so a high material count alone signals memory/texture cost and lost instancing opportunities, not draw-call cost. A per-parcel cap on materials would therefore misinform more than it helps, so materials is shown as an informative count on every surface (UI rows and the MCP materials key) with no cap. Agents reading raw material counts were drawing the wrong conclusion ("every unique material is an unbatchable draw call"); the variant count is the release-build-safe number that settles it (Unity's ProfilerRecorder render counters — real SetPass/batches — are stripped from release builds, which is what creators run). Both tool descriptions carry this interpretation guidance, and docs/mcp-automation.md § "Interpreting the numbers" documents it for humans.

Creator-facing surface — Scene Stats panel. The same stats are also shown to creators through a third sidebar button (stats-chart icon) in the scene debug menu at the top right, next to the console and debug-panel buttons. That menu only exists in local scene development mode or with --scene-console, so this reaches creators previewing their scene without exposing anything to regular players. The panel (MetricsPanelView) is a dark "Scene Stats" card with edge-to-edge banded rows: uppercase labels on the left, right-aligned monospace values on the right, capped rows showing current / cap (percent%) in white or orange. Each row carries a small info marker whose hover tooltip explains what the metric indicates — capped rows note the per-parcel limit and the white/orange budget colouring, materials explains why it is uncapped (SRP Batcher), the rest describe what they count. The tooltip is parented to the document root so the panel's overflow: hidden (rounded corners) doesn't clip it; it floats in the free space to the panel's left, positioned once on hover and hidden on leave / when the panel closes. Row formatting and caps live in a shared SceneContentStatsFormatter (DCL.Profiling) so both UIs cannot drift apart.

Architecture: a new scene-world system (SceneContentStatsSystem, SyncedPresentationSystemGroup) counts every 60 frames and writes into a new SceneContentStats payload on SceneRuntimeMetrics (now exposed to scene-world systems via ECSWorldInstanceSharedDependencies). Collection runs on demand: the "Scene content" widget (DebugViewCurrentSceneSystem), the metrics panel (DebugMenuController) and the MCP tools each set their own request flag only while active — with all closed, the scene system does a single bool check per frame and nothing else. Consumers re-format only when a new pass lands (they track CollectionCount), so display work is zero between passes. Counting is allocation-free (reused HashSets / scratch list, non-alloc GetSharedMaterials); only explicitly requested breakdown passes allocate.

Test Instructions

Steps (standard run):

metaforge explorer run 9457

Expected result:
The new "Scene content" debug widget shows the eight stat rows with colored current / cap (percent%) values for the scene you are standing in; the "Current scene" widget keeps the runtime tick/FPS/traffic metrics.

Steps (fresh account):

metaforge account create --clear
metaforge explorer run 9457

Expected result:
Same as above after finishing onboarding.

Automation (if applicable):
N/A

Prerequisites

  • Serve Genesis Plaza locally and launch the Explorer pointed at it with the debug panel available. To also exercise the MCP tools, add --mcp, e.g.:
    --realm http://127.0.0.1:8000 --position 0,0 --local-scene true --skip-version-check true --mcp

Test Steps

Scene content widget

  1. Spawn into Genesis Plaza and open the debug panel, then expand the "Scene content" widget.
  2. Rows show for up to ~1 second, then populate against Genesis Plaza's parcel count — capped rows (triangles, entities, bodies, textures) as current / cap (percent%) colored white or orange, uncapped rows (materials, geometries, colliders, external videos/audios) as plain counts.
  3. Because Genesis Plaza is a heavy, multi-parcel scene, confirm at least one capped row (e.g. textures or triangles) sits over 80% and turns orange (soft-limit warning; nothing renders red), while materials stays a plain white count with no cap.
  4. Walk across Genesis Plaza toward its edge and back — values track the content around you and stay stable for the same scene.
  5. Collapse the widget or close the panel — values freeze (collection stops); reopen and they refresh within a second.

Scene Stats panel
6. Click the stats-chart button in the top-right sidebar — a dark "Scene Stats" card opens with banded rows and the same eight Genesis Plaza values; hover any row's info marker and a tooltip explains that metric; close the card and collection stops (unless the debug widget is also open).
7. With both open at once, confirm the Scene content debug widget reflects the same eight values as the Scene Stats panel — every row (capped and uncapped) matches between the two for the same Genesis Plaza scene.

MCP tools (launch with --mcp)
8. With all stats UIs closed, point a coding agent at the running Explorer (loaded into Genesis Plaza) and paste this prompt:

You are going to inspect the Decentraland scene that is already running — this should be Genesis Plaza. Do not stop or restart it, and do not change any scene files. Connect to the Decentraland Explorer MCP server that should already be up and running at http://127.0.0.1:8123/unity-explorer-mcp and use its toolset to give me a readable report on the scene I'm standing in:

  • Call get_scene_content_stats and write up, in plain language, how Genesis Plaza is doing against its per-parcel budget — which metrics are comfortably within budget and which are near or over their cap. (Sanity check: it should respond within ~1s with fresh: true, each capped metric — triangles, entities, bodies, textures — should have a value and a cap, and materials should have a value but no cap.)
  • Call get_scene_content_breakdown and tell me, in a short summary, what content is driving the heaviest metrics.
  • Call get_performance_stats and report the current FPS alongside the content stats.
  • Based on all of the above, suggest a few concrete optimizations that would bring Genesis Plaza further under budget (e.g. reducing triangle load, reusing meshes/materials, trimming textures) and note which metric each suggestion would help most.

Finally, cross-check the numbers against the Scene content debug widget — they should match for the same Genesis Plaza scene.

Additional Testing Notes

  • There is no "Content size" row — deployed-size validation belongs to deploy time / SDK tooling (see "Intentionally omitted" above)
  • Materials is intentionally uncapped everywhere (UI + MCP) — draw-call cost tracks shaderVariants, not the material count (see "Why shader variants?")
  • "External Videos/Audios" counts every media player (video or audio stream) regardless of source
  • GLTF stats only count containers in Finished state, so values grow while a scene streams in
  • Empty/loading scenes show "—" until the first collection pass
  • No SDK behavior changes — this is debug-panel-only

Quality Checklist

  • Changes have been tested locally
  • Documentation has been updated (if required)
  • Performance impact has been considered
  • For SDK features: Test scene is included

Code Review Reference

Please review our Branch & PR Standards before submitting. It explains the automated review flow, QA/DEV approval requirements, and what each label does — especially useful for first-time contributors.

🤖 Generated with Claude Code

Adds per-scene content statistics (entities, triangles, meshes/bodies,
geometries, materials, textures, colliders, runtime content size and
external content) to the "Current scene" debug widget, shown as
current / maxcap (pct%) colored green/yellow/red against hardcoded
caps derived from the scene's parcel count.

Counting runs in a new scene-world system (SceneContentStatsSystem)
gated by a demand flag the widget sets only while expanded, so it
costs a single bool check per frame when the debug panel is closed
or disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

@dalkia dalkia self-assigned this Jul 21, 2026
@dalkia dalkia added the force-build Used to trigger a build on draft PR label Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

badge

Warnings not reduced: 13729 => 13731 — remove at least 3 warnings to merge.

Warnings/errors in files changed by this PR (83)
Assets/DCL/SDKComponents/SceneContentDebug/Systems/SceneContentStatsSystem.cs:372  CSharpWarnings::CS0618  CS0618: Method 'UnityEngine.Object.GetInstanceID()' is obsolete: 'GetInstanceID is deprecated. Use GetEntityId instead. This will be removed in a future version.'
Assets/DCL/PluginSystem/Global/DebugMenuPlugin.cs:76  CSharpWarnings::CS8618  Non-nullable field 'UiDocumentPrefab' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:89  CSharpWarnings::CS8618  Non-nullable field 'assetsProvisioner' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:29  CSharpWarnings::CS8618  Non-nullable field 'consoleButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:22  CSharpWarnings::CS8618  Non-nullable field 'consolePanelView' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:31  CSharpWarnings::CS8618  Non-nullable field 'debugPanelButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:27  CSharpWarnings::CS8618  Non-nullable field 'inputBlock' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:30  CSharpWarnings::CS8618  Non-nullable field 'metricsButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:23  CSharpWarnings::CS8618  Non-nullable field 'metricsPanelView' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:87  CSharpWarnings::CS8618  Non-nullable field 'permissionsProvider' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:25  CSharpWarnings::CS8618  Non-nullable field 'visiblePanel' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:136  CSharpWarnings::CS8618  Non-nullable property 'AssetPreLoadCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:119  CSharpWarnings::CS8618  Non-nullable property 'CacheCleaner' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:95  CSharpWarnings::CS8618  Non-nullable property 'CharacterContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:137  CSharpWarnings::CS8618  Non-nullable property 'CharacterDataPropagationUtility' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:128  CSharpWarnings::CS8618  Non-nullable property 'DebugContainerBuilder' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:102  CSharpWarnings::CS8618  Non-nullable property 'ECSWorldPlugins' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:103  CSharpWarnings::CS8618  Non-nullable property 'EmoteStorage' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:97  CSharpWarnings::CS8618  Non-nullable property 'EmotesContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:115  CSharpWarnings::CS8618  Non-nullable property 'EntityCollidersGlobalCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:120  CSharpWarnings::CS8618  Non-nullable property 'EthereumApi' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:100  CSharpWarnings::CS8618  Non-nullable property 'ExposedGlobalDataContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:124  CSharpWarnings::CS8618  Non-nullable property 'FeatureFlagsProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:130  CSharpWarnings::CS8618  Non-nullable property 'GPUInstancingService' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:135  CSharpWarnings::CS8618  Non-nullable property 'GltfContainerAssetsCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:138  CSharpWarnings::CS8618  Non-nullable property 'ISSDescriptorDiskCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:127  CSharpWarnings::CS8618  Non-nullable property 'ImageControllerProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:121  CSharpWarnings::CS8618  Non-nullable property 'InputBlock' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:132  CSharpWarnings::CS8618  Non-nullable property 'LaunchMode' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:131  CSharpWarnings::CS8618  Non-nullable property 'LoadingStatus' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:96  CSharpWarnings::CS8618  Non-nullable property 'MediaContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:105  CSharpWarnings::CS8618  Non-nullable property 'MemoryCap' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:125  CSharpWarnings::CS8618  Non-nullable property 'PortableExperiencesController' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:114  CSharpWarnings::CS8618  Non-nullable property 'Profiler' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:98  CSharpWarnings::CS8618  Non-nullable property 'ProfilesContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:92  CSharpWarnings::CS8618  Non-nullable property 'PublishIpfsEntityCommand' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:99  CSharpWarnings::CS8618  Non-nullable property 'QualityContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:91  CSharpWarnings::CS8618  Non-nullable property 'RealmData' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:107  CSharpWarnings::CS8618  Non-nullable property 'SceneLoadingLimit' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:123  CSharpWarnings::CS8618  Non-nullable property 'SceneReadinessReportQueue' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:129  CSharpWarnings::CS8618  Non-nullable property 'SceneRestrictionBusController' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:122  CSharpWarnings::CS8618  Non-nullable property 'ScenesCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:112  CSharpWarnings::CS8618  Non-nullable property 'SharedPlugins' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:126  CSharpWarnings::CS8618  Non-nullable property 'SmartWearableCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:118  CSharpWarnings::CS8618  Non-nullable property 'StaticSettings' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:101  CSharpWarnings::CS8618  Non-nullable property 'WebRequestsContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:133  CSharpWarnings::CS8618  Non-nullable property 'WorldManifestProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:226  CSharpWarnings::CS8625  Cannot convert null literal to non-nullable reference type
Assets/DCL/Infrastructure/Global/StaticContainer.cs:277  ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract  Expression is always true according to nullable reference types' annotations
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:68  ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract  Expression is always true according to nullable reference types' annotations

…and 33 more (see the csharp-lint-reports artifact).

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

badge

⚠️ EditMode produced no results — the run likely crashed or timed out before finishing. Check the Unity Test / Test (editmode) job.

TESTS SUITE Result Passed Failed Skipped
EditMode ⚠️ No results
PlayMode ✅ Passed 236 0 5

dalkia and others added 24 commits July 24, 2026 09:53
Deployed-size validation belongs to deploy time (catalyst) and SDK
tooling; the runtime-memory measurement compared a different quantity
against the 15MB/parcel budget and showed red on deploy-compliant
scenes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep the five caps that exist on the official scene-limitations page
(triangles, entities, bodies, materials, textures) and show geometries,
colliders and external content as plain counts - their caps were
project-invented (geometries only existed in legacy SDK6 docs). The
docs define the limits as soft, so exceeding one now renders yellow
instead of red.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a third sidebar button to the creator-facing scene debug menu
(local scene development / --scene-console) that opens a Scene Metrics
panel showing the same content stats as the Current Scene debug widget.

Formatting and caps move to a shared SceneContentStatsFormatter in
DCL.Profiling so both consumers render identical rows, and the
collection demand flag is split per consumer so either UI can drive
the scene-world counting system independently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds get_scene_content_stats to the embedded MCP server so agents and
scripts can read the same numbers as the Current Scene debug widget and
the scene metrics panel as structured JSON, including the documented
soft-limit caps for the scene's parcel count.

The tool sets its own demand flag and waits for the scene world to
complete a counting pass (CollectionCount stamp), so it returns fresh
values even while every stats UI is closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_scene_content_breakdown ranks the current scene's rendered content
by triangles, grouped by GLTF source (plus one aggregate row for
primitive meshes), reporting instances, renderers and share of the
scene total. The stats system fills the breakdown during a normal
counting pass when a one-shot flag is set, so it costs nothing unless
requested. Answers 'what should I optimize', not just 'over budget'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each breakdown entry now reports the source's unique material count and
a draw-call estimate (material slots across renderers, pre-batching),
and get_scene_content_breakdown gains a sortBy argument
(triangles/materials/drawCalls) so an agent can answer 'where do my
2,000 materials come from' directly. Primitive meshes flow through the
same grouping path instead of dedicated accumulators.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Current scene widget keeps the runtime tick/FPS/traffic metrics;
the new Scene content widget owns the content stat rows and is the only
debug-panel consumer that triggers the counting pass, so watching
performance no longer pays for content collection (and vice versa).

Also halves the collection frequency (30 -> 60 frame cooldown), makes
every consumer re-format only when a new pass lands (CollectionCount
tracking), and raises the MCP tool timeouts to survive the longer
cadence on low-FPS scenes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every breakdown pass now also records each source's visible subset -
renderers that passed culling for the current camera (Renderer.isVisible,
shadow casters included) with their triangles and material slots - and
get_scene_content_breakdown reports them per entry and as view totals,
with sortBy=visibleTriangles to rank what the current viewpoint pays
for. Enables agent-driven POV cost surveys via set_camera_pose +
breakdown sweeps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Samples the client's real frame times over its own short window
(default 2s, no shared profiler state touched) and reports render FPS
avg/min/max, hiccup frames (>50ms) and the current scene's tick FPS vs
target. Closes the POV optimization loop: set_camera_pose ->
get_performance_stats -> get_scene_content_breakdown correlates a
viewpoint's content cost with the frame rate it actually produces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An unqualified Time resolves to the DCL.Time namespace in this
assembly, breaking compilation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename the scene debug menu metrics panel to "Scene Stats" and restyle
it per the design guideline: an in-card title with a "Suggested Specs
per Parcel" subtitle and a live "N Parcels = M m²" summary, uppercase
row labels, and the five capped metrics first followed by the three
uncapped counts. Values now render as "current / cap" with the current
value tinted green/yellow and the cap greyed (percentage text dropped);
the shared formatter change also applies to the "Scene content" widget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the connection (signal-bars) icon on the Scene Stats opener with
a 2x2 grid, drawn as four rounded-square child elements so it needs no
new texture asset and stays crisp at any resolution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the drawn 2x2 grid glyph with the existing info.png sprite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a shaderVariants counter (shader + enabled local keywords, the bin
URP's SRP Batcher batches draws by) to the content counting pass, scene-
wide and per breakdown source. Variant keys are computed allocation-free
by caching each shader's keyword space and XOR-combining enabled keyword
hashes, so the count works identically in release builds where Unity's
render profiler counters are unavailable.

Surface it in get_scene_content_stats and get_scene_content_breakdown
(new sortBy=shaderVariants), and add interpretation guidance to both
tool descriptions and docs/mcp-automation.md: draw-call cost tracks
shader variants, not material count — a high material count with few
variants is a memory/texture concern, not a frame-time one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Match the panel to the Scene Stats mockup: uppercase header with an inline
close button, edge-to-edge alternating row bands, right-aligned monospace
values, and capped rows showing current / cap (percent%) — white within
budget and orange at or above the warning threshold. Rename the external
content row to Videos and drop the parcel-summary subtitle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The panel is opened and closed from its sidebar button, so the header X was
redundant. Make DebugPanelView tolerate a panel without a CloseButton.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shared debug-panel background is only 80% opaque, so bright scenes bled
through and washed out the values. Give the metrics panel its own near-opaque
dark background.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Match the Scene content debug widget label to the Scene Stats panel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review — Scene Content Stats

STEP 2 — Root-cause check

This PR adds a new feature (per-scene content statistics for debugging and automation), not a fix. No root-cause concern applies.

STEP 3 — Design & integration

Problem: Creators and agents need to see how close a scene is to its documented content limits (triangles, entities, bodies, textures) and which assets are the heaviest contributors — without paying for that counting while nobody is looking.

Design verdict: PASS. The architecture is clean and well-placed:

  • SceneContentStatsSystem — a scene-world ECS system that counts content. I searched the repo for existing lifecycle owners: SceneFacade owns SceneRuntimeMetrics, the GLTF loading pipeline owns containers, PrimitivesRenderingPlugin owns primitive meshes. None of these count content stats — this is genuinely new work with no pre-existing owner. The system reads existing components (GltfContainerComponent, PrimitiveMeshRendererComponent, MaterialComponent, PrimitiveColliderComponent, MediaPlayerComponent) for aggregation without duplicating any lifecycle.

  • Demand-driven collection — three independent boolean flags (RequestedByDebugWidget, RequestedByMetricsPanel, RequestedByMcp) gate collection. When all consumers are inactive, the system checks one boolean per frame (CollectionRequested) and does nothing else. When active, it counts every 60 frames. This is the right pattern — explicit creation/destruction moments don't exist for "the current scene's content stats" since the stats are a continuous aggregate, not a lifecycle event.

  • Scratch buffers — the HashSets and dictionaries in SceneContentStatsSystem are cleared on each collection pass and released (cleared) when collection stops. These are per-pass aggregation buffers, consistent with CLAUDE.md §1 ("Can use temporary collections for per-frame aggregation"). The shaderKeywordsCache is retained across passes while collection is active (avoids re-allocating keyword arrays) and cleared when collection stops — good trade-off.

  • Shared formatterSceneContentStatsFormatter is shared between the debug widget and the Scene Stats panel, preventing format drift. Both consumers check CollectionCount to avoid redundant re-formatting.

  • Teardown trace:

    • DebugViewCurrentSceneSystem.OnCurrentSceneChanged → clears RequestedByDebugWidget on the old scene ✅
    • DebugViewCurrentSceneSystem.Update → sets RequestedByDebugWidget = contentExpanded each frame ✅
    • DebugMenuController.OnDisable → clears RequestedByMetricsPanel on metricsScene
    • DebugMenuController.UpdateMetricsPanel → clears RequestedByMetricsPanel on old scene when scene changes ✅
    • MCP tools → clear RequestedByMcp in finally blocks ✅
    • SceneContentStatsSystem.Update → clears all HashSets/caches when CollectionRequested becomes false ✅

STEP 4 — Member audit

  • SceneContentStats.CollectionRequested (property) — derived boolean combining three flags. Used by SceneContentStatsSystem.Update. This is a meaningful encapsulation of the demand-flag pattern, not a single-use merge candidate.
  • SceneContentCaps.ForParcelCount(int) (static factory) — used by DebugViewCurrentSceneSystem, DebugMenuController, and GetSceneContentStatsTool. Three consumers — well-justified.
  • SceneContentStatsFormatter.Format/FormatEmpty — shared by the debug widget and the metrics panel. Two consumers — prevents drift.
  • MetricsPanelView.UpdateValues — called by DebugMenuController.UpdateMetricsPanel. Single consumer, but it's a public API on a view class called by its controller — standard MVC separation.

STEP 5 — Line-level findings

One P2 finding (see inline comment). No P0 or P1 issues.

Observations (not blocking):

  • GetSceneContentBreakdownTool and GetPerformanceStatsTool lack unit tests (only GetSceneContentStatsTool is tested). The breakdown tool's sorting/limiting and the performance tool's frame sampling would benefit from test coverage.
  • The tooltip VisualElement added to documentRoot in MetricsPanelView is not removed on teardown. This follows the existing DebugPanelView pattern (no teardown mechanism), and the tooltip is hidden (display: none) when the panel closes, so it's benign.

Security review

No security issues found. The three MCP tools are read-only (McpToolAnnotations.ReadOnly()), tool arguments are clamped (Mathf.Clamp) or validated against enum values, no secrets or credentials are handled, and no file system or network access is introduced.

STEP 6 — Complexity

COMPLEX — introduces a new ECS scene-world system (SceneContentStatsSystem), a new world plugin (SceneContentStatsPlugin), modifies ECSWorldInstanceSharedDependencies and SceneInstanceDeps (dependency injection), adds three MCP tools, two UI surfaces (debug widget + metrics panel), and spans 38 files with ~1,600 additions.

STEP 7 — QA assessment

QA_REQUIRED: YES — runtime debug UI visible in the debug panel and scene debug menu, plus MCP tools that execute in the Unity player.

STEP 8 — Non-blocking warnings

No Main.unity modification detected.


REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: New ECS system, world plugin, shared dependencies change, three MCP tools, two UI surfaces (debug widget + metrics panel)
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by decentraland-bot via GitHub

Comment thread Explorer/Assets/DCL/UI/DebugMenu/DebugMenuController.cs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dalkia and others added 3 commits August 5, 2026 13:17
Replace the text "i" glyph in the metrics panel row info marker with the
existing InfoIcn.png sprite, tinted #A09BA8 by default and #FCFCFC on hover.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Relocate SceneStats.png into Assets/Textures/UI/Common as
icon-scene-stats.png so it joins the auto-generated common sprite atlas,
and reference it from the metrics sidebar button via the generated
--sprite-common__icon-scene-stats variable instead of a hardcoded asset
URL — matching the console/debug icons. Normalize the importer to
Single sprite mode (the atlas folder's postprocessor enforces this) and
add the generated variable + utility class to Sprites-Common.uss so an
in-editor Generate Sprite USS run reproduces an identical file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unity's importer generated the Single-sprite spriteID for the relocated
icon-scene-stats atlas sprite. Generate Sprite USS reproduced an identical
Sprites-Common.uss, confirming the atlas is in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review — feat: scene content stats — debug widget, creator Scene Stats panel & MCP tools

STEP 2 — Root-cause check

This PR adds new debug/profiling functionality — it is not fixing a bug. The change introduces a read-only content-counting system, three MCP tools, a creator-facing Scene Stats panel, and a debug widget. The feature is well-motivated: creators and MCP agents need visibility into scene content budgets. PASS.

STEP 3 — Design & integration

MANDATORY OWNER SEARCH — SceneContentStatsSystem.

The new system counts renderers, meshes, materials, textures, colliders, and media players across the scene's ECS entities. The lifecycle owners I searched:

  1. GLTF containersGltfContainerGroup and its subsystems load/unload GLTF assets. They do not maintain running content counts.
  2. Primitive meshesPrimitivesRenderingPlugin / rendering systems create and destroy primitive renderers. No aggregation.
  3. MaterialsMaterialLoadingGroup loads/unloads materials. No scene-wide counting.
  4. CollidersAssetsCollidersPlugin manages collider creation. No aggregation.
  5. SceneRuntimeMetrics — already holds BytesFromScene, BytesToScene, TickTimesNs, TargetFps. Adding ContentStats here follows the established pattern for per-scene profiling data.
  6. SceneInstanceDeps — creates SceneRuntimeMetrics at new SceneRuntimeMetrics() (line 68). It is the lifecycle owner. The PR threads RuntimeMetrics through ECSWorldInstanceSharedDependencies to the scene world — this is the documented pattern for passing per-scene data (CLAUDE.md § "pass per-scene data through ECSWorldInstanceSharedDependencies").

Verdict: No existing owner aggregates content counts across component types. The counting logic spans GLTF renderers, primitive renderers, SDK materials, primitive colliders, and media players — five different component queries that no single existing system covers. A new system is the correct home. The system does not manage any lifecycle; it reads existing components on a throttled schedule. PASS.

Persistent collections: The system holds HashSet<Mesh>, HashSet<Material>, HashSet<Texture>, etc. Per CLAUDE.md §1, "systems must not hold persistent entity/component collections." These are asset deduplication sets (meshes, materials, textures — Unity objects, not ECS entities/components), cleared on each collection pass and fully cleared when no consumer requests collection. They are temporary per-pass scratch buffers reused for allocation-free operation. The shaderKeywordsCache caches shader.keywordSpace.keywords arrays (one allocation per distinct shader, not per material) and is also cleared when collection stops. This follows the "temporary collections for per-frame aggregation" exception. PASS.

Demand-flag pattern: Three booleans (RequestedByDebugWidget, RequestedByMetricsPanel, RequestedByMcp) gate collection. The property CollectionRequested ORs them. Simple and appropriate.

TEARDOWN / CONSUMPTION TRACE:

  • scenesCache.CurrentScene.OnUpdate += onCurrentSceneChangedOnDispose unsubscribes. ✅
  • metricsButton.clicked += OnMetricsButtonClickedOnDisable unsubscribes. ✅
  • consoleButton.clicked += OnConsoleButtonClickedpre-existing: no unsubscribe in OnDisable (not introduced by this PR).
  • info.RegisterCallback<PointerEnterEvent> / <PointerLeaveEvent> in MetricsPanelView → Cleaned up when the UXML hierarchy is torn down. Follows ConsolePanelView pattern. ✅
  • RequestedByDebugWidget cleared in OnCurrentSceneChanged on old scene. Not cleared in OnDispose, but global world disposal coincides with scene world teardown. ✅
  • RequestedByMetricsPanel cleared in OnDisable, on scene change, and when panel is hidden. ✅
  • RequestedByMcp cleared in finally blocks in both MCP tools. ✅

STEP 4 — Member audit

  • SceneContentStats.CollectionRequested — 1 consumer (SceneContentStatsSystem.Update). Centralizes the OR of three flags — appropriate.
  • SceneContentCaps.ForParcelCount(int) — 3 consumers. Factory method, correctly shared.
  • SceneContentStatsFormatter.Format() — 3 consumers. Shared formatting, no issues.
  • MetricsPanelView.UpdateValues() — 2 consumers in DebugMenuController. Appropriate.

All members audited — no single-use-merge or absent≠false issues found.

STEP 5 — Line-level findings

See inline comments below.

STEP 6 — Complexity: COMPLEX

39 files changed, ~1800 lines of additions. Touches ECS system registration, plugin wiring, ECSWorldInstanceSharedDependencies, cross-world data sharing, MCP tool layer, and UI toolkit panels.

STEP 7 — QA: YES

Runtime UI changes (debug widget, Scene Stats panel), new ECS system running in scene worlds, new MCP tools.

STEP 8 — Non-blocking warnings

No changes to Main.unity.

CI Status

  • Lint — Warning ratchet failure: 13731 warnings vs baseline 13729. Must remove at least 3 warnings to merge.
  • ✅ Tests (editmode + playmode), builds (Windows + macOS), semantic title all pass.

REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Touches ECS system registration, plugin wiring, ECSWorldInstanceSharedDependencies, cross-world data sharing via SceneRuntimeMetrics, MCP tool layer, and UI toolkit panels.
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by Juan Ignacio Molteni (<@U03JSUQ5Z7U>) via Slack

Comment thread Explorer/Assets/DCL/McpServer/Tools/GetPerformanceStatsTool.cs
Comment thread Explorer/Assets/DCL/McpServer/Tools/GetSceneContentBreakdownTool.cs Outdated
Comment thread Explorer/Assets/DCL/McpServer/Tools/GetSceneContentBreakdownTool.cs
Comment thread Explorer/Assets/DCL/UI/DebugMenu/MetricsPanelView.cs
- Declare sampleSeconds in get_performance_stats input schema (DescribeInput)
- Extract the shared demand-flag wait loop and its timeout constant into
  SceneContentStatsPolling so the stats and breakdown tools cannot drift
- Add GetSceneContentBreakdownTool tests (no-scene error, cleanup finally
  clears both demand flags, input schema declares limit/sortBy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@pravusjif pravusjif left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent initiative, love the new utility and the new MCP tool, thanks for adding it!

@popuz popuz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍 Some design questions, can you please address them if possible (non blocking).

Comment thread Explorer/Assets/DCL/McpServer/Utils/SceneContentStatsPolling.cs
Comment thread Explorer/Assets/DCL/UI/DebugMenu/DebugMenuController.cs
Comment thread Explorer/Assets/DCL/UI/DebugMenu/DebugMenuController.cs

@DafGreco DafGreco left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️ PR reviewed and approved by QA on both platforms following instructions playing both happy and un-happy path

Regressions for this ticket had been performed in order to verify that the normal flow is working as expected:

  • [ ✔️] Backpack and wearables in world
  • [✔️ ] Emotes in world and in backpack
  • [ ✔️] Teleport with map/coordinates/Jump In
  • [ ✔️] Chat and multiplayer
  • [✔️ ] Profile card
  • [ ✔️] Skybox
  • [ ✔️] Settings

report created by claude regarding the AI requirement on the PR , so far so good on both platforms and will approve shortly 

Evidence

20260807-0852-35.4803456.1.mp4
Image

dalkia and others added 8 commits August 7, 2026 10:29
Samples skipped by the ns <= 0 guard were excluded from the sum but
still counted in the divisor, deflating the mean tick duration and
inflating the reported averageFps. Count the samples that actually
contribute and divide by that, mirroring ComputeTickFps in the debug
view.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_performance_stats read the whole 256-entry TickTimesNs ring
(~8.5 s at 30 tps) regardless of sampleSeconds, so the scene-tick
numbers included ticks from before the camera was positioned and
polluted the POV correlation the tool promises.

Add a monotonic AddedCount to SampledCounter, delta it across the
sampling loop, and aggregate only the trailing samples that landed
inside the window. Report null when the current scene changed
mid-window or did not tick during it (e.g. paused), instead of
attributing stale or mixed data to it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tool hardcoded a flat 50 ms bar while the rest of the client
defines a hiccup as max(50 ms, 2x target frame time), so on capped
configs the MCP hiccup count disagreed with the HUD and telemetry for
the same frames. Expose Profiler.EffectiveHiccupThresholdNs and derive
the tool's threshold from it, and report hiccupThresholdMs in the
output so the count is interpretable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The loop accumulated the requested delay instead of real elapsed time,
so at low FPS - the case the generous timeout exists for - each Delay
completed a whole frame late and the effective timeout drifted well
past the intended 10 s, into the dispatcher's 30 s kill.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cel each other

McpHttpServer dispatches tool calls concurrently, so two content-stats
calls can overlap; with a single bool the first finally cleared the
shared demand, the counting pass stopped, and the other call stalled to
its timeout on a healthy scene. BreakdownRequested had the same flaw,
plus the system's one-shot clear stomped a second waiter's demand.

Replace both bools with main-thread refcounts (McpRequests,
BreakdownRequests): each tool call increments before waiting and
releases only its own count in finally, and the system reads count > 0
instead of clearing. Interlocked is unnecessary - the tools declare
RequiresMainThread, so overlap is async interleaving on one thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The behavioural tests all passed collectionTimeoutMs: 0, so the wait
body - pass landing, scene-changed detection - never executed, the
happy paths were unreachable, and get_performance_stats had no tests
at all.

Give the content tools an injectable WaitForCollection delegate
(defaulting to SceneContentStatsPolling.WaitForCollectionAsync) and
extract get_performance_stats' frame loop behind a SampleFrames
delegate, then cover: render-stats math from a sampled window, the
tick-window slicing (stale ring ticks excluded, null on no ticks or
scene change mid-sample), sampleSeconds clamping, the shared hiccup
threshold, breakdown sorting and share math, sortBy=visibleTriangles,
limit clamping, and scene-changed errors on both content tools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SceneContentStatsSystem: GetInstanceID() is obsolete in Unity 6000.4;
  use GetEntityId() for the shader variant key (CS0618).
- DebugMenuController: visiblePanel and inputBlock are genuinely null
  at times (no panel open; before Initialize runs), so annotate them
  nullable and guard the OnEnable forward of inputBlock instead of
  passing null into the console view (CS8618/CS8625 + always-true).
- DebugMenuSettings.UiDocumentPrefab: inspector-assigned required
  reference, initialized null! per the serialized-settings convention
  (CS8618).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tool returned structuredContent without declaring outputSchema in
tools/list, breaking the server invariant that every structured tool
declares one - clients that validate against the schema would reject
or drop the payload.

Add McpJsonSchema.ObjectArray for the entries array, declare the full
schema, teach McpSchemaAssert to recurse into array items so the
ranking test guards schema-payload drift, and fix the doc paragraph
that listed neither this tool nor get_performance_stats among the
structured ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🚦 CI Status

Build

Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below.

Name Link
Commit c6e1800
Logs https://github.com/decentraland/unity-explorer/actions/runs/31190321629
Download Windows https://github.com/decentraland/unity-explorer/suites/84636969297/artifacts/9000550606
Download Windows S3 https://explorer-artifacts.decentraland.org/@dcl/unity-explorer/branch/feat/current-scene-content-stats-debug/pr-24746-c6e1800/Decentraland_windows64.zip
Download Mac https://github.com/decentraland/unity-explorer/suites/84636969297/artifacts/9000360238
Download Mac S3 https://explorer-artifacts.decentraland.org/@dcl/unity-explorer/branch/feat/current-scene-content-stats-debug/pr-24746-c6e1800/Decentraland_macos.zip
Built on 2026-08-07T16:00:59Z

Lint

Warnings count reduced: 13722 => 13715

Warnings/errors in files changed by this PR (87)
Assets/DCL/SDKComponents/SceneContentDebug/Systems/SceneContentStatsSystem.cs:370  CSharpWarnings::CS0618  CS0618: Operator 'implicit UnityEngine.EntityId.operator int(EntityId)' is obsolete: 'EntityId will not be representable by an int in the future. This casting operator will be removed in a future version.'
Assets/DCL/Infrastructure/Global/StaticContainer.cs:89  CSharpWarnings::CS8618  Non-nullable field 'assetsProvisioner' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:29  CSharpWarnings::CS8618  Non-nullable field 'consoleButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:22  CSharpWarnings::CS8618  Non-nullable field 'consolePanelView' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:31  CSharpWarnings::CS8618  Non-nullable field 'debugPanelButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:30  CSharpWarnings::CS8618  Non-nullable field 'metricsButton' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/UI/DebugMenu/DebugMenuController.cs:23  CSharpWarnings::CS8618  Non-nullable field 'metricsPanelView' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:87  CSharpWarnings::CS8618  Non-nullable field 'permissionsProvider' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:136  CSharpWarnings::CS8618  Non-nullable property 'AssetPreLoadCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:119  CSharpWarnings::CS8618  Non-nullable property 'CacheCleaner' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:95  CSharpWarnings::CS8618  Non-nullable property 'CharacterContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:137  CSharpWarnings::CS8618  Non-nullable property 'CharacterDataPropagationUtility' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:128  CSharpWarnings::CS8618  Non-nullable property 'DebugContainerBuilder' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:102  CSharpWarnings::CS8618  Non-nullable property 'ECSWorldPlugins' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:103  CSharpWarnings::CS8618  Non-nullable property 'EmoteStorage' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:97  CSharpWarnings::CS8618  Non-nullable property 'EmotesContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:115  CSharpWarnings::CS8618  Non-nullable property 'EntityCollidersGlobalCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:120  CSharpWarnings::CS8618  Non-nullable property 'EthereumApi' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:100  CSharpWarnings::CS8618  Non-nullable property 'ExposedGlobalDataContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:124  CSharpWarnings::CS8618  Non-nullable property 'FeatureFlagsProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:130  CSharpWarnings::CS8618  Non-nullable property 'GPUInstancingService' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:135  CSharpWarnings::CS8618  Non-nullable property 'GltfContainerAssetsCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:138  CSharpWarnings::CS8618  Non-nullable property 'ISSDescriptorDiskCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:127  CSharpWarnings::CS8618  Non-nullable property 'ImageControllerProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:121  CSharpWarnings::CS8618  Non-nullable property 'InputBlock' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:132  CSharpWarnings::CS8618  Non-nullable property 'LaunchMode' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:131  CSharpWarnings::CS8618  Non-nullable property 'LoadingStatus' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:96  CSharpWarnings::CS8618  Non-nullable property 'MediaContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:105  CSharpWarnings::CS8618  Non-nullable property 'MemoryCap' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:125  CSharpWarnings::CS8618  Non-nullable property 'PortableExperiencesController' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:114  CSharpWarnings::CS8618  Non-nullable property 'Profiler' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:98  CSharpWarnings::CS8618  Non-nullable property 'ProfilesContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:92  CSharpWarnings::CS8618  Non-nullable property 'PublishIpfsEntityCommand' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:99  CSharpWarnings::CS8618  Non-nullable property 'QualityContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:91  CSharpWarnings::CS8618  Non-nullable property 'RealmData' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:107  CSharpWarnings::CS8618  Non-nullable property 'SceneLoadingLimit' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:123  CSharpWarnings::CS8618  Non-nullable property 'SceneReadinessReportQueue' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:129  CSharpWarnings::CS8618  Non-nullable property 'SceneRestrictionBusController' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:122  CSharpWarnings::CS8618  Non-nullable property 'ScenesCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:112  CSharpWarnings::CS8618  Non-nullable property 'SharedPlugins' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:126  CSharpWarnings::CS8618  Non-nullable property 'SmartWearableCache' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:118  CSharpWarnings::CS8618  Non-nullable property 'StaticSettings' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:101  CSharpWarnings::CS8618  Non-nullable property 'WebRequestsContainer' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:133  CSharpWarnings::CS8618  Non-nullable property 'WorldManifestProvider' is uninitialized. Consider adding the 'required' modifier or declaring the property as nullable.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:277  ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract  Expression is always true according to nullable reference types' annotations
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:196  InconsistentNaming  Name 'CommunicationsControllerAPI' does not match rule 'members_should_be_pascal_case'. Suggested name is 'CommunicationsControllerApi'.
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:201  InconsistentNaming  Name 'EngineAPI' does not match rule 'members_should_be_pascal_case'. Suggested name is 'EngineApi'.
Assets/DCL/Infrastructure/Global/StaticContainer.cs:138  InconsistentNaming  Name 'ISSDescriptorDiskCache' does not match rule 'members_should_be_pascal_case'. Suggested name is 'IssDescriptorDiskCache'.
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:192  InconsistentNaming  Name 'RestrictedActionsAPI' does not match rule 'members_should_be_pascal_case'. Suggested name is 'RestrictedActionsApi'.
Assets/DCL/Infrastructure/SceneRunner/SceneInstanceDeps.cs:270  InconsistentNaming  Name 'WithRuntimeAndJsAPI' does not match rule 'members_should_be_pascal_case'. Suggested name is 'WithRuntimeAndJsApi'.

…and 37 more (see the csharp-lint-reports artifact).

Tests

All Unity tests passed ✅

TESTS SUITE Result Passed Failed Skipped
EditMode ✅ Passed 24553 0 13
PlayMode ✅ Passed 236 0 5

@dalkia
dalkia merged commit a1fc162 into dev Aug 7, 2026
27 of 30 checks passed
@dalkia
dalkia deleted the feat/current-scene-content-stats-debug branch August 7, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

force-build Used to trigger a build on draft PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants