extends Node ## 离线加载实际鬼木林/赤鬼木林地图,并把树怪放进生产 GameScene 的实体挂载点。 ## 服务器刷新、选中、战斗和掉落仍由 playable_live_test 负责。 const GameScene = preload("res://game_scene.gd") const Fixtures = preload("res://gamescene_test.gd") const MobView = preload("res://ui/mob_view.gd") const Config = preload("res://testing/playable_config.gd") const PlayableReport = preload("res://testing/playable_report.gd") var failures := 0 func _ready() -> void: call_deferred("run") func _fail(message: String) -> void: failures += 1 printerr("FOREST MAP FAIL: " + message) func run() -> void: var map_key := OS.get_environment("MT_FOREST_MAP") var config_path := OS.get_environment("MT_PLAYABLE_CONFIG") var loaded_config := Config.load_file(config_path) if not config_path.is_empty() else {"ok": false, "config": {}} if map_key.is_empty() and loaded_config.ok: map_key = String(loaded_config.config.get("map_key", "")) if map_key.is_empty(): map_key = "outdoortrent/metin2_map_trent" var race := int(OS.get_environment("MT_FOREST_MOB_RACE")) if not OS.get_environment("MT_FOREST_MOB_RACE").is_empty() else 2301 var output := OS.get_environment("MT_TEST_OUTPUT") if output.is_empty(): output = ProjectSettings.globalize_path("res://../build/rendering/forest-map-%d" % Time.get_unix_time_from_system()) DirAccess.make_dir_recursive_absolute(output) var playable_report := PlayableReport.new() playable_report.begin(OS.get_environment("MT_PLAYABLE_RUN_ID"), "playable", loaded_config.config if loaded_config.ok else {}) get_tree().root.size = Vector2i(1280, 720) print("FOREST MAP: loading %s" % map_key) var client := Fixtures.FakeClient.new() # Server-space values chosen inside the corresponding local map rectangle. # GameScene/MapCoord performs the actual base-position conversion. var base_x := 0.0 if map_key == "outdoortrent/metin2_map_trent" else 1049600.0 var server_x := base_x + 12800.0 var server_y := 12800.0 client.spawn(1000, "ForestRender", Vector3(server_x * 0.01, 0.0, -server_y * 0.01), true) var scene := GameScene.new() get_tree().root.add_child(scene) await scene.setup(client, AssetRoot.path(), map_key) print("FOREST MAP: GameScene setup complete") if not scene._map_loaded(): _fail("map did not load: %s" % map_key) if not scene._model_built or scene.player == null: _fail("local player model is not ready") var entities := scene.get_node_or_null("Entities") if entities == null: _fail("GameScene entity mount is missing") var positions := [Vector3(12.0, 0.0, 18.0), Vector3(15.0, 0.0, 21.0)] var monster := MobView.new() monster.name = "ForestTreeMonster_%d" % race if not monster.build(AssetRoot.path(), null, race): _fail("tree monster build failed race=%d" % race) else: entities.add_child(monster) monster.position = positions[0] monster.set_anim_state("wait") client.spawn(23001, "TreeMonster", Vector3(positions[0].x * 100.0, 0.0, -positions[0].z * 100.0)) await get_tree().process_frame if monster.model == null or monster.model.call("get_visual_aabb").size.length() <= 0.0: _fail("tree monster has no visible geometry") if scene.cam and scene.cam.has_method("snap_to_target"): scene.cam.snap_to_target() await get_tree().process_frame await get_tree().process_frame var image_name := "forest-map-%s.png" % map_key.get_file() if DisplayServer.get_name() != "headless": await RenderingServer.frame_post_draw if get_tree().root.get_texture().get_image().save_png(output.path_join(image_name)) != OK: _fail("map screenshot could not be saved") var report := {"passed": failures == 0, "failures": failures, "map": map_key, "tree_monster_race": race, "tree_monster_model": monster.model != null, "map_loaded": scene._map_loaded(), "screenshot": image_name if DisplayServer.get_name() != "headless" else "", "assets": AssetRoot.path(), "headless": DisplayServer.get_name() == "headless", "scope": "production GameScene map load plus offline tree-monster placement; no server spawn"} var file := FileAccess.open(output.path_join("report.json"), FileAccess.WRITE) if file: file.store_string(JSON.stringify(report, "\t")) file.close() var client_report_path := OS.get_environment("MT_TEST_REPORT") if not client_report_path.is_empty(): playable_report.add_case("MAP-FOREST-01", "PASS" if failures == 0 else "FAIL", "map=%s tree_monster_race=%d" % [map_key, race]) playable_report.write(client_report_path) print("FOREST MAP RENDER: ", JSON.stringify(report)) scene.queue_free() client.queue_free() await get_tree().process_frame get_tree().quit(1 if failures else 0)