# p9_test —— P9:小地图 + 昼夜 + 天气 + 传送 headless 自检。 # godot --headless --path project --script p9_test.gd extends SceneTree const Minimap = preload("res://ui/minimap.gd") const WorldTime = preload("res://world/world_time.gd") const Weather = preload("res://fx/weather.gd") class FakeClient extends Node: signal time_changed(server_epoch: int) signal channel_changed(channel: int) signal npc_marks_changed() signal land_areas_changed() signal observer_event(kind: int, vid: int, pos: Vector2) signal world_markers_changed() signal warp(pos: Vector3, same_server: bool) var _time := 0 var entities := [] var npc_marks := [] var markers := [] var observers := [] var land_areas := [] var party := [] func get_server_time() -> int: return _time func get_entities() -> Array: return entities func get_npc_marks() -> Array: return npc_marks func get_world_markers() -> Array: return markers func get_observers() -> Array: return observers func get_land_areas() -> Array: return land_areas func get_party() -> Array: return party func get_channel() -> int: return 3 var _fail := 0 func _ck(c: bool, m: String) -> void: if not c: _fail += 1 printerr("FAIL: " + m) func _init() -> void: _run() if _fail == 0: print("PASS: p9_test (minimap + world_time + weather + warp)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _run() -> void: var canvas := CanvasLayer.new() get_root().add_child(canvas) var fc := FakeClient.new() get_root().add_child(fc) var player := Node3D.new() player.position = Vector3.ZERO get_root().add_child(player) # --- 小地图 --- var mm: Node = Minimap.new() get_root().add_child(mm) mm.setup(fc, canvas, func() -> Node3D: return player) _ck(mm._view != null, "minimap: view built") fc.channel_changed.emit(7) _ck(mm._ch_label.text == "CH 7", "minimap: channel label") # _to_map: 北(−z 100m)应在圆心正上方附近;夹到半径内 var north: Vector2 = mm._to_map(Vector3(0, 0, -1000), Vector3.ZERO) _ck(north.x == mm.RADIUS and north.y < mm.RADIUS, "minimap: north maps up, clamped") var east: Vector2 = mm._to_map(Vector3(10, 0, 0), Vector3.ZERO) _ck(east.x > mm.RADIUS and abs(east.y - mm.RADIUS) < 0.01, "minimap: east maps right") var base_scale: float = mm.get_scale() mm.set_scale(base_scale * 2.0) var zoomed_east: Vector2 = mm._to_map(Vector3(10, 0, 0), Vector3.ZERO) _ck(mm.get_scale() > base_scale and zoomed_east.x > east.x, "minimap: scale zooms world projection") var wheel_scale: float = mm.get_scale() var wheel := InputEventMouseButton.new() wheel.button_index = MOUSE_BUTTON_WHEEL_DOWN wheel.pressed = true mm._on_gui_input(wheel) _ck(mm.get_scale() < wheel_scale, "minimap: wheel down zooms out") fc.entities = [{"vid": 11, "is_main": false, "ch_type": 0, "pos": Vector3(5, 0, 5)}] fc.party = [{"vid": 11, "leader": true}] fc.npc_marks = [{"type": 2, "name": "Gate", "pos": Vector3(3, 0, 3)}] fc.markers = [{"id": 1, "name": "Quest", "pos": Vector3(-4, 0, -4)}] fc.observers = [{"vid": 9001, "pos": Vector3(2, 0, -2)}] fc.land_areas = [{"id": 42, "guild_id": 77, "x": -200, "y": -200, "width": 400, "height": 400}] mm._view.queue_redraw() await process_frame _ck(mm._view.is_visible_in_tree(), "minimap: redraw scheduled, view live") # --- 昼夜 --- var sun := DirectionalLight3D.new() get_root().add_child(sun) var env := Environment.new() env.background_mode = Environment.BG_COLOR var wt: Node = WorldTime.new() get_root().add_child(wt) wt.setup(fc, sun, env) # 正午:2025-01-01 12:00:00 UTC = 1735732800 fc._time = 1735732800 fc.time_changed.emit(1735732800) _ck(abs(wt.day_fraction() - 0.5) < 0.01, "world_time: noon -> day_fraction ~0.5") wt._process(0.016) var noon_energy: float = sun.light_energy _ck(noon_energy > 0.9, "world_time: noon sun bright (%.2f)" % noon_energy) # 午夜 fc.time_changed.emit(1735732800 - 43200) _ck(abs(wt.day_fraction()) < 0.01 or abs(wt.day_fraction() - 1.0) < 0.01, "world_time: midnight -> fraction ~0") wt._process(0.016) _ck(sun.light_energy < 0.2, "world_time: midnight sun dark (%.3f)" % sun.light_energy) # --- 天气 --- var cam := Camera3D.new() get_root().add_child(cam) var w: Node3D = Weather.new() get_root().add_child(w) w.setup(cam) _ck(w.kind() == "none" and not w._p.emitting, "weather: starts off") w.set_weather("snow") _ck(w._p.emitting and w.kind() == "snow", "weather: snow on") var g_snow: Vector3 = w._p.process_material.gravity w.set_weather("rain") var g_rain: Vector3 = w._p.process_material.gravity _ck(g_rain.y < g_snow.y, "weather: rain falls faster than snow") w.set_weather("none") _ck(not w._p.emitting, "weather: off again") # --- 传送信号(同服)--- var got := [] fc.warp.connect(func(pos, same): got.append([pos, same])) fc.warp.emit(Vector3(50, 0, -30), true) _ck(got.size() == 1 and got[0][1] == true, "warp: same-server signal received")