ece7724a28
Work-Package: M03-RND-M2-RUNTIME-MESH-FINALIZER-001 Agent: sindo-main-codex Tests: 37 headless renderer/coordinate contracts pass; checkpoint dry-run 7/7; documentation and coordination gates pass Fidelity: preserves refresh version 2, classifier, rebuild and fallback transitions; no visual parity claim
79 lines
2.5 KiB
GDScript
79 lines
2.5 KiB
GDScript
class_name M2RuntimeMeshFinalizer
|
|
extends RefCounted
|
|
|
|
## Finalizes stale cached M2 Meshes using caller-supplied raw data. The caller
|
|
## owns raw-file I/O, cache adoption, missing state and materialization.
|
|
|
|
const M2_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_builder.gd")
|
|
const M2_RUNTIME_MESH_REBUILD_CLASSIFIER_SCRIPT := preload(
|
|
"res://src/render/m2/m2_runtime_mesh_rebuild_classifier.gd"
|
|
)
|
|
const M2_MESH_RESOURCE_EXTRACTOR_SCRIPT := preload(
|
|
"res://src/render/m2/m2_mesh_resource_extractor.gd"
|
|
)
|
|
|
|
const MATERIAL_REFRESH_VERSION := 2
|
|
const MATERIAL_REFRESH_VERSION_META := "wow_m2_material_refresh_version"
|
|
|
|
var _runtime_mesh_rebuild_classifier := M2_RUNTIME_MESH_REBUILD_CLASSIFIER_SCRIPT.new()
|
|
var _mesh_resource_extractor := M2_MESH_RESOURCE_EXTRACTOR_SCRIPT.new()
|
|
|
|
|
|
## Returns whether one Mesh is stale and the caller should load raw M2 data.
|
|
func requires_raw_data_for_refresh(mesh: Mesh) -> bool:
|
|
return (
|
|
mesh != null
|
|
and int(mesh.get_meta(MATERIAL_REFRESH_VERSION_META, 0)) < MATERIAL_REFRESH_VERSION
|
|
)
|
|
|
|
|
|
## Marks, rebuilds or falls back one stale Mesh using already-loaded raw M2
|
|
## data. Current Meshes return unchanged and never inspect raw data.
|
|
func finalize_mesh(
|
|
normalized_relative_path: String,
|
|
mesh: Mesh,
|
|
raw_m2_data: Dictionary,
|
|
extracted_directory: String) -> Mesh:
|
|
if mesh == null:
|
|
return null
|
|
if not requires_raw_data_for_refresh(mesh):
|
|
return mesh
|
|
if raw_m2_data.is_empty() or not _runtime_mesh_rebuild_classifier.needs_runtime_mesh_rebuild(
|
|
normalized_relative_path,
|
|
raw_m2_data):
|
|
_mark_mesh_current(mesh)
|
|
return mesh
|
|
var rebuilt_mesh := _rebuild_mesh(raw_m2_data, extracted_directory)
|
|
if rebuilt_mesh != null:
|
|
return rebuilt_mesh
|
|
_mark_mesh_current(mesh)
|
|
return mesh
|
|
|
|
|
|
## Clears memoized per-path rebuild decisions at the existing map/shutdown sites.
|
|
func clear() -> void:
|
|
_runtime_mesh_rebuild_classifier.clear()
|
|
|
|
|
|
## Returns the memoized rebuild-decision count for diagnostics and verification.
|
|
func cached_rebuild_decision_count() -> int:
|
|
return _runtime_mesh_rebuild_classifier.cached_path_count()
|
|
|
|
|
|
func _mark_mesh_current(mesh: Mesh) -> void:
|
|
mesh.set_meta(MATERIAL_REFRESH_VERSION_META, MATERIAL_REFRESH_VERSION)
|
|
|
|
|
|
func _rebuild_mesh(raw_m2_data: Dictionary, extracted_directory: String) -> Mesh:
|
|
var temporary_prototype: Node3D = M2_BUILDER_SCRIPT.build(
|
|
raw_m2_data,
|
|
extracted_directory
|
|
)
|
|
if temporary_prototype == null:
|
|
return null
|
|
var rebuilt_mesh := _mesh_resource_extractor.find_first_mesh_in_subtree(
|
|
temporary_prototype
|
|
)
|
|
temporary_prototype.free()
|
|
return rebuilt_mesh
|