import xlsx from 'node-xlsx' import fs from 'fs'; import path from 'path'; import { Utils } from './Utils'; const ROOM_COUNT = 7; export type SubpackageConfig = { key: string, name: string, des: string, uuids: string[], } type RoomFishData = { [filePath: string]: { [roomType: number]: boolean } }; type SubpackageInfoData = { [name: string]: { key: string, name: string, des: string; } }; type SubpackageContentDataItem = { path: string, type: number }[] type SubpackageContentData = { [name: string]: SubpackageContentDataItem }; export class Config { private readonly assetsDir: string; private readonly uuidMap: { db: string, uuid: string, dest: string }[]; private readonly gameConfig: any; private readonly packageMap: { [name: string]: string[] }; private readonly subpackageInfoData: SubpackageInfoData; private readonly subpackageContentData: SubpackageContentData; private subpackageConfigs: SubpackageConfig[]; constructor(projectDir: string, xlsxPath: string, xxtea?: string) { this.assetsDir = path.join(projectDir, 'assets'); const buildJson = fs.readFileSync(path.join(projectDir, 'build', 'build.json')); const buildData = JSON.parse(buildJson.toString()); this.uuidMap = buildData.uuid; const gameConfigPath = path.join(this.assetsDir, 'resources', 'conf', 'allConf.json'); const gameConfigContent = fs.readFileSync(gameConfigPath); this.gameConfig = JSON.parse(gameConfigContent.toString()); this.packageMap = {} for (let db in buildData.pac) { const url: string = buildData.pac[db]; const name = url.substring(url.lastIndexOf('\\') + 1, url.lastIndexOf('.')); this.packageMap[name] = this.packageMap[name] || []; this.packageMap[name].push(db); } this.subpackageContentData = {}; const data = xlsx.parse(xlsxPath); for (const item of data) { switch (item.name) { case 'Subpackage': this.subpackageInfoData = this.decodeSubpackageInfoData(item.data as string[][]); break; default: this.subpackageContentData[item.name] = this.initializeSubpackageData(item.data as string[][]); break; } } } private dataArrayToObjectArray(data: any[][]): any[] { const title: string[] = data.shift()!; const objArray: { [title: string]: string }[] = []; for (const dataItem of data) { const dataObj: { [title: string]: string } = {} for (let i = 0, length = title.length; i < length; i++) { const key: string = title[i]; if (!key) break; dataObj[key] = dataItem[i]; } objArray.push(dataObj); } return objArray; } private decodeSubpackageInfoData(data: string[][]): SubpackageInfoData { const subpackageInfoData: SubpackageInfoData = {} data.splice(1, 1);//排除说明行 const objArray = this.dataArrayToObjectArray(data); for (const obj of objArray) { obj.name && (subpackageInfoData[obj.key] = { key: obj.key, name: obj.name, des: obj.des }); } return subpackageInfoData; } private initializeSubpackageData(data: string[][]): SubpackageContentDataItem { const files: SubpackageContentDataItem = []; data.splice(1, 1);//排除说明行 const objArray = this.dataArrayToObjectArray(data); for (const obj of objArray) { const path: string = obj.path; const type: number = parseInt(obj.type); files.push({ path, type }); } return files; } private getUUIDsInPath(filePath: string, uuids?: { db: string, uuid: string }[]): { db: string, uuid: string }[] { uuids = uuids || []; this.uuidMap.forEach(value => { const db = value.db.substring(12);//"db://assets/".length if (!db.startsWith(filePath)) return; if (uuids.findIndex(item => item.uuid === value.uuid) >= 0) return; uuids.push(value); }); return uuids; } private getUUIDsByRegExp(regExp: RegExp, uuids?: { db: string, uuid: string }[]): { db: string, uuid: string }[] { uuids = uuids || []; this.uuidMap.forEach(value => { const db = value.db.substring(12);//"db://assets/".length if (!regExp.test(db)) return; if (uuids.findIndex(item => item.uuid === value.uuid) >= 0) return; uuids.push(value); }); return uuids; } private updatePackageAssets(uuids?: { db: string, uuid: string }[]): { db: string, uuid: string }[] { for (const fileName in this.packageMap) { const packageDBs = this.packageMap[fileName]; let match = true; const removedUUIDs: { db: string, uuid: string }[] = []; for (const packageDB of packageDBs) { const index = uuids.findIndex(value => value.db === packageDB); match = index >= 0; if (match) { removedUUIDs.push(...uuids.splice(index, 1)); } else { uuids.push(...removedUUIDs); match = false; break; } } match && uuids.push({ db: null, uuid: fileName }); } return uuids; } //通过鱼属性表读取相关资源所属的房间 private decodeRoomFishData(): RoomFishData { const filesRoomData: RoomFishData = {}; const fishAttribute = this.dataArrayToObjectArray(this.gameConfig['FishAttribute']); for (const fish of fishAttribute) { //房间数据 const fishName: string = fish.name; if (!fishName) continue; //处理鱼资源、鱼技能资源 this.updateRoomFishData(filesRoomData, `resources/anim/clip/fish/${fishName}`, fish);//鱼动画 this.updateRoomFishData(filesRoomData, `res/anim/texture/fish/${fishName}`, fish);;//鱼动画纹理 this.updateRoomFishData(filesRoomData, `resources/spine/fish/play/${fishName}`, fish);//鱼技能Spine this.updateRoomFishData(filesRoomData, `res/spine/fish/play/${fishName}`, fish);//鱼技能Spine //处理背景资源 // const backgroundString: string | null = fish.Background // if (backgroundString) { // const background = backgroundString.split('|'); // switch (background[0]) { // case '1': // this.updateRoomFishData(filesRoomData, `resources/texture/mainScene/bg/${background[1]}`, fish);//鱼背景静态图 // break; // case '2': // } // } } return filesRoomData; } private updateRoomFishData(container: RoomFishData, key: string, fish: any): void { const exitsData = container[key] || {}; for (let i = 1; i <= ROOM_COUNT; i++) { exitsData[i] = exitsData[i] || (fish[`room${i}`] === 1); } container[key] = exitsData; } private initExcelSubpackage(config: SubpackageConfig[]): void { const fileRoomData: RoomFishData = this.decodeRoomFishData(); Utils.log(`fileRoomData: ${JSON.stringify(fileRoomData)}`, Utils.LogLevel.Particular); for (const key in this.subpackageContentData) { Utils.log(`-------------------------------------------Decode package [${key}] config---------------------------------------------------`, Utils.LogLevel.Particular); const uuids: { db: string, uuid: string }[] = []; const files = this.subpackageContentData[key]; const roomTypes: number[] = []; const excludeRoomTypes: number[] = []; for (const file of files) { switch (file.type) { case 1: { Utils.log(`Add path: ${file.path}`, Utils.LogLevel.Particular); this.getUUIDsInPath(file.path, uuids); } break; case 2: { Utils.log(`Add path: ${file.path}`, Utils.LogLevel.Particular); const regexp = new RegExp(file.path, 'i'); this.getUUIDsByRegExp(regexp, uuids); } break; case 3: { const roomType = parseInt(file.path); roomTypes.indexOf(roomType) >= 0 || roomTypes.push(roomType); } break; case 4: { const roomType = parseInt(file.path); excludeRoomTypes.indexOf(roomType) >= 0 || excludeRoomTypes.push(roomType); } break; } } if (roomTypes.length || excludeRoomTypes.length) { for (const filePath in fileRoomData) { let isSubFile = true; const data = fileRoomData[filePath]; for (let i = 0; i < roomTypes.length && isSubFile; i++) { const roomType = roomTypes[i]; if (!data[roomType]) isSubFile = false; } for (let i = 0; i < excludeRoomTypes.length && isSubFile; i++) { const roomType = excludeRoomTypes[i]; if (data[roomType]) isSubFile = false; } if (isSubFile) { Utils.log(`Add path: ${filePath}`, Utils.LogLevel.Particular); this.getUUIDsInPath(filePath, uuids); } } } this.updatePackageAssets(uuids); const base = this.subpackageInfoData[key]; console.log(`Package ${key} files: \n${uuids.join(', ')}`); config.push({ key: base.key, name: base.name, des: base.des, uuids: uuids.map(value => value.uuid) }); } } // private initWelfareSubpackage(config: SubpackageConfig[]): void { // const welfare = this.dataArrayToObjectArray(this.gameConfig['Welfare']); // welfare.forEach(({ id, page, pic }) => { // const uuids: { db: string; uuid: string; }[] = []; // this.getUUIDsInPath(`res/spine/welfare/${page}`, uuids); // this.getUUIDsInPath(`res/prefab/welfare/${page}`, uuids); // this.getUUIDsInPath(`res/texture/welfare/${page}`, uuids); // this.getUUIDsInPath(`res/texture/_atlasexclude/welfare/${page}`, uuids); // this.getUUIDsInPath(`resources/texture/welfareImgs/${pic}`, uuids); // this.updatePackageAssets(uuids); // config.push({ name: `welfare${id}`, des: '', uuids: uuids.map(value => value.uuid) }); // }) // } private initSubpackageConfig(): SubpackageConfig[] { const config: SubpackageConfig[] = []; this.initExcelSubpackage(config); return config; } public getSubpackageConfig(): SubpackageConfig[] { this.subpackageConfigs = this.subpackageConfigs || this.initSubpackageConfig(); return this.subpackageConfigs; } }