class LeeLua: def __init__(self): self.leeCommon = LeeCommon() self.sourceDirectory = None self.outputDirectory = None self.grfCLFilepath = None self.baseDirectory = None def __getOutputFilePath(self, sourcePath): relpath = os.path.relpath(sourcePath, self.sourceDirectory) outputpath = os.path.abspath( '%s%s%s' % (self.outputDirectory, os.path.sep, relpath)) return outputpath def isTrulyLubFile(self, filepath): rawfile = open(filepath, 'rb') magicHeader = rawfile.read(6) rawfile.close() return (magicHeader[0] == 0x1B and magicHeader[1] == 0x4C and magicHeader[2] == 0x75 and magicHeader[3] == 0x61 and magicHeader[4] == 0x51 and magicHeader[5] == 0x00) def __replaceFunctionStruct(self, line): matches = re.match(r'^(\w*?)\s=\sfunction\((.*?)\)(.*?)$', line) if not matches: return line return 'function {funname}({params})'.format(funname=matches.group(1), params=matches.group(2)) def __removeFunctionNote(self, line): if line.startswith('-- Function #'): return None return line def __lubAmendmentsByFile(self, filename, content): # 移除 GRF Editor Decompiler 标记 markRemoveIndex = [] for index, line in enumerate(content): if re.match('^-- Using GRF Editor Decompiler.*?$', line): content[index] = None markRemoveIndex.append(index + 1) if index in markRemoveIndex: content[index] = None # 若文件的末尾没有空行的话, 补加一个空行 if not content: content.append('') if str(content[-1]).strip() != '' and not str( content[-1]).endswith('\n'): content.append('') # if filename.lower() == 'kaframovemapservicelist.lub': # pass content = [x for x in content if x is not None] return content def lubAmendments(self, srcfilepath, dstfilepath): encoding = self.leeCommon.getEncodingByFile(srcfilepath) encoding = 'latin1' if encoding is None else encoding try: luafile = open(srcfilepath, 'r', encoding=encoding, newline='') content = luafile.readlines() luafile.close() # 按行进行处理 content = [ x.replace('\r\n', '\n').replace('\n', '') for x in content ] for index, line in enumerate(content): line = self.__replaceFunctionStruct(line) line = self.__removeFunctionNote(line) content[index] = line content = [x for x in content if x is not None] # 按文件进行处理 content = self.__lubAmendmentsByFile(os.path.basename(srcfilepath), content) savefile = open(dstfilepath, 'w', encoding=encoding, newline='') savefile.write('\r\n'.join(content)) savefile.close() return True except Exception as _err: print('对 lub 文件进行处理时发生错误: %s' % srcfilepath) raise def amendmentsDir(self, lubSourceDirectory, lubOutputDirectory): self.sourceDirectory = lubSourceDirectory self.outputDirectory = lubOutputDirectory self.baseDirectory = os.path.dirname(self.sourceDirectory) for dirpath, _dirnames, filenames in os.walk(lubSourceDirectory): for filename in filenames: fullpath = os.path.normpath('%s/%s' % (dirpath, filename)) destpath = self.__getOutputFilePath(fullpath) os.makedirs(os.path.dirname(destpath), exist_ok=True) if fullpath.lower().endswith( '.lub') and not self.isTrulyLubFile(fullpath): self.lubAmendments(fullpath, destpath) print('整理完毕: ' + os.path.relpath(fullpath, self.baseDirectory)) else: shutil.copyfile(fullpath, destpath) print('已经复制: ' + os.path.relpath(fullpath, self.baseDirectory)) def getLubEncoding(self, filepath): if not self.isTrulyLubFile(filepath): return True, self.leeCommon.getEncodingByFile(filepath) else: return False, None def decodeFile(self, lubSourcePath, lubOutputPath): grfCLProc = subprocess.Popen( '%s %s' % (self.grfCLFilepath, '-breakOnExceptions true -lub "%s" "%s"' % (lubSourcePath, lubOutputPath)), stdout=subprocess.PIPE, cwd=os.path.dirname(self.grfCLFilepath)) grfCLProc.wait() # 确认结果并输出提示信息表示反编译结束 if grfCLProc.returncode == 0 and self.leeCommon.isFileExists( lubOutputPath): print('已输出到: ' + os.path.relpath(lubOutputPath, self.baseDirectory)) self.lubAmendments(lubOutputPath, lubOutputPath) return True print('进行反编译时发生错误: ' + os.path.relpath(lubSourcePath, self.baseDirectory)) return False def decodeDir(self, lubSourceDirectory, lubOutputDirectory): # 记录到成员变量里面 self.sourceDirectory = lubSourceDirectory self.outputDirectory = lubOutputDirectory self.baseDirectory = os.path.dirname(self.sourceDirectory) # 确认操作系统平台 if platform.system() != 'Windows': self.leeCommon.exitWithMessage('很抱歉, 此功能目前只能在 Windows 平台上运行.') # 确认 GrfCL 所需要的 .net framework 已安装 if not self.leeCommon.isDotNetFrameworkInstalled('v3.5'): print('您必须先安装微软的 .NET Framework v3.5 框架.') self.leeCommon.exitWithMessage( '下载地址: https://www.microsoft.com/zh-CN/download/details.aspx?id=21' ) # 确认 GrfCL 文件存在 scriptDir = self.leeCommon.utility(withmark=False) self.grfCLFilepath = ('%s/Bin/GrfCL/GrfCL.exe' % scriptDir).replace( '/', os.path.sep) if not self.leeCommon.isFileExists(self.grfCLFilepath): self.leeCommon.exitWithMessage( '反编译 lub 文件所需的 GrfCL.exe 程序不存在, 无法执行反编译.') for dirpath, _dirnames, filenames in os.walk(lubSourceDirectory): for filename in filenames: fullpath = os.path.normpath('%s/%s' % (dirpath, filename)) destpath = self.__getOutputFilePath(fullpath) os.makedirs(os.path.dirname(destpath), exist_ok=True) print('') if fullpath.lower().endswith('.lub') and self.isTrulyLubFile( fullpath): print('需反编译: ' + os.path.relpath(fullpath, self.baseDirectory)) if not self.decodeFile(fullpath, destpath): print('失败复制: ' + os.path.relpath(fullpath, self.baseDirectory)) shutil.copyfile(fullpath, destpath) else: print('直接复制: ' + os.path.relpath(fullpath, self.baseDirectory)) shutil.copyfile(fullpath, destpath)
class LeeGrf: def __init__(self): self.leeCommon = LeeCommon() self.patchManager = LeePatchManager() def isGrfExists(self): leeClientDir = self.leeCommon.client(withmark=False) grfFiles = glob.glob('%s/*.grf' % leeClientDir) return len(grfFiles) > 0 def makeGrf(self, dataDirpath, grfOutputPath): # 确认操作系统平台 if platform.system() != 'Windows': self.leeCommon.exitWithMessage('很抱歉, 此功能目前只能在 Windows 平台上运行.') # 确认 GrfCL 所需要的 .net framework 已安装 if not self.leeCommon.isDotNetFrameworkInstalled('v3.5'): print('您必须先安装微软的 .NET Framework v3.5 框架.') self.leeCommon.exitWithMessage( '下载地址: https://www.microsoft.com/zh-CN/download/details.aspx?id=21' ) # 确认已经切换到了需要的客户端版本 if not self.patchManager.canRevert(): self.leeCommon.exitWithMessage( '请先将 LeeClient 切换到某个客户端版本, 以便制作出来的 grf 文件内容完整.') # 确认有足够的磁盘剩余空间进行压缩 currentDriver = self.leeCommon.utility()[0] currentFreeSpace = self.leeCommon.getDiskFreeSpace(currentDriver) if currentFreeSpace <= 1024 * 1024 * 1024 * 3: self.leeCommon.exitWithMessage('磁盘 %s: 的空间不足 3GB, 请清理磁盘释放更多空间.' % currentDriver) # 确认 GrfCL 文件存在 scriptDir = self.leeCommon.utility(withmark=False) grfCLFilepath = ('%s/Bin/GrfCL/GrfCL.exe' % scriptDir).replace( '/', os.path.sep) if not self.leeCommon.isFileExists(grfCLFilepath): self.leeCommon.exitWithMessage( '制作 grf 文件所需的 GrfCL.exe 程序不存在, 无法执行压缩.') # data.grf 文件若存在则进行覆盖确认 if self.leeCommon.isFileExists(grfOutputPath): lines = [ '发现客户端目录中已存在 %s 文件,' % os.path.basename(grfOutputPath), '若继续将会先删除此文件, 为避免文件被误删, 请您进行确认.' ] title = '文件覆盖提示' prompt = '是否删除文件并继续?' if not self.leeCommon.confirm(lines, title, prompt, None, None, None): self.leeCommon.exitWithMessage('由于您放弃继续, 程序已自动终止.') os.remove(grfOutputPath) # 执行压缩工作(同步等待) grfCLProc = subprocess.Popen( '%s %s' % (grfCLFilepath, '-breakOnExceptions true -makeGrf "%s" "%s"' % (os.path.relpath(grfOutputPath, os.path.dirname(grfCLFilepath)), os.path.relpath(dataDirpath, os.path.dirname(grfCLFilepath)))), stdout=sys.stdout, cwd=os.path.dirname(grfCLFilepath)) grfCLProc.wait() # 确认结果并输出提示信息表示压缩结束 if grfCLProc.returncode == 0 and self.leeCommon.isFileExists( grfOutputPath): print('已经将 data 目录压缩为 data.grf 并存放到根目录.') print('') self.leeCommon.printSmallCutLine() print('') else: self.leeCommon.exitWithMessage('进行压缩工作的时候发生错误, 请发 Issue 进行反馈.')