|
4 | 4 |
|
5 | 5 | from typing import TYPE_CHECKING |
6 | 6 |
|
| 7 | +import time |
| 8 | +from pathlib import Path |
| 9 | + |
7 | 10 | from scenarios.geometry import ( |
8 | 11 | dropdown_option, |
9 | 12 | DIALOG, |
|
14 | 17 | PARK_PANEL, |
15 | 18 | TAB_X, |
16 | 19 | TAB_Y, |
| 20 | + TOOLBAR, |
17 | 21 | dialog_point, |
18 | 22 | editor_point, |
19 | 23 | panel_left, |
@@ -461,3 +465,86 @@ def settings_panel(run_state: E2ERun) -> None: |
461 | 465 | run_state.screenshot("specular-off") |
462 | 466 | run_state.click(*panel_point(left, MAP["settings_map_size"]), delay=0.9) |
463 | 467 | run_state.screenshot_root("specular-on-root") |
| 468 | + |
| 469 | + |
| 470 | +def _sweep(run_state: E2ERun, left: int, width: int, height: int) -> None: |
| 471 | + """One held stroke across the map, so the whole surface is covered rather |
| 472 | + than a patch. The map fills the screen at the default zoom, so no zooming is |
| 473 | + needed; the sweep stays inside the map (its edges are sky).""" |
| 474 | + y = height // 2 |
| 475 | + run_state.press(width // 3, y) |
| 476 | + run_state.move(left - 200, y, delay=0.4) |
| 477 | + run_state.release(left - 200, y) |
| 478 | + |
| 479 | + |
| 480 | +def _wait_for_archive(run_state: E2ERun, stem: str, timeout_s: float = 20.0) -> Path | None: |
| 481 | + """Poll the write dir for the compiled `.sdz`. The archive is built off the |
| 482 | + draw thread, so it lands a little after the export command is logged.""" |
| 483 | + assert run_state.write_dir is not None |
| 484 | + deadline = time.monotonic() + timeout_s |
| 485 | + while time.monotonic() < deadline: |
| 486 | + matches = [p for p in run_state.write_dir.rglob(f"{stem}*.sdz")] |
| 487 | + if matches: |
| 488 | + return matches[0] |
| 489 | + time.sleep(0.3) |
| 490 | + return None |
| 491 | + |
| 492 | + |
| 493 | +@scenario() |
| 494 | +def map_export(run_state: E2ERun) -> None: |
| 495 | + """The whole map pipeline: save a project, sculpt and paint the map, then |
| 496 | + compile it to a Spring archive. |
| 497 | +
|
| 498 | + Save As establishes a project (Export needs its path); a Terrain/Add sweep |
| 499 | + reshapes the ground across the whole map, a texture sweep paints it, Ctrl+S |
| 500 | + saves, and Export -> Spring archive runs the bundled compiler. Asserts the |
| 501 | + sculpt/paint/export commands and that the compiled `.sdz` lands on disk. |
| 502 | + Deliberately fast -- the point is the pipeline runs end to end. |
| 503 | + """ |
| 504 | + run_state.focus() |
| 505 | + left = panel_left(run_state) |
| 506 | + width, height = window_size(run_state) |
| 507 | + |
| 508 | + # A project first: Export compiles the *saved* project, so it needs a path. |
| 509 | + # Save As creates it and reloads into it (the one unavoidable wait). |
| 510 | + run_state.click(*panel_point(left, TOOLBAR["save_as"]), delay=0.6) |
| 511 | + run_state.click(*dialog_point(run_state, DIALOG["file_name"]), delay=0.15) |
| 512 | + run_state.type_text("ExportMap") |
| 513 | + run_state.key("Return", delay=0.15) |
| 514 | + # The one unavoidable wait: Save As restarts the engine into the new project. |
| 515 | + run_state.click(*dialog_point(run_state, DIALOG["file_ok_name"]), delay=8.0) |
| 516 | + |
| 517 | + # Terrain: pick a pattern, arm Add, a fat brush, one sweep across the map. |
| 518 | + run_state.click(left + TAB_X["map"], TAB_Y, delay=0.15) |
| 519 | + run_state.click(*editor_point(left, "map", "terrain"), delay=0.3) |
| 520 | + run_state.click(*panel_point(left, MAP["terrain_pattern"]), delay=0.15) |
| 521 | + run_state.click(*panel_point(left, MAP_ACTIONS["terrain_add"]), delay=0.15) |
| 522 | + click_field(run_state, left, MAP["terrain_size"], "1200") |
| 523 | + click_field(run_state, left, MAP["terrain_height"], "80") |
| 524 | + _sweep(run_state, left, width, height) |
| 525 | + run_state.assert_command_at_least("TerrainShapeModifyCommand", 1) |
| 526 | + |
| 527 | + # Texture: choose a material, pick a brush shape, paint across the map. |
| 528 | + run_state.click(*editor_point(left, "map", "texture"), delay=0.3) |
| 529 | + run_state.click(*panel_point(left, MAP["saved_brush_add"]), delay=0.4) |
| 530 | + run_state.click(*dialog_point(run_state, DIALOG["asset_core_cell"]), delay=0.3) |
| 531 | + run_state.click(*panel_point(left, MAP["saved_brush_rect"]), delay=0.15) |
| 532 | + run_state.click(*panel_point(left, MAP_ACTIONS["texture_paint"]), delay=0.15) |
| 533 | + _sweep(run_state, left, width, height) |
| 534 | + run_state.assert_any_command("TerrainChangeTextureCommand", paintMode="paint") |
| 535 | + |
| 536 | + # Save the edits, then Export -> Spring archive (the default type). |
| 537 | + run_state.key("ctrl+s", delay=0.5) |
| 538 | + run_state.assert_command_at_least("SaveCommand", 1) |
| 539 | + run_state.click(*panel_point(left, TOOLBAR["export"]), delay=0.3) |
| 540 | + run_state.click(*dialog_point(run_state, DIALOG["file_name"]), delay=0.15) |
| 541 | + run_state.type_text("ExportMap") |
| 542 | + run_state.key("Return", delay=0.15) |
| 543 | + run_state.click(*dialog_point(run_state, DIALOG["file_ok_export"]), delay=0.3) |
| 544 | + run_state.assert_command("ExportSpringArchiveCommand") |
| 545 | + |
| 546 | + archive = _wait_for_archive(run_state, "ExportMap") |
| 547 | + if archive is None: |
| 548 | + raise AssertionError("export did not produce a .sdz archive") |
| 549 | + if archive.stat().st_size < 1024: |
| 550 | + raise AssertionError(f"compiled archive is suspiciously small: {archive}") |
0 commit comments