Files
open-wc/docs/modules/m2-runtime-mesh-rebuild-classifier.md
T

9.8 KiB

M2 Runtime Mesh Rebuild Classifier

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-M2-RUNTIME-REBUILD-CLASSIFIER-001
Owners Billboard/UV-rotation rebuild decision and per-path memoization
Last verified Worktree work/sindo-main-codex/m03-m2-runtime-rebuild-classifier, 2026-07-17
Profiles/capabilities Existing M2 material-refresh path; profile-independent

Purpose

Determine whether a stale cached M2 mesh must be rebuilt in memory from raw M2 data to restore billboard custom attributes or UV-rotation material inputs. The first decision is memoized by normalized relative path for the current map/ runtime-cache lifetime.

Non-goals

  • Read M2 files or invoke M2Loader/M2Builder.
  • Own cached Meshes, scenes, materials, Nodes or RIDs.
  • Select cache paths, perform ResourceLoader transitions or consume permits.
  • Change refresh/cache format versions or shader behavior.
  • Classify animation, particles, ribbons or general visual fidelity.

Context and boundaries

flowchart LR
    Cache[Stale cached M2 Mesh] --> Loader[StreamingWorldLoader]
    Loader --> Raw[M2Loader raw Dictionary]
    Raw --> Classifier[M2RuntimeMeshRebuildClassifier]
    Classifier --> Decision[Memoized rebuild boolean]
    Decision --> Loader
    Loader -->|true| Builder[M2Builder rebuild]
    Loader -->|false| Refresh[Mark material refresh version]

Allowed dependencies are Dictionary/Array, PackedInt32Array, Vector4 and scalar math. Files, ResourceLoader, parser/builder classes, SceneTree, WorkerThreadPool, Mesh/Node/RID ownership and other layers are forbidden.

Public API

Symbol Kind Purpose Thread/lifetime Errors
needs_runtime_mesh_rebuild(normalized_relative_path, raw_m2_data) Memoized query Detect billboard or referenced UV rotation requirements Renderer main thread; cached until clear Invalid variants/indices are skipped; first path decision wins
clear() Command Drop all memoized path decisions Main thread; map reset/shutdown Idempotent
cached_path_count() Query Return memoized path count Main thread None
diagnostic_snapshot() Query Return detached path/decision map Main thread; caller-owned None

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Normalized M2 relative path Loader cache lookup Classifier cache key String value copied Until clear
Input Raw M2 batches/transforms/combos Dictionary Native M2Loader adapter Classifier Borrowed; not mutated First classification call per path
Output Rebuild-required boolean Classifier Loader material-refresh adapter Scalar Memoized until clear
Output Detached decision Dictionary Classifier Verifier/future diagnostics Caller-owned copy Snapshot lifetime

Side effects are limited to inserting and clearing boolean memoization entries.

Data flow

flowchart TD
    Query[path + raw M2 data] --> Cached{Path cached?}
    Cached -->|yes| Return[Return first decision]
    Cached -->|no| Billboard{Any billboard flag or positive vertex count?}
    Billboard -->|yes| StoreTrue[Store true]
    Billboard -->|no| Inputs{Transforms and combos present?}
    Inputs -->|no| StoreFalse[Store false]
    Inputs -->|yes| Batch[For each Dictionary batch]
    Batch --> Stage[Inspect at most four referenced stages]
    Stage --> Rotation{Non-identity rotation or speed above epsilon?}
    Rotation -->|yes| StoreTrue
    Rotation -->|no| StoreFalse
    StoreTrue --> Return
    StoreFalse --> Return

Lifecycle/state

Each path moves from unknown to one immutable cached boolean. Clear returns all paths to unknown; no resource lifecycle participates.

stateDiagram-v2
    [*] --> Unknown
    Unknown --> RebuildRequired: billboard or referenced UV rotation
    Unknown --> RebuildNotRequired: no relevant metadata
    RebuildRequired --> RebuildRequired: repeated query
    RebuildNotRequired --> RebuildNotRequired: repeated query
    RebuildRequired --> Unknown: clear
    RebuildNotRequired --> Unknown: clear

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant Native as M2Loader
    participant Classifier as M2RuntimeMeshRebuildClassifier
    participant Builder as M2Builder
    Loader->>Native: load_m2(normalized path)
    Native-->>Loader: raw Dictionary
    Loader->>Classifier: needs_runtime_mesh_rebuild(path, data)
    Classifier-->>Loader: memoized boolean
    alt rebuild required
        Loader->>Builder: rebuild mesh from raw data
    else no rebuild required
        Loader->>Loader: stamp material refresh version
    end

