render: extract static M2 build resource observer
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
class_name M2StaticBuildResourceObserver
|
||||
extends RefCounted
|
||||
|
||||
## Resolves or requests one static M2 build Mesh and fills a resource snapshot.
|
||||
|
||||
const OUTCOME_REJECTED := &"rejected"
|
||||
const OUTCOME_CACHED := &"cached"
|
||||
const OUTCOME_PENDING := &"pending"
|
||||
const OUTCOME_REQUESTED := &"requested"
|
||||
const OUTCOME_MISSING := &"missing"
|
||||
|
||||
|
||||
## Observes cache/request state and adopts the exact static result into snapshot.
|
||||
func observe(
|
||||
resource_snapshot: RefCounted,
|
||||
normalized_relative_path: String,
|
||||
cache_directory: String,
|
||||
mesh_cache_state: RefCounted,
|
||||
prototype_cache_state: RefCounted,
|
||||
load_pipeline_state: RefCounted
|
||||
) -> StringName:
|
||||
if (
|
||||
resource_snapshot == null
|
||||
or normalized_relative_path.is_empty()
|
||||
or mesh_cache_state == null
|
||||
or prototype_cache_state == null
|
||||
or load_pipeline_state == null
|
||||
):
|
||||
return OUTCOME_REJECTED
|
||||
if bool(mesh_cache_state.call("has_mesh", normalized_relative_path)):
|
||||
resource_snapshot.call(
|
||||
"adopt_static_observation",
|
||||
mesh_cache_state.call("find_mesh", normalized_relative_path) as Mesh,
|
||||
false
|
||||
)
|
||||
return OUTCOME_CACHED
|
||||
if bool(prototype_cache_state.call("is_model_missing", normalized_relative_path)):
|
||||
resource_snapshot.call("adopt_static_observation", null, true)
|
||||
return OUTCOME_MISSING
|
||||
if bool(load_pipeline_state.call("has_request", normalized_relative_path)):
|
||||
resource_snapshot.call("adopt_static_observation", null, false)
|
||||
return OUTCOME_PENDING
|
||||
|
||||
for cache_resource_path in cache_resource_paths(
|
||||
cache_directory,
|
||||
normalized_relative_path,
|
||||
[".tscn", ".glb"]
|
||||
):
|
||||
if not ResourceLoader.exists(cache_resource_path):
|
||||
continue
|
||||
if (
|
||||
cache_resource_path.get_extension().to_lower() == "glb"
|
||||
and glb_animation_schema(cache_resource_path) == "pivot_prefix_v1"
|
||||
):
|
||||
continue
|
||||
var request_error := ResourceLoader.load_threaded_request(
|
||||
cache_resource_path,
|
||||
"",
|
||||
false,
|
||||
ResourceLoader.CACHE_MODE_REUSE
|
||||
)
|
||||
if request_error == OK or request_error == ERR_BUSY:
|
||||
load_pipeline_state.call(
|
||||
"remember_request",
|
||||
normalized_relative_path,
|
||||
cache_resource_path
|
||||
)
|
||||
resource_snapshot.call("adopt_static_observation", null, false)
|
||||
return OUTCOME_REQUESTED
|
||||
break
|
||||
|
||||
prototype_cache_state.call("mark_model_missing", normalized_relative_path)
|
||||
resource_snapshot.call("adopt_static_observation", null, true)
|
||||
return OUTCOME_MISSING
|
||||
|
||||
|
||||
## Returns historical nested/lowercase/basename cache candidates without I/O.
|
||||
func cache_resource_paths(
|
||||
cache_directory: String,
|
||||
relative_path: String,
|
||||
extensions: Array[String]
|
||||
) -> PackedStringArray:
|
||||
var normalized := relative_path.replace("\\", "/")
|
||||
var lower := normalized.to_lower()
|
||||
var stems := [
|
||||
normalized.get_basename(),
|
||||
lower.get_basename(),
|
||||
normalized.get_file().get_basename(),
|
||||
lower.get_file().get_basename(),
|
||||
]
|
||||
var result := PackedStringArray()
|
||||
for extension in extensions:
|
||||
for stem in stems:
|
||||
if stem.is_empty():
|
||||
continue
|
||||
var path := cache_directory.path_join(stem + extension)
|
||||
if not result.has(path):
|
||||
result.append(path)
|
||||
return result
|
||||
|
||||
|
||||
## Reads only the OpenWC animation schema marker from a GLB JSON chunk.
|
||||
func glb_animation_schema(cache_resource_path: String) -> String:
|
||||
var absolute_path := ProjectSettings.globalize_path(cache_resource_path)
|
||||
if not FileAccess.file_exists(absolute_path):
|
||||
return ""
|
||||
var file := FileAccess.open(absolute_path, FileAccess.READ)
|
||||
if file == null or file.get_length() < 20:
|
||||
return ""
|
||||
var magic := file.get_32()
|
||||
var version := file.get_32()
|
||||
file.get_32()
|
||||
if magic != 0x46546c67 or version != 2:
|
||||
return ""
|
||||
var json_length := int(file.get_32())
|
||||
var chunk_type := file.get_32()
|
||||
if json_length <= 0 or chunk_type != 0x4e4f534a:
|
||||
return ""
|
||||
var parsed: Variant = JSON.parse_string(
|
||||
file.get_buffer(json_length).get_string_from_utf8()
|
||||
)
|
||||
if not (parsed is Dictionary):
|
||||
return ""
|
||||
var asset: Dictionary = (parsed as Dictionary).get("asset", {})
|
||||
var extras: Dictionary = asset.get("extras", {})
|
||||
return String(extras.get("openwc_m2_anim_schema", ""))
|
||||
@@ -0,0 +1 @@
|
||||
uid://c0e3p80ld1dfb
|
||||
Reference in New Issue
Block a user