refactor(M03): extract M2 prototype cache state
This commit is contained in:
@@ -66,6 +66,9 @@ const M2_RUNTIME_MESH_FINALIZER_SCRIPT := preload(
|
||||
const M2_RAW_MODEL_REPOSITORY_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_raw_model_repository.gd"
|
||||
)
|
||||
const M2_PROTOTYPE_CACHE_STATE_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_prototype_cache_state.gd"
|
||||
)
|
||||
const M2_MESH_LOAD_PIPELINE_STATE_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_mesh_load_pipeline_state.gd"
|
||||
)
|
||||
@@ -263,6 +266,7 @@ var _m2_placement_grouper := M2_PLACEMENT_GROUPER_SCRIPT.new()
|
||||
var _m2_build_batch_planner := M2_BUILD_BATCH_PLANNER_SCRIPT.new()
|
||||
var _m2_runtime_mesh_finalizer := M2_RUNTIME_MESH_FINALIZER_SCRIPT.new()
|
||||
var _m2_raw_model_repository := M2_RAW_MODEL_REPOSITORY_SCRIPT.new()
|
||||
var _m2_prototype_cache_state := M2_PROTOTYPE_CACHE_STATE_SCRIPT.new()
|
||||
var _m2_mesh_resource_cache_state := M2_MESH_RESOURCE_CACHE_STATE_SCRIPT.new()
|
||||
var _m2_mesh_resource_extractor := M2_MESH_RESOURCE_EXTRACTOR_SCRIPT.new()
|
||||
var _m2_mesh_load_pipeline_state := M2_MESH_LOAD_PIPELINE_STATE_SCRIPT.new()
|
||||
@@ -309,10 +313,6 @@ var _wmo_render_build_queue := WMO_RENDER_BUILD_QUEUE_SCRIPT.new()
|
||||
var _wmo_scene_resource_cache_state := WMO_SCENE_RESOURCE_CACHE_STATE_SCRIPT.new()
|
||||
var _wmo_missing_cache: Dictionary = {}
|
||||
var _wmo_placement_resolver := WMO_PLACEMENT_RESOLVER_SCRIPT.new()
|
||||
var _m2_scene_cache: Dictionary = {}
|
||||
var _m2_animated_scene_cache: Dictionary = {}
|
||||
var _m2_static_animation_cache: Dictionary = {}
|
||||
var _m2_missing_cache: Dictionary = {}
|
||||
var _world_wmo_root: Node3D
|
||||
var _wmo_placement_registry := WMO_PLACEMENT_REGISTRY_SCRIPT.new()
|
||||
var _wmo_render_build_step_planner := WMO_RENDER_BUILD_STEP_PLANNER_SCRIPT.new()
|
||||
@@ -481,12 +481,9 @@ func _render_operation_limits_for_frame() -> Dictionary:
|
||||
## loader after all asynchronous work has completed. Map refreshes retain these
|
||||
## caches; only scene shutdown destroys them.
|
||||
func _release_runtime_caches_for_shutdown() -> void:
|
||||
_free_detached_node_cache(_m2_scene_cache)
|
||||
_free_detached_node_cache(_m2_animated_scene_cache)
|
||||
_m2_prototype_cache_state.clear_and_release()
|
||||
_free_detached_node_cache(_wmo_prototype_cache)
|
||||
_m2_mesh_resource_cache_state.clear()
|
||||
_m2_static_animation_cache.clear()
|
||||
_m2_missing_cache.clear()
|
||||
_wmo_render_resource_cache_state.clear_all()
|
||||
_wmo_scene_resource_cache_state.clear_all()
|
||||
_wmo_missing_cache.clear()
|
||||
@@ -4219,7 +4216,7 @@ func _drain_m2_animation_loads() -> void:
|
||||
var path := String(pending.get("path", ""))
|
||||
if path.is_empty():
|
||||
_m2_animation_load_requests.erase(normalized_rel)
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
continue
|
||||
var status := ResourceLoader.load_threaded_get_status(path)
|
||||
if status != ResourceLoader.THREAD_LOAD_LOADED and status != ResourceLoader.THREAD_LOAD_FAILED:
|
||||
@@ -4232,10 +4229,14 @@ func _drain_m2_animation_loads() -> void:
|
||||
RENDER_BUDGET_SCHEDULER_SCRIPT.M2_ANIMATION_FINALIZE):
|
||||
var pending: Dictionary = _m2_animation_finalize_queue.pop_front()
|
||||
var normalized_rel := String(pending.get("normalized", ""))
|
||||
if normalized_rel.is_empty() or _m2_animated_scene_cache.has(normalized_rel) or _m2_static_animation_cache.has(normalized_rel):
|
||||
if (
|
||||
normalized_rel.is_empty()
|
||||
or _m2_prototype_cache_state.has_animated_prototype(normalized_rel)
|
||||
or _m2_prototype_cache_state.is_animation_static(normalized_rel)
|
||||
):
|
||||
continue
|
||||
if int(pending.get("status", ResourceLoader.THREAD_LOAD_FAILED)) != ResourceLoader.THREAD_LOAD_LOADED:
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
continue
|
||||
|
||||
var path := String(pending.get("path", ""))
|
||||
@@ -4246,12 +4247,15 @@ func _drain_m2_animation_loads() -> void:
|
||||
_repair_m2_animated_materials(normalized_rel, node as Node3D)
|
||||
var players := _find_animation_players_recursive(node)
|
||||
if not players.is_empty():
|
||||
_m2_animated_scene_cache[normalized_rel] = node as Node3D
|
||||
_m2_prototype_cache_state.adopt_animated_prototype(
|
||||
normalized_rel,
|
||||
node as Node3D
|
||||
)
|
||||
if debug_streaming:
|
||||
print("M2_ANIM_CACHE path=%s cache=%s players=%d" % [normalized_rel, path, players.size()])
|
||||
continue
|
||||
node.free()
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
|
||||
|
||||
func _drain_m2_mesh_loads() -> void:
|
||||
@@ -4260,7 +4264,7 @@ func _drain_m2_mesh_loads() -> void:
|
||||
var path: String = String(pending.get("path", ""))
|
||||
if path.is_empty():
|
||||
_m2_mesh_load_pipeline_state.discard_request(normalized_rel)
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
continue
|
||||
var status := ResourceLoader.load_threaded_get_status(path)
|
||||
if status != ResourceLoader.THREAD_LOAD_LOADED and status != ResourceLoader.THREAD_LOAD_FAILED:
|
||||
@@ -4277,7 +4281,7 @@ func _drain_m2_mesh_loads() -> void:
|
||||
):
|
||||
continue
|
||||
if int(pending.get("status", ResourceLoader.THREAD_LOAD_FAILED)) != ResourceLoader.THREAD_LOAD_LOADED:
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
continue
|
||||
|
||||
var path := String(pending.get("path", ""))
|
||||
@@ -4289,7 +4293,7 @@ func _drain_m2_mesh_loads() -> void:
|
||||
_prepare_m2_mesh_for_runtime(normalized_rel, mesh)
|
||||
)
|
||||
else:
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
|
||||
|
||||
func _process_m2_build_jobs() -> void:
|
||||
@@ -4357,7 +4361,7 @@ func _process_m2_build_jobs() -> void:
|
||||
else:
|
||||
var mesh := _get_m2_mesh_or_request(rel_path)
|
||||
if mesh == null:
|
||||
if not _m2_missing_cache.has(normalized_rel):
|
||||
if not _m2_prototype_cache_state.is_model_missing(normalized_rel):
|
||||
_m2_build_queue.pop_front()
|
||||
_m2_build_queue.append(key)
|
||||
_render_budget_scheduler.try_consume_permit(RENDER_BUDGET_SCHEDULER_SCRIPT.M2_BUILD)
|
||||
@@ -4624,7 +4628,7 @@ func _get_m2_mesh_or_request(rel_path: String) -> Mesh:
|
||||
return null
|
||||
if _m2_mesh_resource_cache_state.has_mesh(normalized_rel):
|
||||
return _m2_mesh_resource_cache_state.find_mesh(normalized_rel)
|
||||
if _m2_missing_cache.has(normalized_rel):
|
||||
if _m2_prototype_cache_state.is_model_missing(normalized_rel):
|
||||
return null
|
||||
_request_m2_mesh_load(normalized_rel)
|
||||
return null
|
||||
@@ -4649,7 +4653,7 @@ func _request_m2_mesh_load(normalized_rel: String) -> void:
|
||||
return
|
||||
break
|
||||
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
|
||||
|
||||
func _prepare_m2_mesh_for_runtime(normalized_rel: String, mesh: Mesh) -> Mesh:
|
||||
@@ -4840,11 +4844,11 @@ func _get_or_load_m2_prototype(rel_path: String) -> Node3D:
|
||||
var normalized_rel := _normalize_m2_rel_path(rel_path)
|
||||
if normalized_rel.is_empty():
|
||||
return null
|
||||
if _m2_scene_cache.has(normalized_rel):
|
||||
var cached: Node3D = _m2_scene_cache[normalized_rel]
|
||||
var cached := _m2_prototype_cache_state.find_static_prototype(normalized_rel)
|
||||
if cached != null:
|
||||
_prepare_m2_node_for_runtime(normalized_rel, cached)
|
||||
return cached
|
||||
if _m2_missing_cache.has(normalized_rel):
|
||||
if _m2_prototype_cache_state.is_model_missing(normalized_rel):
|
||||
return null
|
||||
|
||||
# Try pre-baked cache (.tscn first, then legacy .glb)
|
||||
@@ -4858,8 +4862,10 @@ func _get_or_load_m2_prototype(rel_path: String) -> Node3D:
|
||||
var node = (resource as PackedScene).instantiate()
|
||||
if node is Node3D:
|
||||
_prepare_m2_node_for_runtime(normalized_rel, node as Node3D)
|
||||
_m2_scene_cache[normalized_rel] = node as Node3D
|
||||
return node as Node3D
|
||||
return _m2_prototype_cache_state.adopt_static_prototype(
|
||||
normalized_rel,
|
||||
node as Node3D
|
||||
)
|
||||
break
|
||||
|
||||
# Fall back to the raw native M2 repository.
|
||||
@@ -4868,25 +4874,30 @@ func _get_or_load_m2_prototype(rel_path: String) -> Node3D:
|
||||
normalized_rel
|
||||
)
|
||||
if data.is_empty():
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
return null
|
||||
|
||||
var prototype: Node3D = M2_BUILDER_SCRIPT.build(data, extracted_dir)
|
||||
if prototype == null:
|
||||
_m2_missing_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_model_missing(normalized_rel)
|
||||
return null
|
||||
|
||||
_m2_scene_cache[normalized_rel] = prototype
|
||||
return prototype
|
||||
return _m2_prototype_cache_state.adopt_static_prototype(
|
||||
normalized_rel,
|
||||
prototype
|
||||
)
|
||||
|
||||
|
||||
func _get_or_load_m2_native_animated_prototype(rel_path: String) -> Node3D:
|
||||
var normalized_rel := _normalize_m2_rel_path(rel_path)
|
||||
if normalized_rel.is_empty() or not _is_m2_native_animation_candidate(normalized_rel):
|
||||
return null
|
||||
if _m2_animated_scene_cache.has(normalized_rel):
|
||||
return _m2_animated_scene_cache[normalized_rel]
|
||||
if _m2_static_animation_cache.has(normalized_rel):
|
||||
var cached_animated := _m2_prototype_cache_state.find_animated_prototype(
|
||||
normalized_rel
|
||||
)
|
||||
if cached_animated != null:
|
||||
return cached_animated
|
||||
if _m2_prototype_cache_state.is_animation_static(normalized_rel):
|
||||
return null
|
||||
var data := _m2_raw_model_repository.load_animated_model_data(
|
||||
extracted_dir,
|
||||
@@ -4894,15 +4905,18 @@ func _get_or_load_m2_native_animated_prototype(rel_path: String) -> Node3D:
|
||||
)
|
||||
var animated_surfaces: Array = data.get("animated_surfaces", [])
|
||||
if data.is_empty() or animated_surfaces.is_empty():
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
return null
|
||||
|
||||
var prototype: Node3D = M2_NATIVE_ANIMATED_BUILDER_SCRIPT.build(data, extracted_dir)
|
||||
if prototype == null or prototype.get_child_count() <= 0:
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
return null
|
||||
|
||||
_m2_animated_scene_cache[normalized_rel] = prototype
|
||||
prototype = _m2_prototype_cache_state.adopt_animated_prototype(
|
||||
normalized_rel,
|
||||
prototype
|
||||
)
|
||||
if debug_streaming:
|
||||
print("M2_NATIVE_ANIM_CACHE path=%s surfaces=%d bones=%d anim_id=%d seq=%d score=%d length=%.2f" % [
|
||||
normalized_rel,
|
||||
@@ -4924,9 +4938,12 @@ func _get_or_load_m2_animated_prototype(rel_path: String) -> Node3D:
|
||||
var normalized_rel := _normalize_m2_rel_path(rel_path)
|
||||
if normalized_rel.is_empty():
|
||||
return null
|
||||
if _m2_animated_scene_cache.has(normalized_rel):
|
||||
return _m2_animated_scene_cache[normalized_rel]
|
||||
if _m2_static_animation_cache.has(normalized_rel):
|
||||
var cached_animated := _m2_prototype_cache_state.find_animated_prototype(
|
||||
normalized_rel
|
||||
)
|
||||
if cached_animated != null:
|
||||
return cached_animated
|
||||
if _m2_prototype_cache_state.is_animation_static(normalized_rel):
|
||||
return null
|
||||
if _m2_animation_load_requests.has(normalized_rel):
|
||||
return null
|
||||
@@ -4940,7 +4957,7 @@ func _request_m2_animation_load(normalized_rel: String) -> void:
|
||||
return
|
||||
var cache_res_path := _find_m2_animated_glb_cache_path(normalized_rel)
|
||||
if cache_res_path.is_empty():
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
return
|
||||
var err := ResourceLoader.load_threaded_request(
|
||||
cache_res_path,
|
||||
@@ -4953,7 +4970,7 @@ func _request_m2_animation_load(normalized_rel: String) -> void:
|
||||
"path": cache_res_path,
|
||||
}
|
||||
else:
|
||||
_m2_static_animation_cache[normalized_rel] = true
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
|
||||
|
||||
func _find_m2_animated_glb_cache_path(normalized_rel: String) -> String:
|
||||
@@ -5018,8 +5035,8 @@ func _repair_m2_animated_materials(normalized_rel: String, animated_root: Node3D
|
||||
func _get_or_load_m2_material_prototype(normalized_rel: String) -> Node3D:
|
||||
if normalized_rel.is_empty():
|
||||
return null
|
||||
if _m2_scene_cache.has(normalized_rel):
|
||||
var cached: Node3D = _m2_scene_cache[normalized_rel]
|
||||
var cached := _m2_prototype_cache_state.find_static_prototype(normalized_rel)
|
||||
if cached != null:
|
||||
_prepare_m2_node_for_runtime(normalized_rel, cached)
|
||||
return cached
|
||||
|
||||
@@ -5031,8 +5048,10 @@ func _get_or_load_m2_material_prototype(normalized_rel: String) -> Node3D:
|
||||
var node = (resource as PackedScene).instantiate()
|
||||
if node is Node3D:
|
||||
_prepare_m2_node_for_runtime(normalized_rel, node as Node3D)
|
||||
_m2_scene_cache[normalized_rel] = node as Node3D
|
||||
return node as Node3D
|
||||
return _m2_prototype_cache_state.adopt_static_prototype(
|
||||
normalized_rel,
|
||||
node as Node3D
|
||||
)
|
||||
return null
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user