def __searchMark(self, filename): line_num = 0 charset = self.__detectCharset(filename) regex = r'\s*?' + self.__options__['mark_format'] + r'\s*?' if '../../src/'.replace('/', os.path.sep) in filename and charset.upper() != 'UTF-8-SIG': Message.ShowWarning('期望文件 %s 的编码为 UTF-8-SIG 而实际上是 %s' % (filename, charset.upper())) return try: textfile = open(filename, encoding=charset) for line in textfile: line_num = line_num + 1 if '//' not in line: continue re_match = re.match(regex, line) if not re_match: continue if str(re_match.group(1)) in self.mark_dict: Message.ShowError('发现重复的代码注入标记: ' + re_match.group(0)) Common.exit_with_pause(-1) self.mark_dict[re_match.group(1)] = { 'index' : int(re_match.group(1)), 'filepath' : filename, 'line' : line_num } textfile.close() except Exception as err: Message.ShowError('文件 : %s | 错误信息 : %s' % (filename, err))
def process_sub(export_file, renewal, langinfo): print('') # 确认当前的版本号 version = Common.get_pandas_ver(os.path.abspath(project_slndir), 'v') Message.ShowStatus('正在准备生成 {model} - {lang} 的打包目录...'.format( model = '复兴后(RE)' if renewal else '复兴前(PRE)', lang = langinfo['name'] )) # 构建解压的打包目录 packagedir = '../Release/Pandas/{version}/Pandas_{version}_{timestamp}_{model}_{lang}'.format( version = version, model = 'RE' if renewal else 'PRE', timestamp = Common.timefmt(True), lang = langinfo['dirname'] ) # 获取压缩文件的保存路径 zipfilename = os.path.abspath(project_slndir + packagedir) + '.zip' # 获取打包的绝对路径 packagedir = os.path.abspath(project_slndir + packagedir) + os.path.sep # 确保目标文件夹存在 os.makedirs(os.path.dirname(packagedir), exist_ok = True) # 若之前目录已经存在, 先删掉 if os.path.exists(packagedir) and os.path.isdir(packagedir): shutil.rmtree(packagedir) # 将 zip 文件解压到指定的目录中去 Message.ShowStatus('正在解压归档文件到: %s' % os.path.relpath( packagedir, os.path.abspath(os.path.join(packagedir, r'../../')) )) if not zip_unpack(export_file, packagedir): clean(export_file) Message.ShowError('很抱歉, 解压归档文件失败, 程序终止.') Common.exit_with_pause(-1) # 进行文本的翻译工作 trans.process(packagedir, langinfo['trans'], True) # 进行后期处理 Message.ShowStatus('正在对打包源目录进行后期处理...') if renewal: arrange_renewal(packagedir) else: arrange_pre_renewal(packagedir) Message.ShowStatus('后期处理完毕, 即将把打包源压缩成 ZIP 文件...') # 执行打包操作 if not zip_pack(packagedir, zipfilename): clean(export_file) Message.ShowError('打包成 zip 文件时失败了, 请联系开发者协助定位问题, 程序终止.') Common.exit_with_pause(-1) Message.ShowStatus('已成功构建 {model} - {lang} 的压缩文件.'.format( model = '复兴后(RE)' if renewal else '复兴前(PRE)', lang = langinfo['name'] ))
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 compile_renewal(version): ''' 编译复兴后版本 ''' time.sleep(3) print('') define_options = {} if os.getenv("DEFINE_CRASHRPT_APPID"): define_options["CRASHRPT_APPID"] = '_CT(\\"%s\\")' % os.getenv( "DEFINE_CRASHRPT_APPID") if os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): define_options["CRASHRPT_PUBLICKEY"] = '_CT(\\"%s\\")' % os.getenv( "DEFINE_CRASHRPT_PUBLICKEY") define_options["GIT_BRANCH"] = '\\"%s\\"' % Common.get_pandas_branch( project_slndir) define_options["GIT_HASH"] = '\\"%s\\"' % Common.get_pandas_hash( project_slndir) define_values = define_builder(define_options) if not compile_sub(define_values, '复兴后', version): Message.ShowError('编译复兴前版本时发生了一些错误, 请检查...') Common.exit_with_pause(-1) print('')
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 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 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 compile_renewal(version): ''' 编译复兴后版本 ''' time.sleep(3) print('') define_options = {} if os.getenv("DEFINE_CRASHRPT_APPID"): define_options["CRASHRPT_APPID"] = '\\"%s\\"' % os.getenv( "DEFINE_CRASHRPT_APPID") if os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): define_options["CRASHRPT_PUBLICKEY"] = '\\"%s\\"' % os.getenv( "DEFINE_CRASHRPT_PUBLICKEY") define_options["GIT_BRANCH"] = '\\"%s\\"' % Common.get_pandas_branch( project_slndir) define_options["GIT_HASH"] = '\\"%s\\"' % Common.get_pandas_hash( project_slndir) define_values = define_builder(define_options) if not compile_sub(define_values, '复兴后', version): Message.ShowError('编译复兴前版本时发生了一些错误, 请检查...') Common.exit_with_pause(-1) # 将之前 compile_prere 中临时重命名的复兴前产物全部改回正常的文件名 if 'pre' in os.getenv('DEFINE_COMPILE_MODE').split(','): move_product_files('-pre-t', '-pre') print('')
def compile_prere(version): ''' 编译复兴前版本 ''' time.sleep(3) print('') define_options = { "PRERE": "" } if os.getenv("DEFINE_CRASHRPT_APPID"): define_options["CRASHRPT_APPID"] = '\\"%s\\"' % os.getenv("DEFINE_CRASHRPT_APPID") if os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): define_options["CRASHRPT_PUBLICKEY"] = '\\"%s\\"' % os.getenv("DEFINE_CRASHRPT_PUBLICKEY") define_options["GIT_BRANCH"] = '\\"%s\\"' % Common.get_pandas_branch(project_slndir) define_options["GIT_HASH"] = '\\"%s\\"' % Common.get_pandas_hash(project_slndir) define_values = define_builder(define_options) if not compile_sub(define_values, '复兴前', version): Message.ShowError('编译复兴前版本时发生了一些错误, 请检查...') Common.exit_with_pause(-1) # 将复兴前版本的编译产物重命名一下, 避免编译复兴后版本时被覆盖 # 因 ab7a827 的修改每次清理工程时, 也会同时清理复兴前的编译产物, 所以这里需要临时重命名 shutil.move(slndir('login-server.exe'), slndir('login-server-pre-t.exe')) shutil.move(slndir('login-server.pdb'), slndir('login-server-pre-t.pdb')) shutil.move(slndir('char-server.exe'), slndir('char-server-pre-t.exe')) shutil.move(slndir('char-server.pdb'), slndir('char-server-pre-t.pdb')) shutil.move(slndir('map-server.exe'), slndir('map-server-pre-t.exe')) shutil.move(slndir('map-server.pdb'), slndir('map-server-pre-t.pdb')) print('')
def detect(self, src_dir): if isinstance(src_dir, str): src_dir = [src_dir] for single_dir in src_dir: for dirpath, _dirnames, filenames in os.walk(single_dir): for filename in filenames: _base_name, extension_name = os.path.splitext(filename.lower()) if extension_name not in self.__options__['process_exts']: continue fullpath = os.path.normpath('%s/%s' % (dirpath, filename)) self.__searchMark(fullpath) bMarkPassed = True for configure in self.__options__['mark_configure']: if str(int(configure['id'])) not in self.mark_dict: Message.ShowError('无法定位代码注入点: {index} : {constant} : {desc}'.format( index = str(int(configure['id'])), constant = str(configure['id']), desc = configure['desc'] )) bMarkPassed = False return bMarkPassed
def compile_sub(define_val, name, version, scheme='Release|Win32'): ''' 用于执行编译 ''' # 获取第一个支持的 Visual Studio 对应的 vcvarsall 路径 vcvarsall = get_vcvarsall_path() # 根据名称确定一下标记 modetag = ('RE' if name == '复兴后' else 'PRE') # 执行编译 Common.cmd_execute([ '"%s" x86' % vcvarsall, 'set CL=%s' % define_val, 'Devenv rAthena.sln /clean', 'Devenv rAthena.sln /Rebuild "%s"' % scheme ], project_slndir, modetag, slndir(compile_logfile)) # 编译完成后, 判断编译是否成功 result, succ, faild, _skip = get_compile_result() if not result: Message.ShowError('无法获取 %s 的编译结果' % name) return False # 若成功, 则进行符号文件的存储 if result and int(succ) > 1 and int(faild) == 0: return True else: Message.ShowWarning('%s: 存在编译失败的工程, 请进行检查...' % modetag) return False
def compile_renewal(version): ''' 编译复兴后版本 ''' time.sleep(3) print('') define_options = {} if os.getenv("DEFINE_CRASHRPT_APPID"): define_options["CRASHRPT_APPID"] = '\\"%s\\"' % os.getenv("DEFINE_CRASHRPT_APPID") if os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): define_options["CRASHRPT_PUBLICKEY"] = '\\"%s\\"' % os.getenv("DEFINE_CRASHRPT_PUBLICKEY") define_options["GIT_BRANCH"] = '\\"%s\\"' % Common.get_pandas_branch(project_slndir) define_options["GIT_HASH"] = '\\"%s\\"' % Common.get_pandas_hash(project_slndir) define_values = define_builder(define_options) if not compile_sub(define_values, '复兴后', version): Message.ShowError('编译复兴前版本时发生了一些错误, 请检查...') Common.exit_with_pause(-1) # 将之前 compile_prere 中临时重命名的复兴前产物全部改回正常的文件名 shutil.move(slndir('login-server-pre-t.exe'), slndir('login-server-pre.exe')) shutil.move(slndir('login-server-pre-t.pdb'), slndir('login-server-pre.pdb')) shutil.move(slndir('char-server-pre-t.exe'), slndir('char-server-pre.exe')) shutil.move(slndir('char-server-pre-t.pdb'), slndir('char-server-pre.pdb')) shutil.move(slndir('map-server-pre-t.exe'), slndir('map-server-pre.exe')) shutil.move(slndir('map-server-pre-t.pdb'), slndir('map-server-pre.pdb')) print('')
def process(project_dir, lang='zh-cn', silent=False): try: for v in configures: operate_params = v['operate_params'] operate_params['lang'] = lang operate_params['project_dir'] = project_dir operate_params['silent'] = silent operate = globals()[v['operate']](**operate_params) if 'filepath' in v: for path in v['filepath']: fullpath = os.path.abspath(project_dir + path) operate.execute(fullpath) if 'globpath' in v: for path in v['globpath']: files = glob.glob(os.path.abspath(project_dir + path), recursive=True) for x in files: relpath = os.path.relpath(x, project_dir).replace( '\\', '/') is_exclude = False if 'globexclude' in v: for e in v['globexclude']: if e in relpath: is_exclude = True break if not is_exclude: operate.execute(x) except Exception as _err: Message.ShowError(str(_err)) Common.exit_with_pause(-1)
def __encoding_check(self, text, encoding, line): try: for i, element in enumerate(text): element.encode(encoding) except Exception as _err: Message.ShowError( '%s 第 %-5d 行中的 "%s" 字符不存在于 "%s" 编码中, 此错误必须被消除' % (os.path.relpath(self.__filename), line, element, encoding))
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 __init__(self, options): self.__options__ = options self.mark_dict = {} if not self.detect(self.__options__['source_dirs']): Message.ShowError('无法成功定位所有需要的代码注入点, 程序终止!') Common.exit_with_pause(-1) else: Message.ShowStatus('已成功定位所有代码注入点.\n')
def versionFormat(self, version, vmode): ver_fields = [] if '.' in version: ver_fields = version.split('.') elif ',' in version: ver_fields = version.split(',') else: Message.ShowError('您传入的版本号格式不正确: %s' % version) Common.exit_with_pause(-1) if vmode == '.': return '.'.join(ver_fields) elif vmode == ',': return ','.join(ver_fields) elif vmode == 'fmt': return 'v%s.%s.%s%s' % (ver_fields[0], ver_fields[1], ver_fields[2], '-dev' if ver_fields[3] == '1' else '') else: Message.ShowError('您传入的 vmode 版本号格式不正确: %s' % vmode) Common.exit_with_pause(-1) return version
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 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 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 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 compile_prere(version): ''' 编译复兴前版本 ''' time.sleep(3) print('') define_options = {"PRERE": ""} if os.getenv("DEFINE_CRASHRPT_APPID"): define_options["CRASHRPT_APPID"] = '\\"%s\\"' % os.getenv( "DEFINE_CRASHRPT_APPID") if os.getenv("DEFINE_CRASHRPT_PUBLICKEY"): define_options["CRASHRPT_PUBLICKEY"] = '\\"%s\\"' % os.getenv( "DEFINE_CRASHRPT_PUBLICKEY") define_options["GIT_BRANCH"] = '\\"%s\\"' % Common.get_pandas_branch( project_slndir) define_options["GIT_HASH"] = '\\"%s\\"' % Common.get_pandas_hash( project_slndir) define_values = define_builder(define_options) if not compile_sub(define_values, '复兴前', version): Message.ShowError('编译复兴前版本时发生了一些错误, 请检查...') Common.exit_with_pause(-1) # 将复兴前版本的编译产物重命名一下, 避免编译复兴后版本时被覆盖 # 因 ab7a827 的修改每次清理工程时, 也会同时清理复兴前的编译产物, 所以这里需要临时重命名 if 're' in os.getenv('DEFINE_COMPILE_MODE').split(','): move_product_files('', '-pre-t') else: move_product_files('', '-pre') print('')
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): 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='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)