refactor(M03): extract WMO scene resource cache state

This commit is contained in:
2026-07-17 01:19:19 +04:00
parent 71fa093118
commit c83929428d
11 changed files with 783 additions and 40 deletions
+30 -28
View File
@@ -24,6 +24,9 @@ const WMO_RENDER_BUILD_QUEUE_SCRIPT := preload(
const WMO_RENDER_RESOURCE_CACHE_STATE_SCRIPT := preload(
"res://src/render/wmo/wmo_render_resource_cache_state.gd"
)
const WMO_SCENE_RESOURCE_CACHE_STATE_SCRIPT := preload(
"res://src/render/wmo/wmo_scene_resource_cache_state.gd"
)
const M2_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_builder.gd")
const M2_NATIVE_ANIMATED_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_native_animated_builder.gd")
const M2_NATIVE_ANIMATOR_SCRIPT := preload("res://src/scenes/streaming/m2_native_animator.gd")
@@ -285,9 +288,7 @@ var _terrain_quality_mesh_cache: RefCounted = TERRAIN_QUALITY_MESH_CACHE_SCRIPT.
var _wmo_prototype_cache: Dictionary = {}
var _wmo_render_resource_cache_state := WMO_RENDER_RESOURCE_CACHE_STATE_SCRIPT.new()
var _wmo_render_build_queue := WMO_RENDER_BUILD_QUEUE_SCRIPT.new()
var _wmo_scene_resource_cache: Dictionary = {}
var _wmo_scene_cache_missing: Dictionary = {}
var _wmo_scene_load_requests: Dictionary = {}
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 = {}
@@ -469,8 +470,7 @@ func _release_runtime_caches_for_shutdown() -> void:
_m2_static_animation_cache.clear()
_m2_missing_cache.clear()
_wmo_render_resource_cache_state.clear_all()
_wmo_scene_resource_cache.clear()
_wmo_scene_cache_missing.clear()
_wmo_scene_resource_cache_state.clear_all()
_wmo_missing_cache.clear()
_shared_tex_cache.clear()
@@ -1007,7 +1007,7 @@ func _log_hitch_profile(start_usec: int, timings: Array[String], did_refresh: bo
_m2_build_queue.size(),
(
_wmo_build_queue.size()
+ _wmo_scene_load_requests.size()
+ _wmo_scene_resource_cache_state.pending_request_count()
+ _wmo_render_resource_cache_state.pending_request_count()
),
_wmo_render_build_queue.pending_count(),
@@ -1038,7 +1038,7 @@ func render_baseline_snapshot() -> Dictionary:
"m2_build": _m2_build_queue.size(),
"wmo_build": (
_wmo_build_queue.size()
+ _wmo_scene_load_requests.size()
+ _wmo_scene_resource_cache_state.pending_request_count()
+ _wmo_render_resource_cache_state.pending_request_count()
),
"wmo_groups": _wmo_render_build_queue.pending_count(),
@@ -1324,7 +1324,7 @@ func _tick_runtime_stats(delta: float) -> void:
_m2_build_queue.size(),
(
_wmo_build_queue.size()
+ _wmo_scene_load_requests.size()
+ _wmo_scene_resource_cache_state.pending_request_count()
+ _wmo_render_resource_cache_state.pending_request_count()
),
_wmo_render_build_queue.pending_count(),
@@ -2359,14 +2359,15 @@ func _wait_for_tile_tasks() -> void:
_m2_animation_load_requests.clear()
_m2_animation_finalize_queue.clear()
for path_variant in _wmo_scene_load_requests.values():
var wmo_scene_request_paths := _wmo_scene_resource_cache_state.request_paths_snapshot()
for path_variant in wmo_scene_request_paths.values():
var path := String(path_variant)
if path.is_empty():
continue
var status := ResourceLoader.load_threaded_get_status(path)
if status == ResourceLoader.THREAD_LOAD_IN_PROGRESS or status == ResourceLoader.THREAD_LOAD_LOADED:
ResourceLoader.load_threaded_get(path)
_wmo_scene_load_requests.clear()
_wmo_scene_resource_cache_state.clear_transient_state()
var wmo_render_request_paths := (
_wmo_render_resource_cache_state.request_paths_snapshot()
@@ -2379,7 +2380,6 @@ func _wait_for_tile_tasks() -> void:
if status == ResourceLoader.THREAD_LOAD_IN_PROGRESS or status == ResourceLoader.THREAD_LOAD_LOADED:
ResourceLoader.load_threaded_get(path)
_wmo_render_resource_cache_state.clear_transient_state()
_wmo_scene_cache_missing.clear()
_wmo_render_build_queue.clear()
for pending in _terrain_upgrade_tasks.values():
@@ -3015,9 +3015,8 @@ func _clear_streamed_world() -> void:
_m2_animation_finalize_queue.clear()
_wmo_build_jobs.clear()
_wmo_build_queue.clear()
_wmo_scene_load_requests.clear()
_wmo_scene_resource_cache_state.clear_transient_state()
_wmo_render_resource_cache_state.clear_transient_state()
_wmo_scene_cache_missing.clear()
_wmo_render_build_queue.clear()
_tile_result_mutex.lock()
@@ -3607,7 +3606,7 @@ func _process_wmo_build_jobs() -> void:
else:
var scene := _get_wmo_scene_or_request(rel_path)
if scene == null:
if _wmo_scene_load_requests.has(normalized_rel):
if _wmo_scene_resource_cache_state.has_request(normalized_rel):
advance_job = false
else:
var live_instance := _instantiate_wmo_world(rel_path, placement)
@@ -3662,21 +3661,24 @@ func _process_wmo_build_jobs() -> void:
func _drain_wmo_scene_loads() -> void:
for normalized_rel_variant in _wmo_scene_load_requests.keys():
var request_paths := _wmo_scene_resource_cache_state.request_paths_snapshot()
for normalized_rel_variant in request_paths.keys():
var normalized_rel := String(normalized_rel_variant)
var path := String(_wmo_scene_load_requests[normalized_rel])
var path := String(request_paths[normalized_rel])
var status := ResourceLoader.load_threaded_get_status(path)
if status != ResourceLoader.THREAD_LOAD_LOADED and status != ResourceLoader.THREAD_LOAD_FAILED:
continue
_wmo_scene_load_requests.erase(normalized_rel)
if status != ResourceLoader.THREAD_LOAD_LOADED:
_wmo_scene_cache_missing[normalized_rel] = true
_wmo_scene_resource_cache_state.complete_request_as_missing(normalized_rel)
continue
var resource: Resource = ResourceLoader.load_threaded_get(path)
if resource is PackedScene and _is_wmo_scene_cache_current(resource as PackedScene):
_wmo_scene_resource_cache[normalized_rel] = resource as PackedScene
_wmo_scene_resource_cache_state.complete_request_with_scene(
normalized_rel,
resource as PackedScene
)
else:
_wmo_scene_cache_missing[normalized_rel] = true
_wmo_scene_resource_cache_state.complete_request_as_missing(normalized_rel)
func _drain_wmo_render_loads() -> void:
@@ -3733,23 +3735,23 @@ func _get_wmo_scene_or_request(rel_path: String) -> PackedScene:
var normalized_rel := _wmo_placement_resolver.normalize_relative_path(rel_path)
if normalized_rel.is_empty():
return null
if _wmo_scene_resource_cache.has(normalized_rel):
return _wmo_scene_resource_cache[normalized_rel]
if _wmo_scene_cache_missing.has(normalized_rel):
if _wmo_scene_resource_cache_state.contains_scene(normalized_rel):
return _wmo_scene_resource_cache_state.scene_for(normalized_rel)
if _wmo_scene_resource_cache_state.is_missing(normalized_rel):
return null
if _wmo_scene_load_requests.has(normalized_rel):
if _wmo_scene_resource_cache_state.has_request(normalized_rel):
return null
var cache_path := wmo_cache_dir.path_join(normalized_rel.get_basename() + ".tscn")
if not ResourceLoader.exists(cache_path):
_wmo_scene_cache_missing[normalized_rel] = true
_wmo_scene_resource_cache_state.mark_missing(normalized_rel)
return null
if wmo_max_runtime_scene_mb > 0.0:
var size_bytes := _get_resource_file_size(cache_path)
var max_bytes := int(wmo_max_runtime_scene_mb * 1024.0 * 1024.0)
if size_bytes > max_bytes:
_wmo_scene_cache_missing[normalized_rel] = true
_wmo_scene_resource_cache_state.mark_missing(normalized_rel)
if debug_streaming:
print("StreamingWorld: skipping large WMO %.2f MB: %s" % [
float(size_bytes) / (1024.0 * 1024.0),
@@ -3763,9 +3765,9 @@ func _get_wmo_scene_or_request(rel_path: String) -> PackedScene:
false,
ResourceLoader.CACHE_MODE_REUSE)
if err == OK or err == ERR_BUSY:
_wmo_scene_load_requests[normalized_rel] = cache_path
_wmo_scene_resource_cache_state.remember_request(normalized_rel, cache_path)
else:
_wmo_scene_cache_missing[normalized_rel] = true
_wmo_scene_resource_cache_state.mark_missing(normalized_rel)
return null