Supersede the composited v001 Title artwork with the Owner-approved single-frame v002 master, align runtime text to its command plaques, and remove the extra background image from responsive composition.
135 lines
5.1 KiB
GDScript
135 lines
5.1 KiB
GDScript
extends SceneTree
|
|
|
|
const EntryShell = preload("res://entry/entry_shell.gd")
|
|
const SettingsStore = preload("res://entry/settings_store.gd")
|
|
|
|
const FIXTURES := [
|
|
{"width": 760, "height": 360, "locale": "zh_CN", "scale": 1.0},
|
|
{"width": 844, "height": 390, "locale": "en", "scale": 1.0},
|
|
{"width": 844, "height": 390, "locale": "zh_CN", "scale": 1.3},
|
|
{"width": 1280, "height": 720, "locale": "en", "scale": 1.3},
|
|
]
|
|
const STATES := ["boot", "setup", "title", "settings", "credits"]
|
|
|
|
var failures: Array[String] = []
|
|
var output_root := ""
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
output_root = OS.get_environment("ABG_EVIDENCE_DIR")
|
|
if output_root.is_empty():
|
|
output_root = "/tmp/abg-dev1-entry-captures"
|
|
DirAccess.make_dir_recursive_absolute(output_root)
|
|
var count := 0
|
|
for fixture in FIXTURES:
|
|
for state in STATES:
|
|
await capture_fixture(fixture, state)
|
|
count += 1
|
|
if failures.is_empty():
|
|
print("ABG_DEV1_ENTRY_CAPTURE_OK frames=%d viewports=760x360,844x390,1280x720 locales=zh_CN,en text=100,130 states=boot,setup,title,settings,credits renderer=normal" % count)
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func capture_fixture(fixture: Dictionary, state: String) -> void:
|
|
var viewport := SubViewport.new()
|
|
viewport.size = Vector2i(int(fixture.width), int(fixture.height))
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
root.add_child(viewport)
|
|
var shell = EntryShell.new()
|
|
shell.auto_start = false
|
|
viewport.add_child(shell)
|
|
await _frames(3)
|
|
shell.settings = SettingsStore.new().defaults()
|
|
shell.settings.setup_completed = true
|
|
shell.settings.locale = String(fixture.locale)
|
|
shell.settings.text_scale = float(fixture.scale)
|
|
shell.setup_draft = shell.settings.duplicate(true)
|
|
match state:
|
|
"boot":
|
|
shell.boot_snapshot = shell.boot_service.begin()
|
|
shell._render_boot_state()
|
|
"setup":
|
|
shell.settings.setup_completed = false
|
|
shell.show_first_launch()
|
|
"title": shell.show_title()
|
|
"settings": shell.show_settings("display")
|
|
"credits": shell.show_credits()
|
|
await _frames(6)
|
|
verify_controls_inside(shell, fixture, state)
|
|
if state == "title":
|
|
verify_title_master(shell, fixture)
|
|
await RenderingServer.frame_post_draw
|
|
var image := viewport.get_texture().get_image()
|
|
var name := "%s-%dx%d-%s-%d.png" % [state, int(fixture.width), int(fixture.height), String(fixture.locale), int(round(float(fixture.scale) * 100.0))]
|
|
var error := image.save_png(output_root.path_join(name))
|
|
if error != OK:
|
|
failures.append("capture %s failed: %s" % [name, error])
|
|
viewport.queue_free()
|
|
await _frames(4)
|
|
|
|
|
|
func verify_title_master(shell: Control, fixture: Dictionary) -> void:
|
|
var world := shell.find_child("TitleMasterWorldExtension", true, false) as Control
|
|
var canvas := shell.find_child("TitleSafeArea", true, false) as Control
|
|
var composite := shell.find_child("TitleMasterComposite", true, false) as TextureRect
|
|
expect(world != null and canvas != null and composite != null, "Title approved composition layers exist")
|
|
if world == null or canvas == null or composite == null:
|
|
return
|
|
expect(is_equal_approx(canvas.size.x / canvas.size.y, 16.0 / 9.0), "Title master remains undistorted")
|
|
expect(composite.get_global_rect().is_equal_approx(canvas.get_global_rect()), "Title art, text and controls share the coordinate master")
|
|
expect(shell.find_child("TitleNewGame", true, false) != null and shell.find_child("TitleContinue", true, false) != null, "Title primary state controls exist")
|
|
expect(shell.find_child("TitleSettings", true, false) != null and shell.find_child("TitleCredits", true, false) != null, "Title utility controls exist")
|
|
if String(fixture.locale) == "zh_CN":
|
|
expect(shell.find_child("TitleIdentity", true, false).text == "裂脉远征团", "Title Chinese identity is engine-rendered")
|
|
|
|
|
|
func verify_controls_inside(shell: Control, fixture: Dictionary, state: String) -> void:
|
|
var bounds := Rect2(Vector2.ZERO, Vector2(float(fixture.width), float(fixture.height)))
|
|
for node in _all_controls(shell):
|
|
if not node.visible or node is TextureRect or node is ColorRect or node is Container or _inside_scroll(node):
|
|
continue
|
|
var rect := node.get_global_rect()
|
|
if rect.size.x <= 0.0 or rect.size.y <= 0.0:
|
|
continue
|
|
if not bounds.encloses(rect):
|
|
failures.append("%s %dx%d %s outside bounds: %s" % [state, int(fixture.width), int(fixture.height), node.name, rect])
|
|
|
|
|
|
func _inside_scroll(control: Control) -> bool:
|
|
var parent := control.get_parent()
|
|
while parent != null:
|
|
if parent is ScrollContainer:
|
|
return true
|
|
parent = parent.get_parent()
|
|
return false
|
|
|
|
|
|
func _all_controls(root_control: Control) -> Array[Control]:
|
|
var result: Array[Control] = []
|
|
var pending: Array[Node] = [root_control]
|
|
while not pending.is_empty():
|
|
var node: Node = pending.pop_back()
|
|
if node is Control:
|
|
result.append(node)
|
|
for child in node.get_children():
|
|
pending.append(child)
|
|
return result
|
|
|
|
|
|
func _frames(count: int) -> void:
|
|
for frame in range(count):
|
|
await process_frame
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("DEV-1 capture: %s" % message)
|