extends Node # Забег Parkour «по существу»: настоящая карта, игрок, сервер (запускает parkour_run_test.py). # Старт-линия -> таймер идёт, смерть его не останавливает, финиш у вершины, слишком быстрое время сервер не принимает, # R перезапускает забег, нормальное время (старт сдвинут на 45 с назад — иначе пришлось бы бежать ~минуту) попадает в рейтинг. var ok := true var level var p func check(cond: bool, text: String) -> void: print((" ДА " if cond else " НЕТ ") + text) if not cond: ok = false func wait(s: float) -> void: await get_tree().create_timer(s).timeout func _ready() -> void: _run.call_deferred() func press_r() -> void: var ev := InputEventKey.new() ev.physical_keycode = KEY_R ev.keycode = KEY_R ev.pressed = true Input.parse_input_event(ev) await get_tree().process_frame ev = ev.duplicate() ev.pressed = false Input.parse_input_event(ev) func _run() -> void: level = (load("res://maps/parkour/parkour.tscn") as PackedScene).instantiate() add_child(level) await wait(0.5) p = get_tree().get_first_node_in_group("local_player") check(await _wait_ready(), "подключились к серверу, вошли в комнату parkour") check(not level.run_active and not level.run_done, "до линии таймер не идёт") await wait(1.0) check(not level.run_active, "стоим на старте — таймер не идёт") p.global_position = Vector3(0, 1.25, -11.0) p.velocity = Vector3.ZERO p.rotation.y = 0.0 await wait(0.3) Input.action_press("move_forward") Input.action_press("sprint") var t0 := Time.get_ticks_msec() while not level.run_active and Time.get_ticks_msec() - t0 < 4000: await get_tree().physics_frame Input.action_release("move_forward") Input.action_release("sprint") check(level.run_active and p.global_position.z < level.START_LINE_Z + 1.0, "пересекли линию z=-14 -> таймер пошёл (z=%.1f)" % p.global_position.z) await wait(1.2) var e1: float = level.run_elapsed() check(e1 > 1.0 and level._timer_label.text != "00:00.000", "таймер считает: %s" % level._timer_label.text) p.die() await wait(3.2) check(level.run_active and not p.is_dead and level.run_elapsed() > e1 + 2.5, "смерть и возрождение таймер не останавливают (%.1f с)" % level.run_elapsed()) # слишком быстрый финиш: таймер остановится, сервер время не примет var D = level.Data p.global_position = D.PORTAL + Vector3(0, 1.4, 3.0) p.velocity = Vector3.ZERO await wait(1.0) check(level.run_done and not level.run_active and level._results_panel.visible, "у вершины финиш: таймер встал на %s, показаны итоги" % level._timer_label.text) await wait(0.8) check(not Net.last_record.has("parkour"), "время %.1f с короче допустимого сервер отверг (ответа нет)" % level.run_time) var n_before: int = Net.boards["parkour"].top.size() if Net.boards.has("parkour") else 0 # R: заново await press_r() await wait(0.4) check(not level.run_active and not level.run_done and level._timer_label.text == "00:00.000" and p.global_position.distance_to(D.START) < 1.0, "R: телепорт на старт, таймер сброшен") # второй забег: линия, затем «состарим» старт на 45 с и финишируем p.global_position = Vector3(0, 1.25, -11.0) p.velocity = Vector3.ZERO await wait(0.3) Input.action_press("move_forward") Input.action_press("sprint") t0 = Time.get_ticks_msec() while not level.run_active and Time.get_ticks_msec() - t0 < 4000: await get_tree().physics_frame Input.action_release("move_forward") Input.action_release("sprint") check(level.run_active, "после R линия снова запускает таймер") level.run_start_tick -= 45000 p.global_position = D.PORTAL + Vector3(0, 1.4, 3.0) p.velocity = Vector3.ZERO await wait(1.5) var rec = Net.last_record.get("parkour") check(rec != null and absf(rec.time - level.run_time) < 0.01 and rec.rank >= 1 and rec.personal, "сервер принял %.2f с: %s" % [level.run_time, str(rec)]) var b = Net.boards.get("parkour") check(b != null and b.my_rank >= 1 and absf(b.my_time - level.run_time) < 0.01, "запись в рейтинге Parkour: место %s, время %.2f" % [str(b.my_rank) if b else "?", b.my_time if b else 0.0]) check(level._results_panel.visible, "панель итогов с рейтингом показана") await wait(8.5) check(not level._results_panel.visible, "итоги скрылись через ~8 с, дальше свободная игра") print("\nПАРКУР ПРОЙДЕН" if ok else "\nПАРКУР ПРОВАЛЕН") get_tree().quit(0 if ok else 1) func _wait_ready() -> bool: var t := 0.0 while not (Net.connected and Net.map_ready): await wait(0.1) t += 0.1 if t > 8.0: return false return true