添加DSL引擎迁移和验证功能
- 新增最终验证脚本和迁移测试脚本,确保DSL引擎的完整性和功能 - 实现故事模块的音频配置、角色定义和情感故事模块 - 迁移现有故事数据到新的DSL格式,支持动态内容和条件导航 - 更新主题和UI组件,确保一致的黑色背景和暗色主题 - 添加音频管理器和性能监控工具,提升游戏体验和调试能力
This commit is contained in:
114
Documentation/mindmap/analyze_end_nodes.py
Normal file
114
Documentation/mindmap/analyze_end_nodes.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
|
||||
NODE_RE = re.compile(r'^\s*@node\s+(?P<id>[A-Za-z0-9_]+)\s*$')
|
||||
TITLE_RE = re.compile(r'^\s*@title\s+"(?P<title>.*)"\s*$')
|
||||
CHOICE_RE = re.compile(r'^\s*choice_\d+\s*:\s*"(?P<label>.*?)"\s*->\s*(?P<target>[A-Za-z0-9_]+)')
|
||||
|
||||
ENDING_ID_PREFIXES = (
|
||||
'ending_',
|
||||
)
|
||||
ENDING_TITLE_KEYWORDS = (
|
||||
'结局', '最终', '终极', '拯救', '守护', '和谐', '文明', '宽恕', '宇宙', '完美'
|
||||
)
|
||||
|
||||
|
||||
def parse_story(path: str) -> Tuple[Dict[str, str], Dict[str, List[Tuple[str, str]]]]:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
nodes: Dict[str, str] = {}
|
||||
edges: Dict[str, List[Tuple[str, str]]] = {}
|
||||
|
||||
current_id: str = ''
|
||||
i = 0
|
||||
n = len(lines)
|
||||
while i < n:
|
||||
line = lines[i].rstrip('\n')
|
||||
m_node = NODE_RE.match(line)
|
||||
if m_node:
|
||||
current_id = m_node.group('id')
|
||||
if current_id not in nodes:
|
||||
nodes[current_id] = current_id
|
||||
if current_id not in edges:
|
||||
edges[current_id] = []
|
||||
|
||||
j = i + 1
|
||||
while j < n:
|
||||
l2 = lines[j].rstrip('\n')
|
||||
if NODE_RE.match(l2):
|
||||
break
|
||||
m_title = TITLE_RE.match(l2)
|
||||
if m_title:
|
||||
title = m_title.group('title').strip()
|
||||
if title:
|
||||
nodes[current_id] = title
|
||||
m_choice = CHOICE_RE.match(l2)
|
||||
if m_choice:
|
||||
label = m_choice.group('label').strip()
|
||||
target = m_choice.group('target').strip()
|
||||
edges.setdefault(current_id, []).append((label, target))
|
||||
j += 1
|
||||
|
||||
i = j
|
||||
continue
|
||||
i += 1
|
||||
|
||||
return nodes, edges
|
||||
|
||||
|
||||
def is_ending(node_id: str, title: str) -> bool:
|
||||
if any(node_id.startswith(p) for p in ENDING_ID_PREFIXES):
|
||||
return True
|
||||
return any(k in (title or '') for k in ENDING_TITLE_KEYWORDS)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--input', required=True)
|
||||
ap.add_argument('--output', required=True)
|
||||
args = ap.parse_args()
|
||||
|
||||
nodes, edges = parse_story(args.input)
|
||||
|
||||
# Compute out-degree
|
||||
outdeg = {nid: len(edges.get(nid, [])) for nid in nodes.keys()}
|
||||
|
||||
leaf_nodes = [nid for nid, deg in outdeg.items() if deg == 0]
|
||||
|
||||
endings = []
|
||||
non_endings = []
|
||||
for nid in sorted(leaf_nodes):
|
||||
title = nodes.get(nid, '')
|
||||
(endings if is_ending(nid, title) else non_endings).append((nid, title))
|
||||
|
||||
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
||||
with open(args.output, 'w', encoding='utf-8') as f:
|
||||
f.write('# 无后续(无 choices)节点清单\n\n')
|
||||
f.write(f'- 总节点数: {len(nodes)}\n')
|
||||
f.write(f'- 无后续节点数: {len(leaf_nodes)}\n')
|
||||
f.write(f'- 结局型: {len(endings)}\n')
|
||||
f.write(f'- 可能未接续: {len(non_endings)}\n\n')
|
||||
|
||||
f.write('## 结局型(Leaf Endings)\n')
|
||||
for nid, title in endings:
|
||||
f.write(f'- {title} | id: `{nid}`\n')
|
||||
f.write('\n')
|
||||
|
||||
f.write('## 可能未接续(需人工确认是否应有后续)\n')
|
||||
for nid, title in non_endings:
|
||||
f.write(f'- {title} | id: `{nid}`\n')
|
||||
|
||||
print(f"Wrote report to {args.output}. Endings={len(endings)} NonEndings={len(non_endings)}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user