用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Godofcong-1/erArk --skill draw-aa-map命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
在不启动图形界面的情况下无头运行 erArk:加载游戏配置、自建角色fixture做函数级单元测试,或加载指定存档、复刻某条指令、带护栏运行角色行为循环并逐轮内窥。用于验证新增的前提/结算器/效果链/口上是否生效,复现与定位死循环/卡死,以及修复前后的回归测试。当需要"给新增的前提或结算写单元测试"、"验证效果链顺序"、"复现某存档下的BUG"、"模拟执行某指令"、"验证行为循环收敛"、"排查NPC卡死"时使用。
为 erArk 新增一个玩家指令及其行为、前提、结算、口上的完整实施流程,含一段行为与二段行为的选型区分。当需要新增游戏指令、行为、二段行为、或为指令补齐前提/结算/口上时使用。
把一次改动按 erArk 的既定体例写进仓库根目录的 update.log(新增/调整/修正三类、括号标签规则、追加位置、文案风格)。当需要"更新更新日志"、"把本次改动写进 update.log"、"补一条 changelog",或完成一个 plan/功能后要登记版本日志时使用。
正在显示 SKILL.md
| name | draw-aa-map |
| description | 创建或调整 erArk 的 AA 地图(data/map/*/Map),包括给区块新增房间、重排整张版面、修正竖墙错位。当需要画地图/改地图/加房间,或玩家反馈地图显示歪掉、排版错乱时使用。 |
你是 erArk 的 AA 地图排版助手。完整原理说明见 地图系统 的「AA 地图排版」一节。
AA 地图的排版由字体的实际字宽决定,不是由 wcwidth.wcswidth 决定。
MapDrawLine.width 走 Script/Core/text_handle.py:65 get_text_index()(即 wcswidth),但它不参与行内排版。see_map_panel.py:97-109 只用全局 max_width 算出一个所有行共用的居中空格前缀,之后逐段原样输出,不做任何裁剪或补齐。因此行内对齐 100% 由字体字宽决定。
⚠️ 永远不要用"数列数"的方式判断对齐——这正是历史上重画后实机仍然歪掉的原因。必须用 tools/map_aa_check.py 按像素校验。
在 等距更纱黑体 SC 下字符分成两个互不通约的度量族:
| 度量族 | 代表字符 | 字号 20 下 |
|---|---|---|
| 框线族 | ═ ║ │ ┃ ┄ ┅ ┆ ┇ ─ ━、▓ ♂ ♀ ¤ ▁、U+2002 | 13 px |
| 框线族(全角) | 汉字、○ ● □ ▣ ♲ ◎ ◇、- ~ ← → ↗ ↘ | 26 px |
| ASCII 族 | ASCII 空格、~、-、数字、字母 | 14 px |
| ASCII 族(双宽) | ☸ ➷ ➹ ✪ | 28 px |
两族在字号 18/22/24/26/30 下碰巧同宽,在 14/16/20/40 下不同宽。当前 config.ini 反算出的字号正好是 20(font_size = int(window_width / text_width) * 2 = int(2000/190)*2),所以每出现一个 ASCII 空格就相对框线漂移 1px。
令 U = 框线字符宽度,只用恒为 1U / 2U 的字符即可在任意字号下对齐:
| 宽度 | 可用字符 |
|---|---|
| 1U | 框线 ═ ║ │ ┃ ┄ ┅ ┆ ┇ ─ ━、▓ ♂ ♀ ¤ ▁、U+2002 EN SPACE(留白)、≈ ∼ ∽ ⊙ ⊕ |
| 2U | 汉字、○ ● □ ▣ ♲ ◎ ◉ ◍ ◇ ◈、~ 〜 ﹏ ⌒、← → ↗ ↘ ↖ ↙、- _ < >、U+3000 |
| 禁用 | ASCII 空格、~、-、数字字母、☸ ➷ ➹ ✪ |
留白一律用 U+2002 EN SPACE 替代 ASCII 空格,这是消除大范围错位的关键。
U+2002 与普通空格肉眼完全一样,手抄/复制粘贴极易被静默换回 ASCII 空格。因此这类地图必须由脚本生成,绝不可手改
Map文件。
python tools/map_aa_check.py <地图名> # 看这张图当前错位多少
python tools/map_aa_check.py --list-bad # 看全部地图的错位排名
同时读一遍目标 data/map/<区块>/Map 与 Map.json,弄清现有房间的相对位置与连通关系。参考画得比较规整的 data/map/仓储/Map、data/map/疗养庭院/Map。
先把版面写成一张列规划表再动手,例如:
上排 0 ┃ 健身区上 26U ┃27 木桩房 18U ┃46 射击房 8U │55 靶道 32U ┃88
走廊 健身区@11U 走廊@46U 入口0@88U
下排 0 ┃ 健身区下 26U ┃27 模拟对战室 18U ┃46 休息室 12U ┃59 更衣室 8U ┃68 淋浴 6U ┃75 游泳池 12U ┃88
要点:
┄ / ┆,实墙用 ═ / ║,必须与 Map.json 的 PathEdge 一致。text_width(190),否则 Tk 会按字符软换行、整张图崩坏。不要手写 Map 文件。 以 tools/map_aa_build_training.py 为模板新建生成脚本,按 U 数拼装:
S = " " # EN SPACE = 1U,替代 ASCII 空格
E = "═"
rest = [ # 休息室 12U
S + "▓¤" + S * 6 + "¤▓" + S, # 1+2+6+2+1 = 12U
S * 12,
S * 3 + "<mapbutton>休息室</mapbutton>" + S * 3, # 3+6+3 = 12U
S * 12,
]
# 整行 = ║ + 26U + ║ + 18U + ║ + 12U + ║ + 8U + 门 + 6U + 门 + 12U + ║ = 89U
open("data/map/<区块>/Map", "wb").write("\r\n".join(lines).encode("utf-8"))
脚本必须在写入前自检三件事,任一不满足就报错退出、不写文件:
<...>(会被富文本正则吞掉)文件格式:UTF-8 无 BOM + CRLF + 末尾无换行。
python tools/map_aa_check.py <地图名> # 容差 0
python tools/map_aa_check.py <地图名> --tol 2 # 明知有小偏差时
它会在 10 个字号下逐字符累加像素位置,检查各竖墙行的总宽与每堵墙的位置是否一致,超差会指出具体哪行哪堵墙差多少,并以非零退出码结束。
期望:每个字号下含竖墙的行总宽只有一个值。
data/map/<区块>/<房间名>/Scene.json——照抄同类场景,字段含义见 地图系统.md。⚠️ 目录名必须与 <mapbutton> 里的名字完全一致,否则 map_handle.py:363 会无限递归抛 RecursionError。data/map/<区块>/Map.json 的 PathEdge 加双向边。通常不需要改任何 CSV、po 或 Python:constant.place_data 由 SceneTag 自动生成。
map_config.init_map_data() 只判断四个缓存文件是否全部存在,没有任何 mtime/hash 校验,不删缓存就完全不生效且无任何报错:
rm -f data/SceneData data/MapData data/PlaceData data/ScenePath
python init_data.py # 530 场景 O(N²) 全量寻路,会跑一会儿,产出 ~21MB
⚠️ 第二层缓存:
save_handle.py:496-516只在场景增删或scene_tag/scene_img/room_area变化时才刷新存档里的map_data。只改 AA 图而不动Scene.json时,老存档读出来仍是旧地图,必须用新档验证。
update.log 加一行(新增房间记「新增:(地图)…」,重排版面记「调整:(地图)…」)plan/ 下留实施记录,可参考 plan/done/plan_01_训练场新增休息室.md| 陷阱 | 依据 |
|---|---|
<mapbutton> 标签零宽,只有中间的名字参与排版 | map_config.py:199 |
行尾空白被 str.rstrip() 吃掉,包括 U+2002——别靠行尾补齐 | map_config.py:243 |
行首公共空格被裁,但只认 ASCII 空格(lstrip(" ")),U+2002 不受影响 | map_config.py:246 |
裸 <...> 会被 re.sub(r"<[^>]+>","") 静默吞掉;要画尖括号用全角 <> | rich_text.py:233 |
未闭合的 <mapbutton> 会让该按钮及本行后续文本静默丢失 | map_config.py:203 |
按钮名 ≠ 子目录名 → RecursionError,不是友好报错 | map_handle.py:363 |
有 Map.json 就必须有同目录 Map,否则 FileNotFoundError | map_config.py:90 |
_pad_map_lines_to_max_width() 是死代码,从未被调用 | map_config.py:345 |
➷➹ 的观感):可以,但要把它放在最右侧的格子里,这样左侧所有竖墙不受影响,只有该行最右端偏移 2px;然后用 --tol 2 校验并在文档里写明确切代价。0):无法改(是目录名)。把它放在没有竖墙的标签行上即可,不产生可见错位。Facility_open.csv 是按 SceneName 匹配的,加进去会连坐所有同名场景(项目里有 9 个"休息室")。需要单独门禁必须起独立 SceneName。tools/map_aa_check.py <地图名> 通过(或在已知容差内通过,且代价已写进文档)<mapbutton> 的名字都能对应到同级子目录Map.json 的 PathEdge 与 AA 图上画的门一一对应,且是双向边init_data.py 无报错tools/ 下,便于以后再改