工程(bp对拍载体退役): 删 game/tests/bp_baseline_dump.gd+.uid 边车——迭代39批bp1断点对拍的一次性dump载体,断点片段化后七时点对拍已收口进审计报告(292dumps×28键零漂移),件核全仓零引用;实现报告§五退役清单件,随批后收尾扫尾批执行(用户令2026-10-28'一并全部处理掉');属文档面收尾的代码面尾巴,按车道铁律走worktree小批

This commit is contained in:
DKChan committed 2026-10-28 04:33:43 +08:00
1 parent fa7747e501
commit d26b5e68ee
2 files changed
-178

No files matched your search

-177
View File
@@ -1,177 +0,0 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# 断点基线对拍采集脚本(迭代 39 拆件批 T0 载体,批末随中间产物退役——非长期测试件)。
# 固定种子集驱动完整冒险至各停点(节点入口/选路/三选一在途/兑付后待推进),逐停点
# dump 断点 Dictionary 全键值(直调 _bp_parts 写侧取值面)→ JSON 落盘,供改前/改后
# 逐键逐位比对(bp1:同种子改前改后 27 键逐位一致)。
# 运行:BP_DUMP_OUT=<json 路径> godot --headless --path . --script res://tests/bp_baseline_dump.gd
# 缺省输出 user://bp_baseline_dump.json。
# 驱动与 sim/level_autoplay 同构(完美档战斗驱动 + 确定性选件/选路)——零随机流自开,
# 同种子逐位可复放;dump 时点由驱动循环状态判定,确定性时点。
extends SceneTree
const AdventureRunnerScript := preload("res://core/adventure_runner.gd")
const Autoplay := preload("res://sim/level_autoplay.gd")
const SEEDS: Array[int] = [1234, 4321, 910042, 20260101, 20260102, 20260103]
const PARAMS := {
"hero_override": {},
"treasure_unlocked": {"wide_scout_band": true},
"attunement": ["sky_eye", "incense_stick", "refresh_practice"], # 充能账非零形态+刷新存量加仓(attunement_charges/refresh_stock 键覆盖)
"attune_refresh_y": 2, # Y 池非零形态(attune_refresh_y 键覆盖)
"shop_mode": "pool", # 共享池货架面(shop_shelf/shop_visit_buys/shop_purchased 覆盖)
"relics_seed": ["twin_pick"], # 特性持有集+adventure_counters 非空形态(adv_twin_digs 计数器用户)
}
func _init() -> void:
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[bp_baseline_dump] FAIL — 数值表加载失败")
quit(1)
return
var runs: Array = []
for seed_val in SEEDS:
var run := _drive_dump_run(db, int(seed_val))
runs.append({"seed": int(seed_val), "result": String(run["result"]), "dumps": run["dumps"]})
print("[bp_baseline_dump] seed=%d result=%s dumps=%d" % [int(seed_val), String(run["result"]), (run["dumps"] as Array).size()])
var out_path := OS.get_environment("BP_DUMP_OUT")
if out_path.is_empty():
out_path = "user://bp_baseline_dump.json"
var f := FileAccess.open(out_path, FileAccess.WRITE)
if f == null:
print("[bp_baseline_dump] FAIL — 输出文件打不开: %s" % out_path)
quit(1)
return
f.store_string(JSON.stringify({"generated_by": "bp_baseline_dump", "seeds": SEEDS, "runs": runs}, " "))
f.close()
print("[bp_baseline_dump] DONE — %s" % out_path)
quit(0)
# 单局驱动+停点 dump(返回 {result, dumps};dumps 元素 = {seq, tag, level_index, node_id, bp})
func _drive_dump_run(db, seed_val: int) -> Dictionary:
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(seed_val)
var adr = AdventureRunnerScript.new(db, rng)
var ctx := {"result": "", "dumps": [] as Array, "seq": 0, "adr": adr, "db": db}
# 信号直连(拆件批 T3——转发族退役):runner 信号在 level_started 重取点重连(同关守卫恰一次);
# 停点件信号面订 stop()(每冒险一次)
adr.level_started.connect(_on_dump_level_started.bind(ctx))
adr.stop().curio_resolved.connect(_on_curio_resolved.bind(ctx))
if not adr.start_adventure(seed_val, PARAMS):
ctx["result"] = "start_failed"
return ctx
var guard := 2000
while String(ctx["result"]) == "" and guard > 0:
guard -= 1
if not (adr.stop()._node_pending as Dictionary).is_empty():
_dump(ctx, "node_curio_pending")
var ncands: Array = (adr.stop()._node_pending.get("candidates", []) as Array)
var npick: Dictionary = Autoplay._pick_token(ncands, "off")
if not adr.stop().apply_node_curio(String(npick.get("kind", "")), String(npick.get("tier", "")), String(npick.get("feat_id", ""))):
ctx["result"] = "node_advance_failed"
continue
if not (adr.stop()._pending as Dictionary).is_empty():
_dump(ctx, "curio_pending")
var cands: Array = (adr.stop()._pending.get("candidates", []) as Array)
var pick: Dictionary = Autoplay._pick_token(cands, "off")
if not adr.stop().pick_curio(String(pick.get("kind", "")), String(pick.get("tier", "")), String(pick.get("feat_id", ""))):
ctx["result"] = "advance_failed"
continue
if bool(adr._pending_next_level):
_dump(ctx, "resolved_wait_continue")
if not adr.continue_to_next_level():
ctx["result"] = "advance_failed"
continue
var runner = adr.runner()
if runner == null:
break # 冒险已收束或停点态未覆盖(防御)
if runner.awaiting_choice():
_dump(ctx, "route_choice")
var ids: Array = runner.next_candidate_ids()
if ids.is_empty():
ctx["result"] = "no_candidates"
break
if not runner.pick_next_node(int(ids[0])):
ctx["result"] = "route_failed"
continue
var settlement = runner.current_battle()
if settlement != null and String(settlement.battle_result) == "":
_drive_battle(ctx, runner, settlement)
continue
# 收束态分派:结算受理后(state=idle/settling)按 summary 定局;其余态无战无停点无选路 = 死循环防护
if String(ctx["result"]) == "":
var sum: Dictionary = adr.summary if adr.summary != null else {}
if not sum.is_empty():
ctx["result"] = String(sum.get("result", "settled"))
break
if String(adr.state) in ["idle", "settling"]:
ctx["result"] = "settled_no_summary"
break
if guard == 1:
ctx["result"] = "timeout"
return ctx
# 完美档战斗驱动(复用 sim 同款决策——上界策略;st 键集满足 _autoplay_battle 消费面)
func _drive_battle(ctx: Dictionary, runner, settlement) -> void:
var st := {"result": "", "rounds": 0, "refreshes": 0, "seal_placed": 0,
"policy": "perfect", "adv": false}
Autoplay._autoplay_battle(runner, settlement, st, null)
# 停点 dump(写侧取值面直调;_runner 为 null 的停点态节点域字段按缺省落档——与真机同构)
static func _dump(ctx: Dictionary, tag: String) -> void:
var adr = ctx["adr"]
var bp: Dictionary = adr._bp_parts()
var runner = adr.runner()
var dumps: Array = ctx["dumps"]
ctx["seq"] = int(ctx["seq"]) + 1
dumps.append({
"seq": int(ctx["seq"]),
"tag": String(tag),
"level_index": int(adr.level_index),
"node_id": int(runner.current_node_id()) if runner != null else -1,
"bp": bp,
})
# 每关开始(dump 直连面):重取 runner 重连 node_entered(同关守卫——level_started 每关恰一次发射)
static func _on_dump_level_started(_li: int, _dn: String, ctx: Dictionary) -> void:
var adr = ctx["adr"]
if String(ctx.get("wired_level", "")) == "%s|%d" % [str(adr.master_seed), int(adr.level_index)]:
return
ctx["wired_level"] = "%s|%d" % [str(adr.master_seed), int(adr.level_index)]
var r = adr.runner()
if r == null:
return
r.node_entered.connect(_on_node_entered.bind(ctx))
# 节点入口驱动(信号时点):入口 dump 覆盖节点域字段形态;rest/shop 直通继续,reward 呈现三选一
static func _on_node_entered(node: Dictionary, _info: Dictionary, ctx: Dictionary) -> void:
var adr = ctx["adr"]
var runner = adr.runner()
if runner == null:
return
var t := String(node.get("type", ""))
_dump(ctx, "node_" + t)
if t == "rest" or t == "shop":
runner.continue_after_node()
elif t == "reward":
var ndraw: Dictionary = adr.stop().node_curio_candidates()
var ncands: Array = ndraw.get("candidates", []) as Array
if ncands.is_empty():
runner.continue_after_node() # 牌库空合法态直通(池耗即枯竭)
else:
adr.stop().present_node_curio(ncands)
# 节点三选一兑付完成回图(context=reward_node → continue_after_node 回选路)
static func _on_curio_resolved(result: Dictionary, ctx: Dictionary) -> void:
if String(result.get("context", "")) != "reward_node":
return
var adr = ctx["adr"]
var runner = adr.runner()
if runner != null and not runner.continue_after_node():
ctx["result"] = "node_advance_failed"
-1
View File
@@ -1 +0,0 @@
uid://byleq6f7m8qm6