Files
open-wc/src/render/m2/m2_mesh_resource_finalizer.gd
T

183 lines
4.9 KiB
GDScript

class_name M2MeshResourceFinalizer
extends RefCounted
## Polls static M2 ResourceLoader requests and publishes prepared Mesh outcomes.
## The caller owns permits, pipeline/cache lifetime and MultiMesh materialization.
var _mesh_resource_extractor: RefCounted
var _runtime_mesh_finalizer: RefCounted
var _raw_model_repository: RefCounted
var _resource_loader_adapter: Object
func _init(
mesh_resource_extractor: RefCounted,
runtime_mesh_finalizer: RefCounted,
raw_model_repository: RefCounted,
resource_loader_adapter: Object = null
) -> void:
_mesh_resource_extractor = mesh_resource_extractor
_runtime_mesh_finalizer = runtime_mesh_finalizer
_raw_model_repository = raw_model_repository
_resource_loader_adapter = resource_loader_adapter
## Moves terminal threaded requests into the pipeline finalize FIFO.
## Empty resource paths retain the historical immediate missing-model outcome.
func poll_terminal_requests(
load_pipeline_state: RefCounted,
prototype_cache_state: RefCounted
) -> int:
if load_pipeline_state == null or prototype_cache_state == null:
return 0
var completed_request_count := 0
var request_records: Array = load_pipeline_state.call(
"request_records_snapshot"
)
for request_variant in request_records:
if not (request_variant is Dictionary):
continue
var request: Dictionary = request_variant
var normalized_relative_path := String(request.get("normalized", ""))
var resource_path := String(request.get("path", ""))
if resource_path.is_empty():
load_pipeline_state.call(
"discard_request",
normalized_relative_path
)
prototype_cache_state.call(
"mark_model_missing",
normalized_relative_path
)
completed_request_count += 1
continue
var load_status := load_threaded_get_status(resource_path)
if (
load_status != ResourceLoader.THREAD_LOAD_LOADED
and load_status != ResourceLoader.THREAD_LOAD_FAILED
):
continue
load_pipeline_state.call(
"complete_request",
normalized_relative_path,
load_status
)
completed_request_count += 1
return completed_request_count
## Pops and finalizes one terminal record. A true result means a record was
## consumed, including cached, failed and invalid outcomes.
func finalize_next_resource(
load_pipeline_state: RefCounted,
mesh_resource_cache_state: RefCounted,
prototype_cache_state: RefCounted,
extracted_directory: String
) -> bool:
if (
load_pipeline_state == null
or mesh_resource_cache_state == null
or prototype_cache_state == null
):
return false
var terminal_record: Dictionary = load_pipeline_state.call(
"pop_finalize_record"
)
if terminal_record.is_empty():
return false
var normalized_relative_path := String(
terminal_record.get("normalized", "")
)
if (
normalized_relative_path.is_empty()
or bool(mesh_resource_cache_state.call(
"has_mesh",
normalized_relative_path
))
):
return true
if int(terminal_record.get(
"status",
ResourceLoader.THREAD_LOAD_FAILED
)) != ResourceLoader.THREAD_LOAD_LOADED:
prototype_cache_state.call(
"mark_model_missing",
normalized_relative_path
)
return true
var resource_path := String(terminal_record.get("path", ""))
var loaded_resource := load_threaded_get(resource_path)
var mesh := _mesh_resource_extractor.call(
"extract_first_mesh",
loaded_resource
) as Mesh
if mesh == null:
prototype_cache_state.call(
"mark_model_missing",
normalized_relative_path
)
return true
mesh_resource_cache_state.call(
"store_mesh",
normalized_relative_path,
prepare_mesh_for_runtime(
normalized_relative_path,
mesh,
extracted_directory
)
)
return true
## Applies the existing refresh-version/raw-data/rebuild path to one Mesh.
func prepare_mesh_for_runtime(
normalized_relative_path: String,
mesh: Mesh,
extracted_directory: String
) -> Mesh:
if mesh == null:
return null
if (
_runtime_mesh_finalizer == null
or not bool(_runtime_mesh_finalizer.call(
"requires_raw_data_for_refresh",
mesh
))
):
return mesh
var raw_model_data: Dictionary = {}
if _raw_model_repository != null:
raw_model_data = _raw_model_repository.call(
"load_static_model_data",
extracted_directory,
normalized_relative_path
)
return _runtime_mesh_finalizer.call(
"finalize_mesh",
normalized_relative_path,
mesh,
raw_model_data,
extracted_directory
) as Mesh
## Production ResourceLoader status adapter; injectable in synthetic tests.
func load_threaded_get_status(resource_path: String) -> int:
if _resource_loader_adapter != null:
return int(_resource_loader_adapter.call(
"load_threaded_get_status",
resource_path
))
return ResourceLoader.load_threaded_get_status(resource_path)
## Production ResourceLoader terminal-result adapter; injectable in tests.
func load_threaded_get(resource_path: String) -> Resource:
if _resource_loader_adapter != null:
return _resource_loader_adapter.call(
"load_threaded_get",
resource_path
) as Resource
return ResourceLoader.load_threaded_get(resource_path)