extends SceneTree ## M03 repository gate preventing gameplay/EditorPlugin coupling to streamer internals. const STREAMING_WORLD_LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd" const GAMEPLAY_ROOT := "res://src/gameplay" const SOURCE_ROOTS: Array[String] = ["res://src", "res://addons"] const RENDERER_DIAGNOSTIC_PATHS: Array[String] = [ "res://src/tools/probe_render_terrain_height.gd", ] func _initialize() -> void: var failures: Array[String] = [] var loader_source := _read_text(STREAMING_WORLD_LOADER_PATH, failures) var private_renderer_symbols := _extract_private_renderer_symbols(loader_source, failures) _verify_synthetic_detection(private_renderer_symbols, failures) var gameplay_paths := _collect_gdscript_paths(GAMEPLAY_ROOT) var editor_source_paths := _discover_editor_source_paths(failures) var consumer_paths_by_path: Dictionary = {} for gameplay_path in gameplay_paths: consumer_paths_by_path[gameplay_path] = true for editor_source_path in editor_source_paths: consumer_paths_by_path[editor_source_path] = true for renderer_diagnostic_path in RENDERER_DIAGNOSTIC_PATHS: consumer_paths_by_path[renderer_diagnostic_path] = true for consumer_path_variant in consumer_paths_by_path: var consumer_path := String(consumer_path_variant) var consumer_source := _read_text(consumer_path, failures) for forbidden_symbol in _find_forbidden_symbols(consumer_source, private_renderer_symbols): failures.append("%s accesses private renderer symbol %s" % [consumer_path, forbidden_symbol]) if not failures.is_empty(): for failure in failures: push_error("RENDERER_INTERNAL_ACCESS: %s" % failure) quit(1) return print("RENDERER_INTERNAL_ACCESS PASS private_symbols=%d gameplay=%d editor_sources=%d renderer_tools=%d" % [ private_renderer_symbols.size(), gameplay_paths.size(), editor_source_paths.size(), RENDERER_DIAGNOSTIC_PATHS.size(), ]) quit(0) func _extract_private_renderer_symbols(loader_source: String, failures: Array[String]) -> Array[String]: var declaration_pattern := RegEx.new() var compile_error := declaration_pattern.compile( "(?m)^var\\s+(_[A-Za-z0-9_]*(?:queue|tasks|cache|states)[A-Za-z0-9_]*)" ) if compile_error != OK: failures.append("cannot compile private renderer symbol pattern") return [] var symbols_by_name: Dictionary = {} for regex_match in declaration_pattern.search_all(loader_source): symbols_by_name[regex_match.get_string(1)] = true var symbols: Array[String] = [] for symbol_variant in symbols_by_name: symbols.append(String(symbol_variant)) symbols.sort() if symbols.is_empty(): failures.append("streamer private symbol inventory is empty") return symbols func _discover_editor_source_paths(failures: Array[String]) -> Array[String]: var all_source_paths: Array[String] = [] for source_root in SOURCE_ROOTS: all_source_paths.append_array(_collect_gdscript_paths(source_root)) var editor_roots_by_path: Dictionary = {} var editor_source_paths_by_path: Dictionary = {} for source_path in all_source_paths: var source := _read_text(source_path, failures) if source_path.contains("/editor/"): editor_source_paths_by_path[source_path] = true if source.contains("extends " + "EditorPlugin") or source_path.ends_with("/plugin.gd"): editor_roots_by_path[source_path.get_base_dir()] = true for source_path in all_source_paths: for editor_root_variant in editor_roots_by_path: var editor_root := String(editor_root_variant) if source_path.begins_with(editor_root + "/"): editor_source_paths_by_path[source_path] = true var editor_source_paths: Array[String] = [] for editor_source_path_variant in editor_source_paths_by_path: editor_source_paths.append(String(editor_source_path_variant)) editor_source_paths.sort() return editor_source_paths func _collect_gdscript_paths(root_path: String) -> Array[String]: var paths: Array[String] = [] var directory := DirAccess.open(root_path) if directory == null: return paths directory.list_dir_begin() var entry_name := directory.get_next() while not entry_name.is_empty(): if entry_name.begins_with(".") or entry_name == "reference": entry_name = directory.get_next() continue var entry_path := root_path.path_join(entry_name) if directory.current_is_dir(): paths.append_array(_collect_gdscript_paths(entry_path)) elif entry_name.ends_with(".gd"): paths.append(entry_path) entry_name = directory.get_next() directory.list_dir_end() paths.sort() return paths func _find_forbidden_symbols(source: String, private_renderer_symbols: Array[String]) -> Array[String]: var found_symbols: Array[String] = [] for private_renderer_symbol in private_renderer_symbols: if _contains_external_symbol_access(source, private_renderer_symbol): found_symbols.append(private_renderer_symbol) return found_symbols func _contains_external_symbol_access(source: String, private_renderer_symbol: String) -> bool: for access_text in [ "." + private_renderer_symbol, '.get("%s"' % private_renderer_symbol, ".get('%s'" % private_renderer_symbol, '.set("%s"' % private_renderer_symbol, ".set('%s'" % private_renderer_symbol, '.call("%s"' % private_renderer_symbol, ".call('%s'" % private_renderer_symbol, '["%s"]' % private_renderer_symbol, "['%s']" % private_renderer_symbol, ]: if source.contains(access_text): return true return false func _verify_synthetic_detection(private_renderer_symbols: Array[String], failures: Array[String]) -> void: if not private_renderer_symbols.has("_tile_states"): failures.append("streamer inventory does not contain _tile_states fixture") return var forbidden_fixture := 'var tile_states = world.get("_tile_states")' var detected_symbols := _find_forbidden_symbols(forbidden_fixture, private_renderer_symbols) if detected_symbols != ["_tile_states"]: failures.append("synthetic private access was not detected exactly") var direct_member_fixture := "var tile_states = world._tile_states" if _find_forbidden_symbols(direct_member_fixture, private_renderer_symbols) != ["_tile_states"]: failures.append("synthetic direct member access was not detected exactly") var unrelated_owner_fixture := "var _tile_states: Dictionary = {}" if not _find_forbidden_symbols(unrelated_owner_fixture, private_renderer_symbols).is_empty(): failures.append("unrelated private declaration was rejected") var safe_fixture := "var metrics = render_facade.renderer_metrics_snapshot()" if not _find_forbidden_symbols(safe_fixture, private_renderer_symbols).is_empty(): failures.append("facade metrics fixture was rejected") func _read_text(path: String, failures: Array[String]) -> String: var file := FileAccess.open(path, FileAccess.READ) if file == null: failures.append("cannot open %s" % path) return "" return file.get_as_text()