645 lines
30 KiB
Python
Raw Normal View History

2025-11-10 18:04:15 +08:00
import os
import csv
from io import StringIO
2025-11-13 21:33:51 +08:00
import re
2025-11-18 14:37:23 +08:00
import shutil
2025-11-10 18:04:15 +08:00
g_ai_cfg_dict = []
2025-11-10 18:04:15 +08:00
# function: read_text_file
2025-11-12 19:42:32 +08:00
def read_text_file(file_path, read_mode='r'):
"""
兼容 UTF-8 GBK 编码的文件读取函数
:param file_path: 文件路径
:param read_mode: 读取模式默认 'r'文本模式
:return: 文件内容字符串
"""
# 先尝试 UTF-8 编码
try:
with open(file_path, read_mode, encoding='utf-8-sig') as f:
return f.read()
except UnicodeDecodeError:
# UTF-8 失败,尝试 GBK 编码
2025-11-10 18:04:15 +08:00
try:
2025-11-12 19:42:32 +08:00
with open(file_path, read_mode, encoding='gbk') as f:
return f.read()
2025-11-10 18:04:15 +08:00
except UnicodeDecodeError:
2025-11-12 19:42:32 +08:00
# 两种编码都失败,抛出异常
raise Exception(f"文件 {file_path} 不支持 UTF-8 和 GBK 编码")
2025-11-10 18:04:15 +08:00
# function: parse_csv_to_dict
def parse_csv_to_dict(csv_str):
"""将CSV字符串解析为字典列表"""
string_io = StringIO(csv_str)
csv_reader = csv.DictReader(string_io)
data = []
for row in csv_reader:
2025-11-18 14:37:23 +08:00
if has_content(row) and is_row_empty(row) == False:
2025-11-12 19:42:32 +08:00
data.append(dict(row)) # 转换为普通字典
2025-11-10 18:04:15 +08:00
return data
2025-11-18 14:37:23 +08:00
def remove_first_line_find(text):
"""
使用 find 方法找到第一个换行符并切片
"""
first_newline = text.find('\n')
if first_newline == -1:
return "" # 没有换行符,说明只有一行
return text[first_newline + 1:]
# function: parse_csv_to_dict2
def parse_csv_to_dict2(csv_str):
"""将CSV字符串解析为字典列表"""
csv_str = remove_first_line_find(csv_str)
string_io = StringIO(csv_str)
csv_reader = csv.DictReader(string_io)
data = []
idx = 0
for row in csv_reader:
if idx > 0 and has_content(row) and is_row_empty(row) == False:
data.append(dict(row)) # 转换为普通字典
idx = idx + 1
return data
2025-11-10 18:04:15 +08:00
def has_content(s):
return s is not None and len(s) > 0
2025-11-18 14:37:23 +08:00
def is_row_empty(row):
is_empty = True
for key, value in row.items():
if value != '':
is_empty = False
break
return is_empty
2025-11-10 18:04:15 +08:00
# function: calc_story_end_idx
def calc_story_range_list(csv_data):
story_ranges = []
for i, item_data in enumerate(csv_data):
if has_content(item_data['关卡']):
story_ranges.append(i)
story_ranges.append(len(csv_data))
story_range_list = []
for i in range(len(story_ranges)-1):
story_range_list.append({'start': story_ranges[i], 'end': story_ranges[i+1]})
return story_range_list
# functino: make_story_data
def make_story_data(csv_data, start_idx, end_idx):
start_csv_line = csv_data[start_idx]
2025-11-18 14:37:23 +08:00
story_type = start_csv_line['剧情分类']
2025-11-10 18:04:15 +08:00
story_data = {
'id': start_csv_line['ID'],
2025-11-18 14:37:23 +08:00
'map_level': start_csv_line['关卡'],
2025-11-10 18:04:15 +08:00
'task_title': start_csv_line['聊天任务标题'],
2025-11-18 14:37:23 +08:00
'story_type': story_type,
#'B1_add_heart': start_csv_line['分支1好感度'],
#'B1_reward': start_csv_line['分支1奖励'],
2025-11-10 18:04:15 +08:00
'B1_scripts': [],
2025-11-18 14:37:23 +08:00
#'B2_add_heart': start_csv_line['分支2好感度'],
#'B2_reward': start_csv_line['分支2奖励'],
2025-11-10 18:04:15 +08:00
'B2_scripts': [],
2025-11-18 14:37:23 +08:00
#'B3_add_heart': start_csv_line['分支3好感度'],
#'B3_reward': start_csv_line['分支3奖励'],
2025-11-10 18:04:15 +08:00
'B3_scripts': [],
}
idx = 0
for i in range(start_idx, end_idx):
csv_line = csv_data[i]
# 分支1
story_data['B1_scripts'].append({'idx': idx, 'name': csv_line['分支1角色'], 'script': csv_line['分支1台词']})
# if csv_line['分支1角色'] != '' and csv_line['分支1台词'] != '':
# story_data['B1_scripts'].append({'idx': idx, 'name': csv_line['分支1角色'], 'script': csv_line['分支1台词']})
# 分支2
story_data['B2_scripts'].append({'idx': idx, 'name': csv_line['分支2角色'], 'script': csv_line['分支2台词']})
# if csv_line['分支2角色'] != '' and csv_line['分支2台词'] != '':
# story_data['B2_scripts'].append({'idx': idx, 'name': csv_line['分支2角色'], 'script': csv_line['分支2台词']})
# 分支3
story_data['B3_scripts'].append({'idx': idx, 'name': csv_line['分支3角色'], 'script': csv_line['分支3台词']})
# if csv_line['分支3角色'] != '' and csv_line['分支3台词'] != '':
# story_data['B3_scripts'].append({'idx': idx, 'name': csv_line['分支3角色'], 'script': csv_line['分支3台词']})
idx = idx + 1
return story_data
# functino: make_language_key
g_language_strs = {}
def make_language_key(idx, str):
key = "ST%s"%(idx)
if key in g_language_strs:
print("ERR: in g_language_strs key %s:%s:%s exist!!!!"%(key,g_language_strs[key], str))
exit()
if has_content(str):
g_language_strs[key] = str
return key
def make_language_story_opt_key(idx, str):
key = "SOPT%s"%(idx)
if key in g_language_strs:
print("ERR: in g_language_strs key %s:%s:%s exist!!!!"%(key,g_language_strs[key], str))
exit()
2025-11-18 14:37:23 +08:00
if has_content(str):
g_language_strs[key] = str
2025-11-10 18:04:15 +08:00
return key
2025-11-18 14:37:23 +08:00
def make_language_key2(key, str):
if has_content(str):
g_language_strs[key] = str
return key
2025-11-10 18:04:15 +08:00
# functino: get_language_name_key
2025-11-18 14:37:23 +08:00
# g_actor_info_dict = [
# {'StoryNpcId': 20000, 'NameKey': 'system', 'Name': '系统', 'Img': 'system', 'Head': 'PlayerHeads/player_head_1'},
# {'StoryNpcId': 20001, 'NameKey': 'player', 'Name': '玩家', 'Img': 'player', 'Head': 'PlayerHeads/player_head_1'},
# {'StoryNpcId': 20002, 'NameKey': 'actor_nvshen', 'Name': '女神', 'Img': 'HeroDraw/Npc_01', 'Head': 'PlayerHeads/player_head_nvshen'},
# {'StoryNpcId': 20003, 'NameKey': 'actor_weier', 'Name': '薇儿', 'Img': 'HeroDraw/Npc_02', 'Head': 'PlayerHeads/player_head_weier'},
# {'StoryNpcId': 20004, 'NameKey': 'actor_xifu', 'Name': '希芙', 'Img': 'HeroDraw/Npc_03', 'Head': 'PlayerHeads/player_head_xifu'},
# {'StoryNpcId': 20005, 'NameKey': 'actor_furuiya', 'Name': '芙蕾雅', 'Img': 'HeroDraw/Npc_04', 'Head': 'PlayerHeads/player_head_furuiya'},
# {'StoryNpcId': 20006, 'NameKey': 'actor_yideng', 'Name': '伊登', 'Img': 'HeroDraw/Npc_05', 'Head': 'PlayerHeads/player_head_yideng'},
# {'StoryNpcId': 20007, 'NameKey': 'actor_haila', 'Name': '海拉', 'Img': 'HeroDraw/Npc_06', 'Head': 'PlayerHeads/player_head_haila'},
# {'StoryNpcId': 20008, 'NameKey': 'actor_waerjili', 'Name': '瓦尔基里', 'Img': 'HeroDraw/Npc_07', 'Head': 'PlayerHeads/player_head_waerjili'}
# ]
g_actor_info_dict = []
2025-11-10 18:04:15 +08:00
def get_actor_info(name):
for value in g_actor_info_dict:
if value['Name'] == name:
return value
print("[get_actor_info] no find actor info name: " + name)
return None
2025-11-18 14:37:23 +08:00
g_StoryRewardCfg = []
2025-11-10 18:04:15 +08:00
# functino: create_story_cfg
2025-11-18 14:37:23 +08:00
def create_story_cfg(story_id, story_type, story_npc_id, map_level, story_selection_texts, story_selection_next,
story_force_guide_group, story_condition):
2025-11-10 18:04:15 +08:00
return {
'Id': int(story_id),
'StoryId': int(story_id),
'Type': int(story_type),
2025-11-18 14:37:23 +08:00
'StoryNpcId': int(story_npc_id),
'MapLevel': int(map_level),
2025-11-10 18:04:15 +08:00
'SelectionTexts': story_selection_texts,
'SelectionNext': story_selection_next,
'NeedBg': False,
'HideUi': False,
'Transition': False,
'TransitionType': 3,
'Skip': False,
'PlayInterval': 5,
'ProgramControl': True,
'NeedSave': len(story_selection_texts) > 0,
'ForceGuideGroup': story_force_guide_group,
'Condition': story_condition,
'Group': '',
'DataCheck': ''
}
# function: create_stroyPerformCfg, act_type: 'RoleMovein', 'RoleSpeaking', 'RoleMoveout'
def create_stroyPerformCfg(script_info_list, story_id, story_type, start_idx, end_idx):
cfgs = []
idx = 0
if start_idx <= end_idx:
for script_info in script_info_list[start_idx:end_idx+1]:
if has_content(script_info['script']):
idx += 1
story_perform_id = str(int(story_id)*100 + idx)
2025-11-10 18:04:15 +08:00
SpeakSite = 1
SpeakId = make_language_key(story_perform_id, script_info['script'])
LeftName = ''
LeftImg = ''
LeftAct = ''
RightName = ''
RightImg = ''
RightAct = ''
actor_info = get_actor_info(script_info['name'])
2025-11-11 15:09:52 +08:00
if actor_info == None:
print("ERR: not find actor name, story_id=" + story_id)
2025-11-10 18:04:15 +08:00
if actor_info['NameKey'] == 'player':
SpeakSite = 2
LeftName = ''
LeftImg = ''
LeftAct = 'RoleMoveout'
2025-11-12 19:42:32 +08:00
RightImg = actor_info['Img']
2025-11-10 18:04:15 +08:00
RightName = actor_info['NameKey']
2025-11-12 19:42:32 +08:00
if story_type == 0:
RightImg = actor_info['Img']
else:
RightImg = actor_info['Head']
2025-11-10 18:04:15 +08:00
RightAct = 'RoleMovein'
else:
SpeakSite = 1
LeftName = actor_info['NameKey']
LeftImg = actor_info['Img']
2025-11-12 19:42:32 +08:00
if story_type == 0:
LeftImg = actor_info['Img']
else:
LeftImg = actor_info['Head']
2025-11-10 18:04:15 +08:00
LeftAct = 'RoleMovein'
RightName = ''
RightImg = ''
RightAct = 'RoleMoveout'
cfgs.append({
'Id': story_perform_id, 'StoryId': story_id, 'Type': 0, 'LeftAct': LeftAct, 'LeftActBgTime': 0,
'RightAct': RightAct, 'RightActBgTime': 0, 'LeftName': LeftName, 'LeftNameColour': 'title02', 'LeftImg': LeftImg,
'RightName': RightName, 'RightNameColour': 'title01', 'RightImg': RightImg, 'SpeakSite': SpeakSite, 'SpeakId': SpeakId, 'SpeakTime': 0,
'WordTime': 10, 'Camp': '', 'CfgId': '', 'Dir': '', 'DirStartTime': '',
'AniName': '', 'AniStartTime': '', 'Eff': '', 'EffStartTime': '', 'OverTime': 0
})
# 如果是对话框对话,就要在首尾添加入场配置和退场配置
if story_type == 0:
story_perform_id = str(int(story_id)*100 + 0)
2025-11-10 18:04:15 +08:00
LeftName = cfgs[0]['LeftName']
LeftImg = cfgs[0]['LeftImg']
RightName = cfgs[0]['RightName']
RightImg = cfgs[0]['RightImg']
cfgs.insert(0, {
'Id': story_perform_id, 'StoryId': story_id, 'Type': 0, 'LeftAct': 'RoleMovein', 'LeftActBgTime': 0,
'RightAct': 'RoleMovein', 'RightActBgTime': 0, 'LeftName': LeftName, 'LeftNameColour': 'title02', 'LeftImg': LeftImg,
'RightName': RightName, 'RightNameColour': 'title01', 'RightImg': RightImg, 'SpeakSite': 0, 'SpeakId': '', 'SpeakTime': 0,
'WordTime': 10, 'Camp': '', 'CfgId': '', 'Dir': '', 'DirStartTime': '',
'AniName': '', 'AniStartTime': '', 'Eff': '', 'EffStartTime': '', 'OverTime': 0
})
story_perform_id = str(int(story_id)*100 + len(cfgs))
2025-11-10 18:04:15 +08:00
LeftName = cfgs[-1]['LeftName']
LeftImg = cfgs[-1]['LeftImg']
RightName = cfgs[-1]['RightName']
RightImg = cfgs[-1]['RightImg']
cfgs.append({
'Id': story_perform_id, 'StoryId': story_id, 'Type': 0, 'LeftAct': 'RoleMoveout', 'LeftActBgTime': 0,
'RightAct': 'RoleMoveout', 'RightActBgTime': 0, 'LeftName': LeftName, 'LeftNameColour': 'title02', 'LeftImg': LeftImg,
'RightName': RightName, 'RightNameColour': 'title01', 'RightImg': RightImg, 'SpeakSite': 0, 'SpeakId': '', 'SpeakTime': 0,
'WordTime': 10, 'Camp': '', 'CfgId': '', 'Dir': '', 'DirStartTime': '',
'AniName': '', 'AniStartTime': '', 'Eff': '', 'EffStartTime': '', 'OverTime': 0
})
2025-11-11 15:09:52 +08:00
for i, cfg_item in enumerate(cfgs):
if cfg_item == None:
print("----cfg_item is None-----")
2025-11-13 21:33:51 +08:00
#print(cfg_item)
2025-11-11 15:09:52 +08:00
2025-11-10 18:04:15 +08:00
return cfgs
2025-11-13 21:33:51 +08:00
# function: make_story_cfg
2025-11-10 18:04:15 +08:00
def make_story_cfg(story_cfgs, stroyPerformCfgV2_cfgs, story_data):
ID = story_data['id']
2025-11-18 14:37:23 +08:00
level = story_data['map_level']
2025-11-10 18:04:15 +08:00
story_type = 0
2025-11-18 14:37:23 +08:00
story_npc_id = 0
if '对话' in story_data['story_type']:
2025-11-10 18:04:15 +08:00
story_type = 0
2025-11-18 14:37:23 +08:00
elif '聊天' in story_data['story_type']:
2025-11-10 18:04:15 +08:00
story_type = 1
2025-11-18 14:37:23 +08:00
strs = story_data['story_type'].split(':')
if len(strs) == 2:
story_type = 0
if strs[0] == '对话':
story_type = 0
elif strs[0] == '聊天':
story_type = 1
actor_info = get_actor_info(strs[1])
story_npc_id = int(actor_info['StoryNpcId'])
2025-11-10 18:04:15 +08:00
story_force_guide_group = 0
story_condition = ''
has_multi_options = False
for i in range(len(story_data['B1_scripts'])):
if has_content(story_data['B1_scripts'][i]['script']) and has_content(story_data['B2_scripts'][i]['script']) and has_content(story_data['B3_scripts'][i]['script']):
story_id = "%s0" % (ID)
story1_id = "%s1" % (ID)
story2_id = "%s2" % (ID)
story3_id = "%s3" % (ID)
story1_opt_1 = make_language_story_opt_key(story1_id, story_data['B1_scripts'][i]['script'])
story1_opt_2 = make_language_story_opt_key(story2_id, story_data['B2_scripts'][i]['script'])
story1_opt_3 = make_language_story_opt_key(story3_id, story_data['B3_scripts'][i]['script'])
2025-11-10 18:04:15 +08:00
story1_selection_texts = "%s;%s;%s" % (story1_opt_1, story1_opt_2, story1_opt_3)
story1_selection_next = "%s;%s;%s" % (story1_id, story2_id, story3_id)
2025-11-18 14:37:23 +08:00
story_cfgs.append(create_story_cfg(story_id, story_type, story_npc_id, level, story1_selection_texts, story1_selection_next, story_force_guide_group, story_condition))
story_cfgs.append(create_story_cfg(story1_id, story_type, story_npc_id, level, '', '', 0, ''))
story_cfgs.append(create_story_cfg(story2_id, story_type, story_npc_id, level, '', '', 0, ''))
story_cfgs.append(create_story_cfg(story3_id, story_type, story_npc_id, level, '', '', 0, ''))
2025-11-10 18:04:15 +08:00
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B1_scripts'], story_id, story_type, 0, i-1))
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B1_scripts'], story1_id, story_type, i+1, len(story_data['B1_scripts'])-1))
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B2_scripts'], story2_id, story_type, i+1, len(story_data['B2_scripts'])-1))
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B3_scripts'], story3_id, story_type, i+1, len(story_data['B3_scripts'])-1))
has_multi_options = True
break
if has_content(story_data['B1_scripts'][i]['script']) and has_content(story_data['B2_scripts'][i]['script']) and has_content(story_data['B3_scripts'][i]['script']) == False:
story_id = "%s0" % (ID)
story1_id = "%s1" % (ID)
story2_id = "%s2" % (ID)
story1_opt_1 = make_language_story_opt_key(story1_id, story_data['B1_scripts'][i]['script'])
story1_opt_2 = make_language_story_opt_key(story2_id, story_data['B2_scripts'][i]['script'])
2025-11-10 18:04:15 +08:00
story1_selection_texts = "%s;%s" % (story1_opt_1, story1_opt_2)
story1_selection_next = "%s;%s" % (story1_id, story2_id)
2025-11-18 14:37:23 +08:00
story_cfgs.append(create_story_cfg(story_id, story_type, story_npc_id, level, story1_selection_texts, story1_selection_next, story_force_guide_group, story_condition))
story_cfgs.append(create_story_cfg(story1_id, story_type, story_npc_id, level, '', '', 0, ''))
story_cfgs.append(create_story_cfg(story2_id, story_type, story_npc_id, level, '', '', 0, ''))
2025-11-10 18:04:15 +08:00
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B1_scripts'], story_id, story_type, 0, i-1))
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B1_scripts'], story1_id, story_type, i+1, len(story_data['B1_scripts'])-1))
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B2_scripts'], story2_id, story_type, i+1, len(story_data['B2_scripts'])-1))
has_multi_options = True
break
if has_multi_options == False:
story_id = "%s0" % (ID)
2025-11-18 14:37:23 +08:00
story_cfgs.append(create_story_cfg(story_id, story_type, story_npc_id, level, '', '', story_force_guide_group, story_condition))
2025-11-10 18:04:15 +08:00
stroyPerformCfgV2_cfgs.extend(create_stroyPerformCfg(story_data['B1_scripts'], story_id, story_type, 0, len(story_data['B1_scripts'])-1))
2025-11-18 14:37:23 +08:00
# function: generate_StoryCfgV2
2025-11-10 18:04:15 +08:00
def generate_StoryCfgV2(out_path, data):
2025-11-11 15:09:52 +08:00
with open(out_path+'/StoryCfgV2.csv', 'w', newline='', encoding='utf-8') as file:
2025-11-18 14:37:23 +08:00
fieldnames = ['序列ID', '触发剧情ID', '剧情类型0是对话其他ChatNpcId', '剧情NpcId', '关卡',
2025-11-10 18:04:15 +08:00
'选项显示', '继续下一个剧情', '是否底图', '是否隐藏UI',
'是否转场', '转场类型', '是否可跳过', '剧情播放间隔时间s',
'是否需要程序驱动', '是否存盘', '强制引导', '触发条件', '同组', '数据判断']
2025-11-18 14:37:23 +08:00
row1 = ['Id', 'StoryId', 'Type', 'StoryNpcId', 'MapLevel',
2025-11-10 18:04:15 +08:00
'SelectionTexts', 'SelectionNext', 'NeedBg', 'HideUi',
'Transition', 'TransitionType', 'Skip', 'PlayInterval',
'ProgramControl', 'NeedSave', 'ForceGuideGroup', 'Condition', 'Group', 'DataCheck']
2025-11-18 14:37:23 +08:00
row2 = ['int', 'int', 'int', 'int', 'int',
'list', 'list', 'bool', 'bool',
'bool', 'int', 'bool', 'int',
2025-11-10 18:04:15 +08:00
'bool', 'bool', 'int', 'list', 'list', 'list']
csv_data = []
csv_data.append(fieldnames)
csv_data.append(row1)
csv_data.append(row2)
for i, data_item in enumerate(data):
csv_data.append(data_item.values())
writer = csv.writer(file)
writer.writerows(csv_data)
2025-11-11 15:09:52 +08:00
#print("\n--- StoryCfgV2.csv ---")
#print(csv_data)
2025-11-10 18:04:15 +08:00
2025-11-13 21:33:51 +08:00
# function: generate_StroyPerformCfgV2
2025-11-10 18:04:15 +08:00
def generate_StroyPerformCfgV2(out_path, data):
2025-11-11 15:09:52 +08:00
with open(out_path+'/StroyPerformCfgV2.csv', 'w', newline='', encoding='utf-8') as file:
2025-11-10 18:04:15 +08:00
fieldnames = ['序列ID', '剧情ID', '类型', '左侧行为',
'左侧行为开始时间', '右侧行为', '右侧行为时间', '左侧姓名',
'左侧姓名颜色', '左侧半身像', '右侧姓名', '右侧姓名颜色',
'阵营', '配置ID', '面向', '面向开始时间',
'动作名字', '动作开始时间', '特效ID', '特效开始时间', '结束时间']
row1 = ['Id', 'StoryId', 'Type', 'LeftAct',
'LeftActBgTime', 'RightAct', 'RightActBgTime', 'LeftName',
'LeftNameColour', 'LeftImg', 'RightName', 'RightNameColour',
'RightImg', 'SpeakSite', 'SpeakId', 'SpeakTime',
'WordTime', 'Camp', 'CfgId', 'Dir',
'DirStartTime', 'AniName', 'AniStartTime', 'Eff', 'EffStartTime', 'OverTime']
row2 = ['int', 'int', 'int', 'string',
'int', 'string', 'int', 'string',
'string', 'string', 'string', 'string',
'string', 'int', 'string', 'int',
'int', 'list', 'list', 'list',
'list', 'list', 'list', 'list', 'list', 'int']
csv_data = []
csv_data.append(fieldnames)
csv_data.append(row1)
csv_data.append(row2)
2025-11-11 15:09:52 +08:00
print("\n--- StroyPerformCfgV2.csv ---")
2025-11-10 18:04:15 +08:00
for i, data_item in enumerate(data):
2025-11-11 15:09:52 +08:00
if data_item == None:
print("data_item: None " + str(i))
2025-11-10 18:04:15 +08:00
csv_data.append(data_item.values())
writer = csv.writer(file)
writer.writerows(csv_data)
2025-11-13 21:33:51 +08:00
2025-11-18 14:37:23 +08:00
# function: generate_StoryNpcCfgV2
def generate_StoryNpcCfgV2(out_path, storyNpcCfg):
with open(out_path+'/StoryNpcCfgV2.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames = ['序列ID', 'Story NPC ID', '类型(1妻子2情人3陌生人,4群聊0其他)', '昵称Key', '昵称',
'头像', '对话框半身像', '地点', '年龄',
'民族', '婚姻状况', '签名', '发现动态内容',
'发现动态图片', '发现动态点赞数', '发现动态评论数', '关卡解锁',
'主角等级解锁', '爬塔层数解锁', '撩一撩剧情']
row1 = ['Id', 'StoryNpcId', 'Type', 'NameKey', 'Name',
'Head', 'Img', 'Location', 'Age',
'Nation', 'Marry', 'Sign', 'Post',
'Photos', 'Upvote', 'Comment', 'MapLevel',
'PlayerLevel', 'TowerLevel', 'StoryId']
row2 = ['int', 'int', 'int', 'string', 'string',
'string', 'string', 'string', 'int',
'string', 'string', 'string', 'string',
'list', 'int', 'int', 'int',
'int', 'int', 'int']
2025-11-13 21:33:51 +08:00
csv_data = []
csv_data.append(fieldnames)
csv_data.append(row1)
csv_data.append(row2)
2025-11-18 14:37:23 +08:00
print("\n--- StoryNpcCfgV2.csv ---")
for i, data_item in enumerate(storyNpcCfg):
if data_item == None:
print("data_item: None " + str(i))
data_item['Location'] = make_language_key2("NPCLoc%s"%(data_item['Id']), data_item['Location'])
data_item['Nation'] = make_language_key2("NPCNation%s"%(data_item['Id']), data_item['Nation'])
data_item['Marry'] = make_language_key2("NPCMarry%s"%(data_item['Id']), data_item['Marry'])
data_item['Sign'] = make_language_key2("NPCSign%s"%(data_item['Id']), data_item['Sign'])
data_item['Post'] = make_language_key2("NPCPost%s"%(data_item['Id']), data_item['Post'])
csv_data.append(data_item.values())
#print(data_item.values())
2025-11-13 21:33:51 +08:00
writer = csv.writer(file)
writer.writerows(csv_data)
2025-11-18 14:37:23 +08:00
# function: generate_StoryRewards, data is storyData
# def generate_StoryRewards(out_path, data):
# with open(out_path+'/StoryRewards.csv', 'w', newline='', encoding='utf-8') as file:
# fieldnames = ['剧情Id', '关卡条件', '增加好感度NPC', '增加好感度', '剧情奖励1', '剧情奖励2', '剧情奖励3',
# '剧情奖励4', '剧情奖励5', '剧情奖励6', '剧情奖励7', '剧情奖励8']
# row1 = ['StoryId', 'MapLevel', 'AddHeartNpc', 'AddHeart', 'Reward1', 'Reward2', 'Reward3', 'Reward4',
# 'Reward5', 'Reward6', 'Reward7', 'Reward8']
# row2 = ['int', 'int', 'int', 'int', 'list', 'list', 'list', 'list',
# 'list', 'list', 'list', 'list']
# csv_data = []
# csv_data.append(fieldnames)
# csv_data.append(row1)
# csv_data.append(row2)
# for i, data_item in enumerate(data):
# story_id = data_item['StoryId']
# map_level = data_item['MapLevel']
# reward_text = data_item['Reward']
# pattern = r'\{([^}]+)\}'
# matches = re.findall(pattern, reward_text)
# row = {'StoryId': story_id, 'MapLevel': map_level, 'AddHeartNpc': data_item['StoryNpcId'], 'AddHeart': data_item['AddHeart']}
# for i in range(8):
# row[f"Reward{i+1}"] = ''
# for i in range(len(matches)):
# row[f"Reward{i+1}"] = matches[i]
# csv_data.append(row.values())
# writer = csv.writer(file)
# writer.writerows(csv_data)
2025-11-10 18:04:15 +08:00
2025-11-13 21:33:51 +08:00
# function: generate_LanguagePackageV2_cn
2025-11-10 18:04:15 +08:00
def generate_LanguagePackageV2_cn(out_path, data):
2025-11-11 15:09:52 +08:00
with open(out_path+'/../../../Assets/Content/Config/LanguagePackageV2_cn.csv', 'w', newline='', encoding='utf-8') as file:
2025-11-10 18:04:15 +08:00
fieldnames = ['key', '内容']
row1 = ['key', 'Language']
row2 = ['string', 'string']
csv_data = []
csv_data.append(fieldnames)
csv_data.append(row1)
csv_data.append(row2)
for actor_info in g_actor_info_dict:
csv_data.append([actor_info['NameKey'], actor_info['Name']])
for key, value in data.items():
csv_data.append([key, value])
writer = csv.writer(file)
writer.writerows(csv_data)
print("\n--- LanguagePackageV2_cn.csv ---")
2025-11-11 15:09:52 +08:00
#print(csv_data)
2025-11-10 18:04:15 +08:00
def generate_StoryAICfgV2(out_path, storyAICfg):
with open(out_path+'/StoryAICfgV2.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames =['序号', '剧情NPC', '剧情ID', '类型1-发送2-响应)', '消息']
row1 = ['Id', 'StoryNpcId', 'StoryId', 'Type', 'Message']
row2 = ['int', 'int', 'int', 'int', 'string']
csv_data = []
csv_data.append(fieldnames)
csv_data.append(row1)
csv_data.append(row2)
print("\n--- StoryAICfgV2.csv ---")
for i, data_item in enumerate(storyAICfg):
if data_item == None:
print("data_item: None " + str(i))
data_item['Message'] = make_language_key2("AIT%s"%(data_item['Id']), data_item['Message'])
csv_data.append(data_item.values())
writer = csv.writer(file)
writer.writerows(csv_data)
2025-11-10 18:04:15 +08:00
2025-11-13 21:33:51 +08:00
# function: generate_config
2025-11-10 18:04:15 +08:00
def generate_config(story_data_list, out_path):
StoryCfgV2_lines = []
StroyPerformCfgV2_lines = []
LanguagePackage_cn_lines = []
for i, story_data in enumerate(story_data_list):
make_story_cfg(StoryCfgV2_lines, StroyPerformCfgV2_lines, story_data)
generate_StoryAICfgV2(out_path, g_ai_cfg_dict)
2025-11-18 14:37:23 +08:00
generate_StoryNpcCfgV2(out_path, g_actor_info_dict)
2025-11-10 18:04:15 +08:00
generate_StoryCfgV2(out_path, StoryCfgV2_lines)
2025-11-18 14:37:23 +08:00
#generate_StoryRewards(out_path, StoryCfgV2_lines)
2025-11-10 18:04:15 +08:00
generate_StroyPerformCfgV2(out_path, StroyPerformCfgV2_lines)
generate_LanguagePackageV2_cn(out_path, g_language_strs)
2025-11-18 14:37:23 +08:00
2025-11-10 18:04:15 +08:00
# main入口
if __name__ == "__main__":
g_script_dir = os.path.dirname(os.path.abspath(__file__))
g_input_dir = os.path.join(g_script_dir, 'input')
g_out_dir = os.path.join(g_script_dir, 'output')
2025-11-11 15:09:52 +08:00
g_input_dir = g_input_dir.replace('\\', '/')
g_out_dir = g_out_dir.replace('\\', '/')
2025-11-10 18:04:15 +08:00
print('g_input_dir: ' + g_input_dir)
print('g_out_dir: ' + g_out_dir)
g_story_data_list = []
2025-11-18 14:37:23 +08:00
# 1. Read StoryNpcCfg.csv
file_path = os.path.join(g_input_dir, 'StoryNpcCfg.csv')
file_content = read_text_file(file_path)
g_actor_info_dict = parse_csv_to_dict2(file_content)
#shutil.copy(file_path, g_out_dir)
# 2. Read StoryAICfg.csv
file_path = os.path.join(g_input_dir, 'StoryAICfg.csv')
file_content = read_text_file(file_path)
g_ai_cfg_dict = parse_csv_to_dict2(file_content)
#shutil.copy(file_path, g_out_dir)
2025-11-18 14:37:23 +08:00
# 3. Read StoryRewardCfg.csv
2025-11-18 14:37:23 +08:00
file_path = os.path.join(g_input_dir, 'StoryRewardCfg.csv')
file_content = read_text_file(file_path)
g_StoryRewardCfg = parse_csv_to_dict2(file_content)
shutil.copy(file_path, g_out_dir)
# 4. Read StoryText.csv
2025-11-18 14:37:23 +08:00
file_path = os.path.join(g_input_dir, 'StoryText.csv')
file_content = read_text_file(file_path)
if file_content is not None:
# 解析csv数据为Dict
csv_data = parse_csv_to_dict(file_content)
# 把csv数据分隔为一段段剧情并生成剧情数据列表story_data_list
story_range_list = calc_story_range_list(csv_data)
for i, story_range in enumerate(story_range_list):
story_data = make_story_data(csv_data, story_range['start'], story_range['end'])
g_story_data_list.append(story_data)
# 根据story_data_list生成配置文件
generate_config(g_story_data_list, g_out_dir)
'''
2025-11-10 18:04:15 +08:00
for filename in os.listdir(g_input_dir):
if filename.endswith('.csv'):
file_path = os.path.join(g_input_dir, filename)
file_content = read_text_file(file_path)
if file_content is not None:
print(f"=== {filename} ===")
# 解析csv数据为Dict
csv_data = parse_csv_to_dict(file_content)
# 把csv数据分隔为一段段剧情并生成剧情数据列表story_data_list
story_range_list = calc_story_range_list(csv_data)
for i, story_range in enumerate(story_range_list):
story_data = make_story_data(csv_data, story_range['start'], story_range['end'])
g_story_data_list.append(story_data)
2025-11-12 19:42:32 +08:00
#print("--- story_data ---")
#print(story_data)
#print()
2025-11-11 15:09:52 +08:00
2025-11-10 18:04:15 +08:00
# 根据story_data_list生成配置文件
generate_config(g_story_data_list, g_out_dir)
else:
print(f"无法读取文件: {filename}")
2025-11-18 14:37:23 +08:00
'''
2025-11-10 18:04:15 +08:00