111 lines
5.8 KiB
GDScript
111 lines
5.8 KiB
GDScript
extends SceneTree
|
|
const Readiness = preload("res://entry/views/readiness_page_view.gd")
|
|
const InkCheck = preload("res://tools/ui_ink_check.gd")
|
|
# Single authoritative size (owner policy).
|
|
const SIZES := [Vector2i(1280, 720)]
|
|
const LOCALES := ["zh_CN", "en"]
|
|
var ink_scanned := 0
|
|
var ink_violations: Array = []
|
|
func _initialize() -> void: call_deferred("_run")
|
|
func _run() -> void:
|
|
var out := OS.get_environment("ABG_EVIDENCE_DIR")
|
|
if out.is_empty(): quit(1); return
|
|
DirAccess.make_dir_recursive_absolute(out)
|
|
var ink_self := InkCheck.self_test(root)
|
|
if ink_self.size() < 3:
|
|
push_error("M62 ink self-test expected at least 3 violations, got %d" % ink_self.size())
|
|
quit(1)
|
|
return
|
|
print("ABG_M62_INK_SELF_TEST_OK violations=%d" % ink_self.size())
|
|
ink_scanned = 0
|
|
ink_violations = []
|
|
for size in SIZES:
|
|
for locale in LOCALES:
|
|
for mode in ["static", "dynamic", "final"]:
|
|
await _capture(Readiness, _readiness_data(locale), size, locale, "readiness", out, mode)
|
|
var report_path := OS.get_environment("ABG_EVIDENCE_DIR").path_join("ink-violations-%s.json" % _probe_id())
|
|
var file := FileAccess.open(report_path, FileAccess.WRITE)
|
|
if file != null:
|
|
file.store_string(JSON.stringify(ink_violations, " "))
|
|
file.close()
|
|
if ink_violations.is_empty():
|
|
print("ABG_M55_READINESS_INK_OK scanned=%d violations=0" % ink_scanned)
|
|
else:
|
|
for violation in ink_violations:
|
|
push_error("M55 ink violation %s %s %s %s: %s" % [
|
|
violation.get("node", "?"), violation.get("locale", "?"),
|
|
violation.get("fixture", "?"), violation.get("kind", "?"),
|
|
violation.get("detail", ""),
|
|
])
|
|
print("ABG_M55_READINESS_INK_FAIL scanned=%d violations=%d" % [ink_scanned, ink_violations.size()])
|
|
quit(1)
|
|
return
|
|
print("ABG_M55_READINESS_VISUAL_PROBE_OK sizes=1 locales=2 pages=readiness scans=%d strict_result=m67" % ink_scanned)
|
|
quit(0)
|
|
|
|
func _probe_id() -> String:
|
|
return "m55-readiness-result"
|
|
|
|
|
|
func _scan_ink(view: Control, locale: String, label: String) -> void:
|
|
# Legacy-chrome pages (pre-M62) record their ink defects as a baseline for
|
|
# the W5 migration; migrated pages (Market, Readiness once moved) must be
|
|
# strict. The report file is the machine-readable work list.
|
|
var violations := InkCheck.scan(view)
|
|
ink_scanned += 1
|
|
for violation in violations:
|
|
violation["locale"] = locale
|
|
violation["fixture"] = label
|
|
ink_violations.append(violation)
|
|
|
|
func _capture(script: Script, data: Dictionary, size: Vector2i, locale: String, page: String, out: String, mode := "final") -> void:
|
|
var viewport := SubViewport.new(); viewport.size = size; viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS; root.add_child(viewport)
|
|
var view: Control = script.new(); view.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT); view.configure_presentation({"safe_area":24,"text_scale":1.0,"locale":locale}); viewport.add_child(view); view.render(data)
|
|
if mode != "final": _apply_capture_mode(view, mode)
|
|
for _i in range(3): await process_frame
|
|
_scan_ink(view, locale, "%s-%dx%d-%s" % [page, size.x, size.y, mode])
|
|
var image := viewport.get_texture().get_image(); if image != null: image.save_png(out.path_join("%s-%dx%d-%s-%s.png" % [page,size.x,size.y,locale,mode]))
|
|
view.queue_free(); viewport.queue_free(); await process_frame
|
|
func _apply_capture_mode(view: Control, mode: String) -> void:
|
|
# Contract views: static-only is the authored master with no runtime
|
|
# content; dynamic-only is the runtime content on a neutral field, which is
|
|
# where slot overflow, contrast and alignment defects are visible. This
|
|
# lives in the probe so product code carries no test-only switches.
|
|
var overlay := view.find_child("ReadinessMasterOverlay", true, false)
|
|
var master := view.find_child("ReadinessStaticMaster", true, false)
|
|
var matte := view.find_child("ReadinessMasterMatte", true, false)
|
|
if mode == "static":
|
|
if overlay != null: overlay.visible = false
|
|
return
|
|
if matte != null: matte.visible = false
|
|
if master != null: master.visible = false
|
|
if master != null and master.get_parent() != null:
|
|
var neutral := ColorRect.new()
|
|
neutral.name = "CaptureNeutralField"
|
|
neutral.color = Color("#5b6165")
|
|
neutral.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
neutral.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
master.get_parent().add_child(neutral)
|
|
master.get_parent().move_child(neutral, 0)
|
|
func _readiness_data(locale: String) -> Dictionary:
|
|
# Real profession and localized-name data: the probe must exercise four
|
|
# distinct members, not four copies of the fallback art. Empty-data probes
|
|
# cannot validate the party layout.
|
|
var professions := ["PF-B01", "PF-B05", "PF-B07", "PF-B03"]
|
|
var zh_names := ["阿里", "布兰", "塞拉", "戴恩"]
|
|
var en_names := ["Ari", "Bram", "Cera", "Dain"]
|
|
var rows: Array = []
|
|
for i in range(4):
|
|
rows.append({
|
|
"position": i,
|
|
"recruit_id": "r-%d" % (i + 1),
|
|
"recruit": {
|
|
"recruit_id": "r-%d" % (i + 1),
|
|
"profession_id": professions[i],
|
|
"rendered_name_snapshot": {"zh_CN": zh_names[i], "en": en_names[i]},
|
|
},
|
|
})
|
|
return {"ok":true,"locale":locale,"company":{"owned_count":4,"line_capacity":4},"contract":{"difficulty":"stormbound","line_capacity":4},"formation":{"coverage":{"protection":2,"long_reach":2,"control":1}},"order":{"front_recruit":rows[0].recruit,"ordered_recruits":rows},"warnings":{"rows":[{"text":"NO GUARD","severity":"warning","owner":"coverage"},{"text":"Outcome not guaranteed","severity":"notice","owner":"risk"},{"text":"Reserve: none","severity":"info","owner":"formation"}],"count":3},"commands":{"accept_enabled":true,"risk_enabled":false}}
|
|
func _result_data(locale: String) -> Dictionary:
|
|
return {"ok":true,"locale":locale,"result":{"outcome":"victory"},"economy":{"coin_before":24,"coin_after":38,"reward_coin":14,"xp_award":20,"xp_per_recruit":5},"knockouts":{"ids":[]},"decisive_event":{"caption_id":"first_hit"},"diagnosis":{"open":true},"commands":{"diagnosis_enabled":true,"continue_enabled":true}}
|