Dependency diagram

flowchart TB
    Loader[StreamingWorldLoader] --> Classifier[M2RuntimeMeshRebuildClassifier]
    Loader --> Native[M2Loader]
    Loader --> Builder[M2Builder]
    Loader --> Cache[M2 Mesh/Scene caches]
    Classifier -. no dependency .-> Native
    Classifier -. no dependency .-> Builder
    Classifier -. no dependency .-> Cache

Ownership, threading and resources

  • The classifier owns only normalized-path boolean entries.
  • The loader owns raw loading, cache/resource selection, Mesh replacement and material refresh metadata.
  • Raw Dictionaries are borrowed and never retained; only the computed boolean is cached.
  • Current calls and clears are serialized on the renderer main thread.
  • No Node, Resource, Mesh, material or RID reference crosses into the classifier.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Non-Dictionary batch/transform Type guard Skip entry or use identity defaults Synthetic verifier Correct parser data on next cleared lifetime
Missing transforms/combos Empty guard No UV-driven rebuild Synthetic verifier Billboard classification still applies
Invalid combo/transform index Bounds guard Skip stage Synthetic verifier Correct raw data and clear
Repeated path with changed data Cache hit Preserve first decision Memoization fixture Map/reset clear recomputes
Load/build failure Outside classifier Existing mesh fallback remains Loader diagnostics Existing reload/fallback path

Configuration and capabilities

Setting/capability Default Profile Runtime mutable Effect
Maximum texture stages inspected 4 Existing M2 material path No Preserves historical four-stage shader boundary
UV rotation-speed epsilon 0.000001 exclusive Existing M2 material path No Larger absolute speed requires rebuild
M2_MATERIAL_REFRESH_VERSION Loader constant 2 All Code version Gates whether classifier is called

Persistence, cache and migration

Memoized booleans are runtime-only and are cleared at the two historical loader reset/shutdown sites. No persisted cache version or rebuild instruction changes.

Diagnostics and observability

  • Logs: none.
  • Metrics: cached_path_count is contract-level only and not added to runtime logs.
  • Debug views: detached path-to-boolean snapshot.
  • Correlation IDs: normalized M2 relative path.

Verification

  • verify_m2_runtime_mesh_rebuild_classifier.gd: billboard flag/count, invalid variants, identity/non-identity rotation, positive/negative speed, exact epsilon, four-stage cap, invalid indices, memoization, clear, source boundary and 100-by-256 timing.
  • Existing M2 builder/material verifiers cover downstream shader/cache behavior.
  • Fidelity evidence is exact predicate/cache extraction. No new asset-backed or original-client parity claim is made.
  • Performance budget: 25,600 classifications and clears under one second.

Extension points

  • A typed raw M2 material descriptor may replace the Dictionary only with parser fixtures and a compatibility adapter.
  • Mesh request/cache/finalization state can be extracted separately without changing this rebuild predicate.

Capability status

Capability Status Evidence Gap/next step
Billboard rebuild classification Implemented extraction Flag/count fixtures Asset-backed cache refresh timing pending
UV-rotation rebuild classification Implemented extraction Combo/stage/threshold fixtures More build-12340 material fixtures pending
Runtime memoization lifetime Implemented extraction First-decision/clear/source fixtures Byte/count runtime metric not exposed
M2 mesh loading/finalization Existing loader-owned Material/shutdown regressions Separate state extraction pending

Known gaps and risks

  • Raw parser data remains Dictionary-based.
  • The first decision wins even if different raw data is passed for the same path; this intentionally preserves prior cache behavior.
  • Only four texture stages are inspected, matching current material support.
  • No private asset traversal, descriptor-pressure, p95/p99 or paired visual run is included.

Source map

Path Responsibility
src/render/m2/m2_runtime_mesh_rebuild_classifier.gd Predicate, thresholds and boolean memoization
src/scenes/streaming/streaming_world_loader.gd Raw loading, Mesh rebuild/adoption, refresh version and clear calls
addons/mpq_extractor/loaders/m2_builder.gd Mesh/material rebuild implementation
src/tools/verify_m2_runtime_mesh_rebuild_classifier.gd Synthetic predicate/cache/boundary/timing regression