def welcome(scriptname = None): ''' 用于在脚本程序开始时显示欢迎信息 ''' LINE_NORMAL = Back.RED + Style.BRIGHT LINE_GREENS = Back.RED + Style.BRIGHT + Fore.GREEN LINE_WHITED = Back.RED + Style.BRIGHT + Fore.WHITE LINE_ENDING = '\033[K' + Style.RESET_ALL print('') print(LINE_NORMAL + r" " + LINE_ENDING) print(LINE_WHITED + r" Pandas Dev Team Presents " + LINE_ENDING) print(LINE_NORMAL + r" ____ _ " + LINE_ENDING) print(LINE_NORMAL + r" | _ \ __ _ _ __ __| | __ _ ___ " + LINE_ENDING) print(LINE_NORMAL + r" | |_) |/ _` || '_ \ / _` | / _` |/ __| " + LINE_ENDING) print(LINE_NORMAL + r" | __/| (_| || | | || (_| || (_| |\__ \ " + LINE_ENDING) print(LINE_NORMAL + r" |_| \__,_||_| |_| \__,_| \__,_||___/ " + LINE_ENDING) print(LINE_NORMAL + r" " + LINE_ENDING) print(LINE_GREENS + r" https://pandas.ws/ " + LINE_ENDING) print(LINE_NORMAL + r" " + LINE_ENDING) print(LINE_WHITED + r" Pandas is only for learning and research purposes. " + LINE_ENDING) print(LINE_WHITED + r" Please don't use it for commercial. " + LINE_ENDING) print(LINE_NORMAL + r" " + LINE_ENDING) print('') if scriptname is not None: Message.ShowInfo('您现在启动的是: {scriptname}'.format(scriptname = scriptname)) Message.ShowInfo('在使用此脚本之前, 建议确保 src 目录的工作区是干净的.') Message.ShowInfo('这样当处理结果不符合预期时, 可以轻松的利用 git 进行重置操作.')
def main(): os.chdir(os.path.split(os.path.realpath(__file__))[0]) welecome() print('') confirm = InputController().requireBool({ 'tips': '是否立刻进行文件编码转换?', 'default': False }) if not confirm: Message.ShowInfo('您取消了操作, 程序终止...\n') Common.exitWithPause() count = CharsetConverter({ 'ignore_files': ['Makefile', 'Makefile.in', 'CMakeLists.txt'], 'process_exts': ['.hpp', '.cpp'] }).convertDirectory('../../src', 'UTF-8-SIG') if count <= 0: Message.ShowInfo('很好! 源代码文件都已转换为 UTF-8-SIG 编码.') print('') Common.exitWithPause()
def dump(self, filename): ''' 将当前 self.body 列表中的内容转储到本地指定文件 ''' try: Message.ShowInfo('正在保存翻译对照表...') _body = [] for x in self.body: _body.append({ 'Original': quoted(x['Original']), 'Translation': quoted(x['Translation']) }) restruct = { 'Header': { 'Type': self.header_type, 'Version': self.header_version }, 'Body' : _body } with open(filename, 'w+', encoding='UTF-8-SIG') as f: yaml.dump( restruct, f, allow_unicode=True, default_flow_style=False, width=2048, sort_keys=False ) f.close() Message.ShowInfo('保存到: %s' % os.path.relpath(os.path.abspath(filename), project_slndir)) return os.path.abspath(filename) except Exception as _err: print(_err) Message.ShowError('保存翻译对照表期间发生错误, 请重试...') return None
def toTraditional(self): ''' 将当前 self.body 中的译文结果转换到目标结果 ''' Message.ShowInfo('正在将译文转换成繁体中文...') for x in self.body: x['Translation'] = self.opencc.convert(x['Translation']) Message.ShowInfo('译文已经顺利转换成繁体中文')
def welecome(): print('=' * 70) print('') print('源代码文件编码转换脚本'.center(62)) print('') print('=' * 70) print('') Message.ShowInfo('在使用此脚本之前, 建议确保 src 目录的工作区是干净的.') Message.ShowInfo('这样处理结果如果不符合预期, 可以轻松的利用 git 进行重置操作.')
def welecome(): print('=' * 70) print('') print('NPC 事件添加助手'.center(62)) print('') print('=' * 70) print('') Message.ShowInfo('在使用此脚本之前, 建议确保 src 目录的工作区是干净的.') Message.ShowInfo('这样添加结果如果不符合预期, 可以轻松的利用 git 进行重置操作.')
def load(self, filename): ''' ''' Message.ShowInfo('正在加载: %s' % filename) with open(filename, encoding='UTF-8-SIG') as f: content = yaml.load(f, Loader=yaml.FullLoader) header = content['Header'] self.header_version = header['Version'] self.header_type = header['Type'] self.body = content['Body'] Message.ShowInfo('已读取 %d 条记录, 数据版本号为: %d' % (len(self.body), self.header_version))
def build(self, src_dir): ''' 根据指定的源代码目录, 构建新的数据保存到 self.body 列表 ''' Message.ShowStatus('正在扫描源代码目录, 提取可被翻译的字符串...') extract_content = [] for dirpath, _dirnames, filenames in os.walk(src_dir): for filename in filenames: _base_name, extension_name = os.path.splitext(filename.lower()) if extension_name.lower() in process_exts: filepath = os.path.normpath('%s/%s' % (dirpath, filename)) content = self.__step1_extract_single_file(filepath) content = self.__step2_replace_constants(content) content = self.__step3_except_nonstring(content) content = self.__step4_field_offset(content) content = self.__step5_drop_params(content) content = self.__step6_unescape(content) extract_content.extend(content) # 对提取到的内容进行消重处理 extract_content = self.__make_distinct(extract_content) self.body = [] for x in extract_content: self.body.append({'Original': x['text'], 'Translation': ''}) Message.ShowInfo('扫描完毕, 共有 %d 条可翻译的字符串' % len(self.body))
def convertFile(self, filepath, to_charset, directory): ''' 给定一个文本文件, 将它转换成指定的编码并保存 ''' origin_charset = self.__detectCharset(filepath).upper() to_charset = to_charset.upper() if origin_charset == to_charset: return False try: absolutely_path = os.path.abspath(filepath) Message.ShowInfo( '将 {filename} 的编码从 {origin_charset} 转换为 {to_charset}'.format( filename=os.path.relpath(absolutely_path, directory), origin_charset=origin_charset, to_charset=to_charset)) origin_file = codecs.open(filepath, 'r', origin_charset) content = origin_file.read() origin_file.close() target_file = codecs.open(filepath, 'w', to_charset) target_file.write(content) target_file.close() return True except IOError as err: Message.ShowError("I/O error: {0}".format(err)) return False
def cmd_execute(cmds, cwd, prefix=None, logfile=None): ''' 在指定的 cwd 工作目录下执行一系列 cmd 指令 并将执行的结果记录带 logfile 文件中 ''' if platform.system() != 'Windows': print('被调用的 cmd_execute 函数只能在 Windows 环境上运行') exit_with_pause(-1) if logfile is not None: os.makedirs(os.path.dirname(logfile), exist_ok=True) logger = open(logfile, 'w', encoding='utf8') cmdline = ' && '.join(cmds) cmdProc = subprocess.Popen(r'cmd /c "%s"' % cmdline, stdout=subprocess.PIPE, universal_newlines=True, cwd=os.path.abspath(cwd)) while True: stdout_data = cmdProc.stdout.readline() if not stdout_data and cmdProc.poll() is not None: break if stdout_data: Message.ShowInfo('%s%s' % ('%s: ' % prefix if prefix is not None else '', stdout_data.strip())) if stdout_data and logfile is not None: logger.write(stdout_data) logger.flush() time.sleep(0.01) if logfile is not None: logger.close() return cmdProc.returncode
def requireSelect(self, options): print('-' * 70) select_name = options['name'] select_data = options['data'] Message.ShowSelect('请选择%s, 可选值为 [0~%d], 分别代表:' % (select_name, len(select_data) - 1)) print('') for select in select_data: Message.ShowMenu('%s' % select['desc']) print('') Message.ShowSelect('请选择%s [0~%d]:' % (select_name, len(select_data) - 1), end="") user_select = input() if not user_select or not user_select.isnumeric(): Message.ShowError('您输入了无效的地图标记类型, 程序终止') print('-' * 70) Common.exitWithPause(-1) user_select = int(user_select) if user_select < 0 or user_select >= len(select_data): Message.ShowError('您输入了无效的地图标记类型, 程序终止') print('-' * 70) Common.exitWithPause(-1) print('') Message.ShowInfo('您选择的是: %s' % select_data[user_select]['name']) print('-' * 70) print('\n') return user_select
def main(): os.chdir(os.path.split(os.path.realpath(__file__))[0]) Common.welcome('版本号修改辅助脚本') print('') # 读取当前的 Pandas 主程序版本号 pandas_ver = Common.get_pandas_ver(os.path.abspath(project_slndir), origin=True) Message.ShowInfo('当前模拟器的主版本是 %s' % pandas_ver) print('') # 询问获取升级后的目标版本 newver = Inputer().requireText( {'tips': '请输入新的版本号 (四段式: 1.0.0.1, 最后一段为 1 则表示为开发版)'}) if not isVersionFormatValid(newver): Message.ShowError('你输入的版本号: %s 不符合四段式规则, 请重试...' % newver) Common.exit_with_pause(-1) # 执行更新操作 ver = VersionUpdater(options) ver.updateDirectory(slndir('src'), newver) Common.exit_with_pause()
def do_check_file(filename): ''' 检查给定的消息文件 ''' # 加载主要的消息文件 Message.ShowStatus('正在加载 {filename} 的消息内容...'.format( filename=os.path.relpath(filename, project_slndir))) master = get_mes_dict(filename) # 递归寻找与他相关的 import 文件 import_files = get_recursion_import_files(filename) Message.ShowStatus( '读取完毕, 找到约 {infocnt} 条消息信息, 额外引入了 {importcnt} 个消息文件.'.format( infocnt=len(master), importcnt=len(import_files))) # 分别加载这些文件的全部消息信息 b_allfine = True for x in import_files: compare = get_mes_dict(os.path.abspath(project_slndir + x)) # 若消息存在于主文件, 那么比对格式化标记 for mesid in compare: if mesid not in master.keys(): continue if not operator.eq(master[mesid]['fmt'], compare[mesid]['fmt']): b_allfine = False Message.ShowWarning( '发现消息编号为: {mesid} 的格式化标记与主文件不一致!'.format(mesid=mesid)) Message.ShowInfo(' 主要 - {filename}: {mes}'.format( filename=os.path.basename(filename), mes=master[mesid]['mes'])) Message.ShowInfo(' 对比 - {filename}: {mes}'.format( filename=os.path.basename(x), mes=compare[mesid]['mes'])) print('') if b_allfine: Message.ShowStatus('检查完毕, 消息信息的格式化标记与主文件完全匹配!') print('')
def requireBool(self, options): print('-' * 70) Message.ShowSelect(options['tips'] + ' [Y/N]:', end="") user_input = input() if user_input.lower() in ['y', 'yes']: result = True elif user_input.lower() in ['n', 'no']: result = False else: result = options['default'] Message.ShowInfo('您输入的是: ' + ('Yes 是的' if result else 'No 不是')) print('-' * 70) print('\n') return result
def execute(self, filename, savefile=None): if not Common.is_file_exists(filename): return False if not savefile: savefile = filename if not self.__silent: Message.ShowInfo('正在处理: %s (%s)' % (os.path.relpath( filename, self.__project_dir), self.__save_encoding)) contents = self.__load(filename) contents = self.__process(contents) return self.__save(contents, savefile)
def main(): ''' 主入口函数 ''' # 显示欢迎信息 Common.welcome('打包流程辅助脚本') print('') pandas_ver = Common.get_pandas_ver(os.path.abspath(project_slndir)) Message.ShowInfo('当前模拟器的主版本是 %s' % pandas_ver) # 检查是否已经完成了编译 if not Common.is_compiled(project_slndir): Message.ShowWarning('检测到打包需要的编译产物不完整, 请重新编译. 程序终止.') print('') Common.exit_with_pause(-1) # 导出当前仓库, 变成一个归档压缩文件 Message.ShowInfo('正在将当前分支的 HEAD 内容导出成归档文件...') export_file = export() if not export_file: Message.ShowError('很抱歉, 导出归档文件失败, 程序终止.') Common.exit_with_pause(-1) Message.ShowInfo('归档文件导出完成, 此文件将在程序结束时被删除.') # 基于归档压缩文件, 进行打包处理 process(export_file, renewal=True) process(export_file, renewal=False) # 执行一些清理工作 clean(export_file) print('') Message.ShowInfo('已经成功打包相关文件, 请进行人工核验.') # 友好退出, 主要是在 Windows 环境里给予暂停 Common.exit_with_pause()
def requireText(self, options): print('-' * 70) Message.ShowSelect(options['tips'] + ':') result = input(options['prefix']) if not result: Message.ShowError('请至少输入一个字符. 程序终止') print('-' * 70) Common.exitWithPause(-1) result = options['prefix'] + result if options['upper']: result = result.upper() Message.ShowInfo('您输入的是: ' + result) print('-' * 70) print('\n') return result
def updateall(self, increase_version=True): ''' 更新全部翻译对照表文件, 并保留现有的翻译结果 ''' yamlfiles = glob.glob('../../conf/msg_conf/translation_*.yml') Message.ShowStatus('即将更新全部翻译对照表, 并保留现有的翻译结果...') if increase_version: Message.ShowInfo('对照表更新完成后会提升数据版本号.') else: Message.ShowWarning('本次对照表更新操作不会提升数据版本号.') for relpath in yamlfiles: fullpath = os.path.abspath(relpath) Message.ShowInfo('正在升级: %s' % os.path.relpath(fullpath, project_slndir)) _backup_body = self.body[:] self.updatefrom(fullpath, increase_version) if '_tw.yml' in relpath: for x in self.body: x['Translation'] = self.__convert_backslash_step1( x['Translation']) self.dump(fullpath) self.body = _backup_body Message.ShowStatus('感谢您的使用, 全部对照表翻译完毕.')
def updateall(self, increase_version=False): ''' 更新全部翻译对照表文件, 并保留现有的翻译结果 ''' yamlfiles = glob.glob('../../conf/msg_conf/translation_*.yml') Message.ShowStatus('即将更新全部翻译对照表, 并保留现有的翻译结果...') for relpath in yamlfiles: fullpath = os.path.abspath(relpath) Message.ShowInfo('正在升级: %s' % os.path.relpath(fullpath, project_slndir)) _backup_body = self.body[:] self.updatefrom(fullpath, increase_version) self.dump(fullpath) self.body = _backup_body Message.ShowStatus('感谢您的使用, 全部对照表翻译完毕.')
def requireInt(self, options): print('-' * 70) Message.ShowSelect(options['tips'] + ':') result = input(options['prefix']) if 'prefix' in options else input() if not result: if not ('allow_empty' in options and options['allow_empty']): Message.ShowError('请至少输入一个数字. 程序终止') print('-' * 70) Common.exit_with_pause(-1) result = '0' if not result.isdigit(): Message.ShowError('请输入一个数字而不是字符串. 程序终止') print('-' * 70) Common.exit_with_pause(-1) Message.ShowInfo('您输入的是: ' + result) print('-' * 70) print('') return int(result)
def requireText(self, options): print('-' * 70) Message.ShowSelect(options['tips'] + ':') prefix_val = options['prefix'] if 'prefix' in options else '' result = input(prefix_val) if not result: if 'default' in options and options['default']: result = options['default'] if not result and not ('allow_empty' in options and options['allow_empty']): Message.ShowError('请至少输入一个字符. 程序终止') print('-' * 70) Common.exit_with_pause(-1) result = prefix_val + result if 'upper' in options and options['upper']: result = result.upper() if 'lower' in options and options['lower']: result = result.lower() Message.ShowInfo('您输入的是: ' + result) print('-' * 70) print('') return result
def requireSelect(self, options): print('-' * 70) prompt = options['prompt'] option_name = options['option_name'] select_data = options['data'] Message.ShowSelect('请选择%s, 可选值为 [0~%d], 分别代表:' % (prompt, len(select_data) - 1)) print('') for select in select_data: Message.ShowMenu('%s' % select['desc']) print('') Message.ShowSelect('请选择%s [0~%d]:' % (prompt, len(select_data) - 1), end="") user_select = input() if not user_select or not user_select.isnumeric(): Message.ShowError( '您选择了无效的%s, 程序终止' % (option_name if option_name is not None else '选项')) print('-' * 70) Common.exit_with_pause(-1) user_select = int(user_select) if user_select < 0 or user_select >= len(select_data): Message.ShowError( '您选择了无效的%s, 程序终止' % (option_name if option_name is not None else '选项')) print('-' * 70) Common.exit_with_pause(-1) print('') Message.ShowInfo('您选择的是: %s' % select_data[user_select]['name']) print('-' * 70) print('') return user_select
def guide(inject): eventlist = [{ 'name': 'Event 类型的标准事件', 'desc': '0 - Event 类型的标准事件, 不能被 processhalt 指令打断' }, { 'name': 'Filter 类型的过滤事件', 'desc': '1 - Filter 类型的过滤事件, 可以被 processhalt 指令打断' }] # 0 为 Event 类型的事件 | 1 为 Filter 类型的事件 eventtype = InputController().requireSelect({ 'name': '想创建的 NPC 事件类型', 'data': eventlist }) # -------- constant_prefix = 'NPCE_' if eventtype == 0 else 'NPCF_' constant = InputController().requireText({ 'tips': '请输入该 NPC 事件的 {prefix} 常量名称 (自动大写, {prefix}的末尾部分)'.format( prefix=constant_prefix), 'prefix': constant_prefix, 'upper': True }) if eventtype == 0: define = 'rAthenaCN_NpcEvent_' + constant.replace(constant_prefix, '') eventvar = constant.replace(constant_prefix, '').lower() + '_event_name' elif eventtype == 1: define = 'rAthenaCN_NpcFilter_' + constant.replace(constant_prefix, '') eventvar = constant.replace(constant_prefix, '').lower() + '_filter_name' else: Message.ShowError('发现无效的事件类型, 请确认..') Common.exitWithPause(-1) # -------- eventname = InputController().requireText({ 'tips': '请输入该 NPC 事件的名称 (以 On 开头, 末尾应为 Event 或 Filter)', 'prefix': '' }) if not eventname.startswith('On'): Message.ShowError('无论是什么类型的事件, 事件名称必须以 On 开头 (严格区分大小写)') Common.exitWithPause(-1) if eventtype == 0: if not eventname.endswith('Event'): Message.ShowError('Event 类型的事件, 事件名称必须以 Event 结尾 (严格区分大小写)') Common.exitWithPause(-1) if eventtype == 1: if not eventname.endswith('Filter'): Message.ShowError('Filter 类型的事件, 事件名称必须以 Filter 结尾 (严格区分大小写)') Common.exitWithPause(-1) # -------- eventdesc = InputController().requireText({ 'tips': '请输入该 NPC 事件的简短说明 (如: 当玩家杀死 MVP 魔物时触发事件)', 'prefix': '' }) # -------- print('-' * 70) Message.ShowInfo('请确认建立的信息, 确认后将开始修改代码.') print('-' * 70) Message.ShowInfo('事件类型 : %s' % eventlist[eventtype]['name']) Message.ShowInfo('常量名称 : %s' % constant) Message.ShowInfo('事件名称 : %s' % eventname) Message.ShowInfo('事件说明 : %s' % eventdesc) print('') Message.ShowInfo('开关名称 : %s' % define) Message.ShowInfo('变量名称 : %s' % eventvar) print('-' * 70) print('\n') nextstep = InputController().requireBool({ 'tips': '请仔细阅读上述信息, 确认要开始写入操作么?', 'default': False }) if not nextstep: Message.ShowStatus('终止写入操作, 程序终止') Common.exitWithPause(-1) # -------- Message.ShowStatus('开始将 NPC 事件写入到源代码...') options = { 'define': define, 'constant': constant, 'eventname': eventname, 'eventvar': eventvar, 'eventdesc': eventdesc } if eventtype == 0: insert_for_normal_npcevent(inject, options) elif eventtype == 1: insert_for_filter_npcevent(inject, options) Message.ShowStatus('已经成功写入到源代码, 请检查并完善必要的注释.') print('') print('=' * 70) print('') print('感谢您的使用, NPC 事件添加助手已经执行完毕'.center(48)) print('') print('=' * 70)
def main(): ''' 主入口函数 ''' # 加载 .env 中的配置信息 load_dotenv(dotenv_path='.config.env', encoding='UTF-8') # 若无配置信息则自动复制一份文件出来 if not Common.is_file_exists('.config.env'): shutil.copyfile('.config.env.sample', '.config.env') # 显示欢迎信息 Common.welcome('编译流程辅助脚本') # 只能在 Windows 环境运行 if platform.system() != 'Windows': Message.ShowError('很抱歉, 此脚本只能在 Windows 环境上运行') Common.exit_with_pause(-1) # 判断本机是否安装了支持的 Visual Studio detected_vs, vs_name = detect_vs() if not detected_vs: Message.ShowError('无法检测到合适的 Visual Studio 版本 (2015 或 2017)') Common.exit_with_pause(-1) else: Message.ShowStatus('检测到已安装: %s 应可正常编译' % vs_name) print('') # 读取当前的 Pandas 主程序版本号 pandas_ver = Common.get_pandas_ver(os.path.abspath(project_slndir)) Message.ShowInfo('当前模拟器的主版本是 %s' % pandas_ver) # 判断是否已经写入了对应的更新日志, 若没有则要给予提示再继续 if (has_changelog(pandas_ver)): Message.ShowStatus('已经在更新日志中找到了 %s 的版本信息.' % pandas_ver) else: Message.ShowWarning('没有在更新日志中找到 %s 版本的信息, 请注意完善!' % pandas_ver) # 判断当前 git 工作区是否干净, 若工作区不干净要给予提示 if git.Repo(project_slndir).is_dirty(): if not Inputer().requireBool({ 'tips': '当前模拟器代码仓库的工作区不干净, 要继续编译吗?', 'default': False }): Message.ShowStatus('您主动放弃了继续操作') Common.exit_with_pause(-1) else: Message.ShowStatus('当前模拟器代码仓库的工作区是干净的.') # 检查 Crashrpt 使用的信息是否都设置好了, 若没有且企图编译正式版, 则给与提示 if Common.is_pandas_release(os.path.abspath(project_slndir)): if not os.getenv("DEFINE_CRASHRPT_APPID"): Message.ShowWarning('当前并未设置 AppID, 且企图编译正式版.') Common.exit_with_pause(-1) if Common.md5(os.getenv("DEFINE_CRASHRPT_APPID") ) != '952648de2d8f063a07331ae3827bc406': Message.ShowWarning('当前已设置了 AppID, 但并非正式版使用的 AppID.') Common.exit_with_pause(-1) if not os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): Message.ShowWarning('当前并未设置 PublicKey, 且企图编译正式版.') Common.exit_with_pause(-1) Message.ShowStatus('即将开始编译, 编译速度取决于电脑性能, 请耐心...') # 清理目前的工作目录, 把一些可明确移除的删掉 clean_environment() # 编译 Pandas 的复兴前版本 compile_prere(pandas_ver) # 编译 Pandas 的复兴后版本 compile_renewal(pandas_ver) Message.ShowStatus('编译工作已经全部结束, 请归档符号并执行打包流程.') # 友好退出, 主要是在 Windows 环境里给予暂停 Common.exit_with_pause()
def main(): ''' 主入口函数 ''' # 加载 .env 中的配置信息 load_dotenv(dotenv_path='.config.env', encoding='UTF-8') # 若无配置信息则自动复制一份文件出来 if not Common.is_file_exists('.config.env'): shutil.copyfile('.config.env.sample', '.config.env') # 显示欢迎信息 Common.welcome('打包流程辅助脚本') print('') pandas_ver = Common.get_pandas_ver(os.path.abspath(project_slndir)) Message.ShowInfo('当前模拟器的主版本是 %s' % pandas_ver) # 若环境变量为空则设置个默认值 if not os.getenv('DEFINE_PROJECT_NAME'): os.environ["DEFINE_PROJECT_NAME"] = "Pandas" if not os.getenv('DEFINE_COMPILE_MODE'): os.environ["DEFINE_COMPILE_MODE"] = "re,pre" Message.ShowInfo('当前输出的项目名称为: %s' % os.getenv('DEFINE_PROJECT_NAME')) # 检查是否已经完成了编译 if 're' in os.getenv('DEFINE_COMPILE_MODE').split(','): if not Common.is_compiled(project_slndir, checkmodel='re'): Message.ShowWarning('检测到打包需要的编译产物不完整, 请重新编译. 程序终止.') print('') Common.exit_with_pause(-1) if 'pre' in os.getenv('DEFINE_COMPILE_MODE').split(','): if not Common.is_compiled(project_slndir, checkmodel='pre'): Message.ShowWarning('检测到打包需要的编译产物不完整, 请重新编译. 程序终止.') print('') Common.exit_with_pause(-1) # 导出当前仓库, 变成一个归档压缩文件 Message.ShowInfo('正在将当前分支的 HEAD 内容导出成归档文件...') export_file = export() if not export_file: Message.ShowError('很抱歉, 导出归档文件失败, 程序终止.') Common.exit_with_pause(-1) Message.ShowInfo('归档文件导出完成, 此文件将在程序结束时被删除.') # 基于归档压缩文件, 进行打包处理 if 're' in os.getenv('DEFINE_COMPILE_MODE').split(','): process(export_file, renewal=True) if 'pre' in os.getenv('DEFINE_COMPILE_MODE').split(','): process(export_file, renewal=False) # 执行一些清理工作 clean(export_file) print('') Message.ShowInfo('已经成功打包相关文件, 请进行人工核验.') # 友好退出, 主要是在 Windows 环境里给予暂停 Common.exit_with_pause()
def guide(inject): define = Inputer().requireText({ 'tips' : '请输入该战斗配置选项的宏定义开关名称 (Pandas_BattleConfig_的末尾部分)', 'prefix' : 'Pandas_BattleConfig_' }) # -------- option_name = Inputer().requireText({ 'tips' : '请输入该战斗配置选项的选项名称' }) # -------- var_name = Inputer().requireText({ 'tips' : '请输入该战斗配置选项的变量名称 (不填默认与选项名称一致)', 'default' : option_name.replace('.', '_') }) # -------- def_val = Inputer().requireInt({ 'tips' : '请输入默认值 (不填则默认为 0)', 'allow_empty' : True }) # -------- min_val = Inputer().requireInt({ 'tips' : '请输入允许设置的最小值 (不填则默认为 0)', 'allow_empty' : True }) # -------- max_val = Inputer().requireInt({ 'tips' : '请输入允许设置的最大值 (不填则默认为 INT_MAX)', 'allow_empty' : True }) if max_val == 0: max_val = 2147483647 if max_val <= min_val: Message.ShowError('最大值比最小值还要小, 这不合理...') Common.exit_with_pause(-1) def_val = str(def_val) min_val = str(min_val) max_val = 'INT_MAX' if max_val == 2147483647 else str(max_val) # -------- print('-' * 70) Message.ShowInfo('请确认建立的信息, 确认后将开始修改代码.') print('-' * 70) Message.ShowInfo('开关名称 : %s' % define) Message.ShowInfo('选项名称 : %s' % option_name) Message.ShowInfo('变量名称 : %s' % var_name) print('') Message.ShowInfo('选项默认值 : %s' % def_val) Message.ShowInfo('选项最小值 : %s' % min_val) Message.ShowInfo('选项最大值 : %s' % max_val) print('-' * 70) print('\n') nextstep = Inputer().requireBool({ 'tips' : '请仔细阅读上述信息, 确认要开始写入操作么?', 'default' : False }) if not nextstep: Message.ShowStatus('终止写入操作, 程序终止') Common.exit_with_pause(-1) # -------- Message.ShowStatus('开始将战斗配置选项写入到源代码...') options = { 'define' : define, 'option_name' : option_name, 'var_name' : var_name, 'def_val' : def_val, 'min_val' : min_val, 'max_val' : max_val } insert_battle_config(inject, options) Message.ShowStatus('已经成功写入到源代码, 请检查并完善必要的注释.') print('') print('=' * 70) print('') print('感谢您的使用, 战斗配置选项添加助手已经执行完毕'.center(50)) print('') print('=' * 70)
def guide(inject): define = Inputer().requireText({ 'tips': '请输入该管理员指令的宏定义开关名称 (Pandas_AtCommand_的末尾部分)', 'prefix': 'Pandas_AtCommand_' }) # -------- funcname = Inputer().requireText({ 'tips': '请输入该管理员指令的处理函数名称 (ACMD_FUNC 部分的函数名)', 'lower': True }) # -------- samefunc = Inputer().requireBool({ 'tips': '管理员指令是否与处理函数名称一致 (%s)?' % funcname, 'default': True }) # -------- cmdname = funcname if not samefunc: cmdname = Inputer().requireText({ 'tips': '请输入该管理员指令的名称 (ACMD_DEF2 使用)', 'lower': True }) # -------- print('-' * 70) Message.ShowInfo('请确认建立的信息, 确认后将开始修改代码.') print('-' * 70) Message.ShowInfo('开关名称 : %s' % define) Message.ShowInfo('管理员指令处理函数名称 : %s' % funcname) Message.ShowInfo('管理员指令名称 : %s' % cmdname) print('-' * 70) print('\n') nextstep = Inputer().requireBool({ 'tips': '请仔细阅读上述信息, 确认要开始写入操作么?', 'default': False }) if not nextstep: Message.ShowStatus('终止写入操作, 程序终止') Common.exit_with_pause(-1) # -------- Message.ShowStatus('开始将管理员指令信息写入到源代码...') options = {'define': define, 'funcname': funcname, 'cmdname': cmdname} insert_atcmd(inject, options) Message.ShowStatus('已经成功写入到源代码, 请检查并完善必要的注释.') print('') print('=' * 70) print('') print('感谢您的使用, 管理员指令添加助手已经执行完毕'.center(48)) print('') print('=' * 70)
def main(): ''' 主入口函数 ''' # 加载 .env 中的配置信息 load_dotenv(dotenv_path='pyhelp.conf', encoding='UTF-8-SIG') # 若无配置信息则自动复制一份文件出来 if not Common.is_file_exists('pyhelp.conf'): shutil.copyfile('pyhelp.conf.sample', 'pyhelp.conf') # 显示欢迎信息 Common.welcome('编译流程辅助脚本') # 只能在 Windows 环境运行 if platform.system() != 'Windows': Message.ShowError('很抱歉, 此脚本只能在 Windows 环境上运行') Common.exit_with_pause(-1) # 判断本机是否安装了支持的 Visual Studio detected_vs, vs_name = detect_vs() if not detected_vs: Message.ShowError('无法检测到合适的 Visual Studio 版本 (2015 或 2017)') Common.exit_with_pause(-1) else: Message.ShowStatus('检测到已安装: %s 应可正常编译' % vs_name) print('') # 读取当前的 Pandas 主程序版本号 pandas_ver = get_pandas_ver() Message.ShowInfo('当前模拟器的主版本是 %s' % pandas_ver) # 判断是否已经写入了对应的更新日志, 若没有则要给予提示再继续 if (has_changelog(pandas_ver)): Message.ShowStatus('已经在更新日志中找到了 %s 的版本信息.' % pandas_ver) else: Message.ShowWarning('没有在更新日志中找到 %s 版本的信息, 请注意完善!' % pandas_ver) # 检查创建并尝试更新符号仓库 update_symstore() # 判断当前 git 工作区是否干净, 若工作区不干净要给予提示 if git.Repo(project_slndir).is_dirty(): if not Inputer().requireBool({ 'tips' : '当前模拟器代码仓库的工作区不干净, 要继续编译吗?', 'default' : False }): Message.ShowStatus('您主动放弃了继续操作') Common.exit_with_pause(-1) else: Message.ShowStatus('当前模拟器代码仓库的工作区是干净的.') Message.ShowStatus('即将开始编译, 编译速度取决于电脑性能, 请耐心...') # 清理目前的工作目录, 把一些可明确移除的删掉 clean_environment() # 编译 Pandas 的复兴前版本 compile_prere(pandas_ver) # 将复兴前版本的编译产物重命名一下, 避免编译复兴后版本时被覆盖 shutil.move(slndir('login-server.exe'), slndir('login-server-pre.exe')) shutil.move(slndir('login-server.pdb'), slndir('login-server-pre.pdb')) shutil.move(slndir('char-server.exe'), slndir('char-server-pre.exe')) shutil.move(slndir('char-server.pdb'), slndir('char-server-pre.pdb')) shutil.move(slndir('map-server.exe'), slndir('map-server-pre.exe')) shutil.move(slndir('map-server.pdb'), slndir('map-server-pre.pdb')) # 编译 Pandas 的复兴后版本 print('') compile_renewal(pandas_ver) print('') Message.ShowStatus('编译工作已经全部结束.') Message.ShowStatus('编译时产生的符号文件已存储, 记得提交符号文件.\n') # 友好退出, 主要是在 Windows 环境里给予暂停 Common.exit_with_pause(0)
def guide(inject): define = Inputer().requireText({ 'tips': '请输入该脚本指令的宏定义开关名称 (Pandas_ScriptCommand_的末尾部分)', 'prefix': 'Pandas_ScriptCommand_' }) # -------- funcname = Inputer().requireText({ 'tips': '请输入该脚本指令的处理函数名称 (BUILDIN_FUNC 部分的函数名)', 'lower': True }) # -------- samefunc = Inputer().requireBool({ 'tips': '脚本指令是否与处理函数名称一致 (%s)?' % funcname, 'default': True }) # -------- cmdname = funcname if not samefunc: cmdname = Inputer().requireText({ 'tips': '请输入该脚本指令的名称 (BUILDIN_DEF2 使用)', 'lower': True }) # -------- argsmode = Inputer().requireText({ 'tips': r'请输入该脚本指令的参数模式 (如一个或多个的: i\s\? 为空则直接回车)', 'lower': True, 'allow_empty': True }) # -------- print('-' * 70) Message.ShowInfo('请确认建立的信息, 确认后将开始修改代码.') print('-' * 70) Message.ShowInfo('开关名称 : %s' % define) Message.ShowInfo('脚本处理函数名称 : %s' % funcname) Message.ShowInfo('脚本指令名称 : %s' % cmdname) Message.ShowInfo('脚本指令的参数模式 : %s' % argsmode) print('-' * 70) print('\n') nextstep = Inputer().requireBool({ 'tips': '请仔细阅读上述信息, 确认要开始写入操作么?', 'default': False }) if not nextstep: Message.ShowStatus('终止写入操作, 程序终止') Common.exit_with_pause(-1) # -------- Message.ShowStatus('开始将脚本指令信息写入到源代码...') options = { 'define': define, 'funcname': funcname, 'cmdname': cmdname, 'argsmode': argsmode } insert_scriptcmd(inject, options) Message.ShowStatus('已经成功写入到源代码, 请检查并完善必要的注释.') print('') print('=' * 70) print('') print('感谢您的使用, 脚本指令添加助手已经执行完毕'.center(48)) print('') print('=' * 70)
def guide(inject): define = Inputer().requireText({ 'tips': '请输入该地图标记的宏定义开关名称 (Pandas_MapFlag_的末尾部分)', 'prefix': 'Pandas_MapFlag_' }) # -------- constant = Inputer().requireText({ 'tips': '请输入该地图标记的 MF 常量名称 (自动大写, MF_的末尾部分)', 'prefix': 'MF_', 'upper': True }) # -------- flaglist = [{ 'name': '普通开关式的地图标记', 'desc': '0 - 普通的地图标记开关, 只有两个状态(开/关)' }, { 'name': '携带单个数值参数的地图标记', 'desc': '1 - 携带单个数值参数的地图标记, 可以记录数值变量 (例如 bexp 标记)' }] # flagtype = 0 # 0 为普通开关 | 1 为数值开关 flagtype = Inputer().requireSelect({ 'prompt': '想创建的地图标记类型', 'option_name': '地图标记类型', 'data': flaglist }) # -------- default_val = 0 if flagtype == 1: default_val = Inputer().requireInt({ 'tips': '请输入"第一个数值参数"的默认值 (不填则默认为 0)', 'allow_empty': True }) # -------- default_disable = False if flagtype == 1: default_disable = Inputer().requireBool({ 'tips': '当"第一个数值参数"的值为 %d 时, 是否表示移除此地图标记?' % default_val, 'default': False }) # -------- print('-' * 70) Message.ShowInfo('请确认建立的信息, 确认后将开始修改代码.') print('-' * 70) Message.ShowInfo('开关名称 : %s' % define) Message.ShowInfo('常量名称 : %s' % constant) Message.ShowInfo('标记类型 : %s' % flaglist[flagtype]['name']) print('') Message.ShowInfo('第一个数值参数的默认值 : %d' % default_val) Message.ShowInfo('第一个数值参数的值为 %d 时, 是否禁用此标记 : %s' % (default_val, default_disable)) print('-' * 70) print('\n') nextstep = Inputer().requireBool({ 'tips': '请仔细阅读上述信息, 确认要开始写入操作么?', 'default': False }) if not nextstep: Message.ShowStatus('终止写入操作, 程序终止') Common.exit_with_pause(-1) # -------- Message.ShowStatus('开始将地图标记信息写入到源代码...') options = { 'flagtype': flagtype, 'define': define, 'constant': constant, 'default_val': default_val, 'default_disable': default_disable } if flagtype == 0: insert_for_normal_mapflag(inject, options) elif flagtype == 1: insert_for_one_param_mapflag(inject, options) Message.ShowStatus('已经成功写入到源代码, 请检查并完善必要的注释.') print('') print('=' * 70) print('') print('感谢您的使用, 地图标记添加助手已经执行完毕'.center(48)) print('') print('=' * 70)