extends SceneTree ## Converts the heavy baked ADT cache into a lightweight runtime streaming cache. ## ## Usage: ## godot --headless --path --script res://src/tools/build_adt_streaming_cache.gd -- \ ## --map Azeroth --input res://data/cache/baked_terrain_v2 --output res://data/cache/baked_terrain_stream_v1 --force const BAKED_TILE_SCRIPT := preload("res://src/resources/baked_adt_tile.gd") const STREAMING_TILE_SCRIPT := preload("res://src/resources/streaming_adt_tile.gd") func _initialize() -> void: var args := OS.get_cmdline_user_args() var map_name := _arg(args, "--map", "Azeroth") var input_dir := _res(_arg(args, "--input", "res://data/cache/baked_terrain_v2")) var output_dir := _res(_arg(args, "--output", "res://data/cache/baked_terrain_stream_v1")) var force := args.has("--force") var in_map_dir := input_dir.path_join(map_name) var out_map_dir := output_dir.path_join(map_name) var in_map_abs := ProjectSettings.globalize_path(in_map_dir) var out_map_abs := ProjectSettings.globalize_path(out_map_dir) if not DirAccess.dir_exists_absolute(in_map_abs): push_error("Input baked terrain cache not found: %s" % in_map_dir) quit(1) return DirAccess.make_dir_recursive_absolute(out_map_abs) var dir := DirAccess.open(in_map_dir) if dir == null: push_error("Cannot open input cache dir: %s" % in_map_dir) quit(1) return var files := dir.get_files() files.sort() var converted := 0 var skipped := 0 var failed := 0 var started_ms := Time.get_ticks_msec() for file_name in files: if not file_name.ends_with(".res"): continue var in_path := in_map_dir.path_join(file_name) var out_path := out_map_dir.path_join(file_name) if not force and ResourceLoader.exists(out_path): skipped += 1 continue var baked: Resource = load(in_path) if baked == null or baked.get_script() != BAKED_TILE_SCRIPT: push_warning("Invalid baked tile: %s" % in_path) failed += 1 continue var stream_tile: Resource = STREAMING_TILE_SCRIPT.new() stream_tile.set("format_version", STREAMING_TILE_SCRIPT.FORMAT_VERSION) stream_tile.set("map_name", str(baked.get("map_name"))) stream_tile.set("tile_x", int(baked.get("tile_x"))) stream_tile.set("tile_y", int(baked.get("tile_y"))) stream_tile.set("tile_origin", baked.get("tile_origin")) stream_tile.set("texture_size", int(baked.get("coarse_texture_size"))) stream_tile.set("wmo_names", baked.get("wmo_names")) stream_tile.set("wmo_placements", baked.get("wmo_placements")) stream_tile.set("m2_names", baked.get("m2_names")) stream_tile.set("m2_placements", baked.get("m2_placements")) stream_tile.set("terrain_mesh", baked.get("coarse_mesh")) var err := ResourceSaver.save(stream_tile, out_path) if err != OK: push_warning("Failed to save streaming tile %s (err=%d)" % [out_path, err]) failed += 1 continue converted += 1 if converted % 25 == 0: print("Converted %d tiles..." % converted) var elapsed_ms := Time.get_ticks_msec() - started_ms print("Streaming cache finished. converted=%d skipped=%d failed=%d elapsed=%.2fs" % [ converted, skipped, failed, float(elapsed_ms) / 1000.0 ]) quit(0 if failed == 0 else 2) func _arg(args: PackedStringArray, name: String, default: String) -> String: var idx := args.find(name) if idx >= 0 and idx + 1 < args.size(): return args[idx + 1] return default func _res(path: String) -> String: if path.begins_with("res://") or path.begins_with("user://"): return path return "res://" + path.trim_prefix("./").trim_prefix("/")