local bit32 = (bit32 or require("bit")) -- 一个缓存文件 local CacheFile = defClass("CacheFile" , defVar("origin" , VT_String) , defVar("name" , VT_String) , defVar("md5" , VT_String) , defVar("originSize" , VT_Double) , defVar("compileSize" , VT_Double) , defVar("encryptSize" , VT_Double) , defVar("compressedSize" , VT_Double) , defVar("modifyTime" , VT_Double) , defVar("compressedFile" , VT_String) , defVar("encryptFile" , VT_String) ); -- 一组缓存文件 local CacheFileList = defClass("CacheFileList" , defVar("list" , VT_Map(VT_String , CacheFile)) ); -- 保存所有缓存的文件 gCacheFiles = CacheFileList:new(); -- 所有配置文件的缓存 gConfigDescCacheFiles = nil -- 保存所有的xml文件对应的desc解析文件 gConfigXmlToDesc = {} local function getNextPowerOfTwo(value) local i = 1; while i < value do i = i * 2; end return i; end local function isPow2(size) return getNextPowerOfTwo(size) == size; end -- 载入文件数据 function loadfileData(filename) local fileData; -- 读取整个文件数据 local file = io.open(filename , "rb"); fileData = file:read("*a"); file:close(); return fileData; end --/* These describe the color_type field in png_info. */ --/* color type masks */ PNG_COLOR_MASK_PALETTE = 1 PNG_COLOR_MASK_COLOR = 2 PNG_COLOR_MASK_ALPHA = 4 --/* color types. Note that not all combinations are legal */ PNG_COLOR_TYPE_GRAY = 0 PNG_COLOR_TYPE_PALETTE = (PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_PALETTE) PNG_COLOR_TYPE_RGB = (PNG_COLOR_MASK_COLOR) PNG_COLOR_TYPE_RGB_ALPHA = (PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA) PNG_COLOR_TYPE_GRAY_ALPHA =(PNG_COLOR_MASK_ALPHA) -- 编译png文件成pvr文件,并返回pvr文件名 local function _compilePngToPvr(sourceFile) local pathName , baseName , ext = string.splitFilename(sourceFile); -- 只打包这三个目录 if not (string.startsWith(pathName , "res/effect/") or string.startsWith(pathName , "res/animation/") or string.startsWith(pathName , "res/scene/")) then return sourceFile; end local image = cc.Image:analysisPngFile(sourceFile); -- PVR转换规则,长宽相等,大小是2次幂。 if image.image_width ~= image.image_height then return sourceFile; end -- 不是2次幂 if not isPow2(image.image_width) or not isPow2(image.image_height) then return sourceFile; end -- 最小8*8 if image.image_width < 8 or image.image_height < 8 then return sourceFile; end local pvrFormat; print("image" , table.tostring(image)); -- 根据纹理格式来决定pvr格式 if image.color_type == PNG_COLOR_TYPE_RGB then pvrFormat = "PVRTC1_4_RGB"; elseif image.color_type == PNG_COLOR_TYPE_RGB_ALPHA then pvrFormat = "PVRTC1_4"; elseif image.color_type == PNG_COLOR_TYPE_GRAY_ALPHA then pvrFormat = "PVRTC1_2"; elseif image.color_type == PNG_COLOR_TYPE_GRAY then pvrFormat = "PVRTC1_2_RGB"; elseif image.color_type == PNG_COLOR_TYPE_PALETTE then if image.expand_color_type == PNG_COLOR_TYPE_RGB_ALPHA then print("调色板带透明"); pvrFormat = "PVRTC1_4"; else print("调色板不带透明"); pvrFormat = "PVRTC1_2_RGB"; end else return sourceFile; end local pvrFile = "cache/" .. baseName .. "." .. pvrFormat .. ".pvr"; local exFlags = ""; -- 场景光效人物,要用mipmap --exFlags = exFlags .. " -m"; local cmdLine = string.format('PVRTexTool -i "%s" -o "%s" -f "%s"%s' , sourceFile , pvrFile , pvrFormat , exFlags); local out = io.popen(cmdLine , "r"); print("正在转换成pvr:" .. cmdLine); print(out:read("*a")); out:close(); local atts = lfs.attributes(pvrFile , "modification"); if not atts then error("转换pvr失败" .. sourceFile); return sourceFile; end return pvrFile; end -- 编译png文件成pvr文件,并返回pvr文件数据 local function compilePngToPvr(sourceFile) local fileName = _compilePngToPvr(sourceFile); return loadfileData(fileName); end -- 编译png文件成etc文件,并返回etc文件名 local function _compilePngToEtc(sourceFile) local pathName , baseName , ext = string.splitFilename(sourceFile); -- 只打包这三个目录 if not (string.startsWith(pathName , "res/effect/") or string.startsWith(pathName , "res/animation/") or string.startsWith(pathName , "res/scene/")) then return sourceFile; end local image = cc.Image:analysisPngFile(sourceFile); -- 不是2次幂 if not isPow2(image.image_width) or not isPow2(image.image_height) then return sourceFile; end -- 最小8*8 if image.image_width < 8 or image.image_height < 8 then return sourceFile; end local etcFormat; -- 根据纹理格式来决定etc格式 if image.expand_color_type == PNG_COLOR_TYPE_RGB or image.expand_color_type == PNG_COLOR_TYPE_GRAY then etcFormat = "ETC1"; else return sourceFile; end local etcFile = "cache/" .. baseName .. "." .. etcFormat .. ".pvr"; local exFlags = ""; -- 场景光效人物,要用mipmap --exFlags = exFlags .. " -m"; local cmdLine = string.format('PVRTexTool -i "%s" -o "%s" -f "%s"%s' , sourceFile , etcFile , etcFormat , exFlags); local out = io.popen(cmdLine , "r"); print("正在转换成etc:" .. cmdLine); print(out:read("*a")); out:close(); local atts = lfs.attributes(etcFile , "modification"); if not atts then error("转换etc失败" .. sourceFile); return sourceFile; end return etcFile; end -- 编译png文件成etc文件,并返回etc文件数据 local function compilePngToEtc(sourceFile) local fileName = _compilePngToEtc(sourceFile); return loadfileData(fileName); end -- 编译png文件成etc文件,并返回etc文件名 local function _compilePngToAtc(sourceFile) local pathName , baseName , ext = string.splitFilename(sourceFile); if string.startsWith(pathName , "res/scene/scene_maoxian_002") then print("res/scene/scene_maoxian_002不能压缩纹理,文件名" .. sourceFile); return sourceFile; end -- 只打包这三个目录 if not (string.startsWith(pathName , "res/effect/") or string.startsWith(pathName , "res/animation/") or string.startsWith(pathName , "res/ui/") or string.startsWith(pathName , "res/scene/"))then print("指定目录之外的纹理不需要压缩,文件名" .. sourceFile); return sourceFile; end local image = cc.Image:analysisPngFile(sourceFile); -- 最小8*8 if image.image_width < 8 or image.image_height < 8 then print("长宽小于8不能压缩纹理,文件名" .. sourceFile); return sourceFile; end local etcFormat; -- 根据纹理格式来决定atc格式 if image.color_type == PNG_COLOR_TYPE_RGB or image.expand_color_type == PNG_COLOR_TYPE_RGB then etcFormat = "RGB"; elseif image.color_type == PNG_COLOR_TYPE_RGB_ALPHA or image.expand_color_type == PNG_COLOR_TYPE_RGB_ALPHA then etcFormat = "RGBA" else print("Texture color type is", image.color_type) print("Texture expand color type is", image.expand_color_type) print("纹理格式不是RGB或者是RGBA格式,不能转换成压缩纹理,文件名" .. sourceFile); return sourceFile; end -- local atcFile = "cache/" .. baseName .. "." .. etcFormat .. ".atc"; local cmdLine = string.format('atc_texture "%s" "%s"' , sourceFile , atcFile); local out = io.popen(cmdLine , "r"); print("正在转换成atc:" .. cmdLine); print(out:read("*a")); out:close(); local atts = lfs.attributes(atcFile , "modification"); if not atts then error("转换atc失败" .. sourceFile); return sourceFile; end return atcFile; end -- 编译png文件成atc文件,并返回atc文件数据 local function compilePngToAtc(sourceFile) local fileName = _compilePngToAtc(sourceFile); return loadfileData(fileName); end -- 编译lua文件,并返回编译后的数据 function compileLua52(filename) -- 编译lua print("正在编译Lua52:" , filename); local cmdLine = string.format('luac.exe -o "luac_tmp.bin" "%s"' , cc.FileUtils:getInstance():fullPathForFilename(filename)); local out = io.popen(cmdLine , "r"); print("正在运行:" .. cmdLine); print(out:read("*a")); local r , what , code = out:close(); if code ~= 0 then error("编译脚本出错:" .. filename); end return loadfileData(cc.FileUtils:getInstance():fullPathForFilename("luac_tmp.bin")); end -- 编译lua文件,并返回编译后的数据 function compileLuajit(filename) -- 编译lua print("正在编译Luajit:" , filename); local cmdLine = string.format('luajit -b -g "%s" "luac_tmp.bin"' , cc.FileUtils:getInstance():fullPathForFilename(filename)); local out = io.popen(cmdLine , "r"); print("正在运行:" .. cmdLine); print(out:read("*a")); local r , what , code = out:close(); if code ~= 0 then error("编译脚本出错:" .. filename); end return loadfileData(cc.FileUtils:getInstance():fullPathForFilename("luac_tmp.bin")); end function compileLua(filename) if hasCmdArg("-lua") then return compileLua52(filename); else return compileLuajit(filename); end end local ConfigLoaded = false; function loadAllXML() if ConfigLoaded then return; end ConfigLoaded = true; local s = app.config.Setting; local r = app.config.RomSetting; app.config = require("LoadAllConfigs") app.config.Setting = s; app.config.RomSetting = r; for i, v in pairs(app.config) do if type(v) == "function" then app.config[i] = v() end end end -- 获取对应版本的lua后缀名 local function getLuaExtName(baseName) local saveBaseName if hasCmdArg("-lua") then saveBaseName = baseName .. ".lua52"; else saveBaseName = baseName .. ".luajit"; end return saveBaseName end -- 判断一个策划配置的xml文件依赖的desc文件是否改变 local function isConfigXmlDescChanged(xmlFileName) local descFileName = gConfigXmlToDesc[xmlFileName] if not descFileName then print("配置文件:" .. xmlFileName .. "统计不到对应的desc缓存文件,xml文件需要重新打包") return true end -- 读取文件 local atts = lfs.attributes(descFileName); if not atts then error("找不到文件" .. descFileName); return true; end -- 拆分desc文件名 local pathName, baseName, ext = string.splitFilename(descFileName); local saveBaseName = getLuaExtName(baseName) local cacheFile = gConfigDescCacheFiles.list[saveBaseName]; if cacheFile then if cacheFile.origin == descFileName and cacheFile.modifyTime == atts.modification and cacheFile.originSize == atts.size then -- 文件没有改变则不需要重新生成 return false end end print("配置文件:" .. xmlFileName .. "对应的desc文件:" .. descFileName .. "改变了,xml文件需要重新打包") return true end local function optimiseRewardConfig(RewardConfig) local deleted = {} for i , v in pairs(RewardConfig) do --print("删掉空奖励:" , table.tostring(v)); if not v.epFull and not v.apFull and #v.gold == 1 and v.gold[1] == "" and #v.ticket == 1 and v.ticket[1] == "" and #v.redGem == 1 and v.redGem[1] == "" and #v.goods == 1 and #v.goods[1] == 1 and v.goods[1][1] == "" and #v.treasure == 0 and #v.awardHero == 0 and #v.awardHeroSaga == 0 and #v.awardRune == 0 and #v.awardRuneChip == 0 and #v.awardHeroSoul == 0 and (not v.awardPrivilege or v.awardPrivilege == 0) then table.insert(deleted , i); print("删掉空奖励:" , i); end end print("总共删掉空奖励:" , #deleted); for i , v in ipairs(deleted) do RewardConfig[v] = nil; end end local function optimiseHeroAwardConfig(AwardConfig) local deleted = {} for i , v in pairs(AwardConfig) do if #v.awardValue == 0 or (#v.awardDungeon == 1 and #v.awardDungeon[1] == 0) then table.insert(deleted , i); print("删掉如何获得的空配置:" , i); end end print("总共删掉如何获得空配置:" , #deleted); for i , v in ipairs(deleted) do AwardConfig[v] = nil; end end local function copyFile(dstFile , srcFile) local src = io.open(srcFile , "rb"); local dst = io.open(dstFile , "wb"); dst:write(src:read("*a")); dst:close(); src:close(); end -- 编译xml文件,并返回编译后的数据 function compileXml(sourceFile) loadAllXML(); local luaData; for i , v in pairs(app.config) do if i ~= "Setting" and i ~= "RomSetting" then if type(v.LuaFile) == "string" then local filename = v.XmlFile; if "dataconfig/" .. filename == sourceFile then local luaFile = "cache/" .. filename .. ".lua"; if filename == "pvpRewardConfig.xml" or filename == "riftRewardConfig.xml" or filename == "castleRewardConfig.xml" or filename == "vipRewardConfig.xml" or filename == "commonRewardConfig.xml" or filename == "appRewardConfig.xml" or filename == "rankRewardConfig.xml" or filename == "pveRewardConfig.xml" or filename == "achieveRewardConfig.xml" then optimiseRewardConfig(v); end if filename == "awardHeroSoulConfig.xml" or filename == "awardStarUpFoodConfig.xml" then optimiseHeroAwardConfig(v); end copyFile(luaFile , v.LuaFile); luaData = compileLua(luaFile); break; end else local desc = v:getConfigDesc(); local filename = desc.XMLFile; if "dataconfig/" .. filename == sourceFile then local luaFile = "cache/" .. filename .. ".lua"; if filename == "pvpRewardConfig.xml" or filename == "riftRewardConfig.xml" or filename == "castleRewardConfig.xml" or filename == "vipRewardConfig.xml" or filename == "commonRewardConfig.xml" or filename == "appRewardConfig.xml" or filename == "rankRewardConfig.xml" or filename == "pveRewardConfig.xml" or filename == "achieveRewardConfig.xml" then optimiseRewardConfig(v); end if filename == "awardHeroSoulConfig.xml" or filename == "awardStarUpFoodConfig.xml" then optimiseHeroAwardConfig(v); end saveLuaXMLConfig(v , desc, luaFile); luaData = compileLua(luaFile); break; end end end end if luaData ~= nil then return lzma.compress(luaData); end end local keepFiles = {}; -- 编译文件 function compileFile(sourceFile, targetPath) local pathName , baseName , ext = string.splitFilename(sourceFile); local lowerExt = string.lower(ext); if isIgnoreFile(pathName , baseName , ext) then return; end local atts = lfs.attributes(sourceFile); if not atts then error("找不到文件" .. sourceFile); return; end local keepFile = keepFiles[pathName]; if not keepFile then keepFile = {}; keepFiles[pathName] = keepFile; local f , r = io.open(pathName .. "/keep.txt" , "rb"); print("open keep" , f , r); if f then while true do local fileName = f:read("*l"); print("read keep" , fileName); if fileName then fileName = string.trim(fileName); keepFile[fileName] = true; print("set keep " , fileName); else break; end end f:close(); end end local saveBaseName = baseName; if not keepFile[baseName] then -- 处理png if lowerExt == "png" then -- preload要用png格式,有些机子不支持etc if pathName ~= "preload" then -- 是否支持PVR格式 if hasCmdArg("-pvr") then saveBaseName = saveBaseName .. ".pvr"; end -- 是否支持PVR格式 if hasCmdArg("-etc") then saveBaseName = saveBaseName .. ".etc"; end -- 是否支持PVR格式 if hasCmdArg("-atc") then saveBaseName = saveBaseName .. ".atc"; end end end -- lua文件 if (isLuaFileExt(lowerExt) or (lowerExt == "xml" and pathName == "dataconfig")) then saveBaseName = getLuaExtName(saveBaseName) end else print("file keeped : " , baseName); saveBaseName = baseName .. ".keep"; end local cacheFile = gCacheFiles.list[saveBaseName]; if cacheFile then if cacheFile.origin == sourceFile and cacheFile.modifyTime == atts.modification and cacheFile.originSize == atts.size then -- 如果是dataconfig里面的xml则需要对比下desc文件是否改变了 if lowerExt == "xml" and pathName == "dataconfig" then if isConfigXmlDescChanged(baseName) == false then print("配置文件没有改变,不需要重新打包", baseName) return cacheFile end elseif baseName ~= "Setting.lua" then return cacheFile; end end end print("编译文件" .. sourceFile) local fileData; if not keepFile[baseName] then print("skip keeped : " , baseName); -- 处理png if lowerExt == "png" then -- preload要用png格式,有些机子不支持etc if pathName ~= "preload" then -- 是否支持PVR格式 if hasCmdArg("-pvr") then fileData = compilePngToPvr(sourceFile); end if hasCmdArg("-etc") then fileData = compilePngToEtc(sourceFile); end if hasCmdArg("-atc") then fileData = compilePngToAtc(sourceFile); end else print("preload的文件不用编译png" , sourceFile); end -- 编译配置文件 elseif lowerExt == "xml" then fileData = compileXml(sourceFile); -- 编译lua文件 elseif isLuaFileExt(lowerExt) then fileData = compileLua(sourceFile); end end -- 普通文件加载 if fileData == nil then fileData = loadfileData(sourceFile); end -- 计算文件信息 local fileInfo = CacheFile:new(); fileInfo.origin = sourceFile; fileInfo.name = baseName; fileInfo.md5 = md5.sumhexa(fileData); fileInfo.compileSize = #fileData; fileInfo.originSize = atts.size; -- 保存修改时间 fileInfo.modifyTime = atts.modification; -- 加密文件 local encryptData = FilePackage.encrypt(fileData) fileInfo.encryptSize = string.len(encryptData); -- 加密完毕后,计算出加密后大小 fileInfo.encryptFile = targetPath .. "/cache/" .. saveBaseName .. ".encrypt"; saveFile(encryptData , fileInfo.encryptFile); -- 压缩文件 local compressedData = FilePackage.compress(encryptData) fileInfo.compressedSize = string.len(compressedData); -- 压缩完毕后,计算出压缩后大小 fileInfo.compressedFile = targetPath .."/cache/" .. saveBaseName .. ".compressed"; saveFile(compressedData , fileInfo.compressedFile); gCacheFiles.list[saveBaseName] = fileInfo; --print("编译文件完毕" .. sourceFile); return fileInfo; end -- 保存文件列表 function saveCacheFile(filename) local stream = NetStream.new(); gCacheFiles:write(stream); print("保存缓存数据:" , #gCacheFiles.list) local cacheData = NetStream.getWriteData(stream); saveFile(cacheData , filename); NetStream.delete(stream); end -- 载入文件列表 function loadCacheFile(filename) gCacheFiles = CacheFileList:new(); local cacheData = loadFile(filename); if cacheData then local stream = NetStream.new(cacheData); gCacheFiles = CacheFileList:read(stream); print("载入缓存数据:" , #gCacheFiles.list) NetStream.delete(stream); end end -- 载入配置描述列表 function loadConfigDescCacheFile(configDescFileName) gConfigDescCacheFiles = CacheFileList:new(); local cacheData = loadFile(configDescFileName); if cacheData then local stream = NetStream.new(cacheData); gConfigDescCacheFiles = CacheFileList:read(stream); NetStream.delete(stream); end end