845 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			845 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| import {
 | |
|     _decorator,
 | |
|     Asset,
 | |
|     assetManager,
 | |
|     BufferAsset,
 | |
|     Component,
 | |
|     Node,
 | |
|     resources,
 | |
|     TextAsset,
 | |
|     v2,
 | |
|     v3,
 | |
|     Vec2,
 | |
| } from "cc";
 | |
| import { ReadStream } from "../Tool/ReadStream";
 | |
| import { Ani_Frame, ScriptAni, ScriptFile } from "../GlobalInterface/GlobalInterface";
 | |
| import { GlobalTool } from "../Tool/GlobalTool";
 | |
| 
 | |
| const { ccclass, property } = _decorator;
 | |
| 
 | |
| class ScriptTree {
 | |
|     //PVF文件头数据
 | |
|     Index_Header_Data: Uint8Array;
 | |
|     //PVF原始数据
 | |
|     Script_Data_Buffer: Uint8Array;
 | |
| 
 | |
|     //文件头读取流
 | |
|     Index_Header_Read_Object: ReadStream;
 | |
| 
 | |
|     //树Map
 | |
|     TreeMap: Map<string, ScriptFile> = new Map<string, ScriptFile>();
 | |
| 
 | |
|     constructor(gIndex_Header_Data, gScript_Data_Buffer) {
 | |
|         this.Index_Header_Data = gIndex_Header_Data;
 | |
|         this.Script_Data_Buffer = gScript_Data_Buffer;
 | |
|         this.Index_Header_Read_Object = new ReadStream(this.Index_Header_Data);
 | |
|     }
 | |
| 
 | |
|     ReadTree(currPos, startPos, Index) {
 | |
|         this.Index_Header_Read_Object.Seekg(currPos);
 | |
|         const FileNumber = this.Index_Header_Read_Object.GetInt();
 | |
|         const FilePathLength = this.Index_Header_Read_Object.GetInt();
 | |
|         const FilePath = this.Index_Header_Read_Object.GetBufferByLength(FilePathLength);
 | |
|         const FileLength = this.Index_Header_Read_Object.GetInt();
 | |
|         const Cre32 = this.Index_Header_Read_Object.GetInt();
 | |
|         //数据偏移
 | |
|         const RelativeOffset = this.Index_Header_Read_Object.GetInt();
 | |
|         if (FileLength > 0) {
 | |
|             //数据长度
 | |
|             const RealFileLength = (FileLength + 3) & 4294967292;
 | |
|             //文件路径
 | |
|             const RealFilePath = GlobalTool.uint8ArrayToString(FilePath).replace("\\", "/");
 | |
|             //建立索引Map
 | |
|             this.TreeMap.set(RealFilePath, { Cre32: Cre32, StartPos: startPos, Offset: RelativeOffset, Length: RealFileLength });
 | |
|         }
 | |
|         return FilePathLength + 20;
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     //原数据
 | |
|     StringtableBaseBuf;
 | |
|     //CRE key
 | |
|     StringtableCre32;
 | |
|     //读取Bin文件
 | |
|     StringTable: Map<number, string> = new Map<number, string>();
 | |
| 
 | |
|     //当前索引位置
 | |
|     StringtableCurrentIndex: number = 0;
 | |
|     //当前读取索引位置
 | |
|     StringtableReadCurrentIndex: number = 0;
 | |
| 
 | |
|     //本类用的特殊解密 分段解密
 | |
|     CrcDecodeSpecial(): boolean {
 | |
|         const num: number = 2175242257; // 2175242257L in hexadecimal
 | |
|         const dataView = new DataView(
 | |
|             this.StringtableBaseBuf.buffer,
 | |
|             this.StringtableBaseBuf.byteOffset,
 | |
|             this.StringtableBaseBuf.byteLength,
 | |
|         );
 | |
| 
 | |
|         //开始时间
 | |
|         const StartTime = new Date().getTime();
 | |
|         //死循环读取树文件数据 但是每一次最多只读15毫秒 为了保证UI线程刷新
 | |
|         while (true) {
 | |
|             // Ensure we don't read beyond the end of the data  //如果当前索引位置加上4大于数组长度 说明读取完毕 返回true
 | |
|             if (this.StringtableCurrentIndex >= this.StringtableBaseBuf.length) return true;
 | |
|             //当前时间减去开始时间
 | |
|             const NowTime = new Date().getTime();
 | |
|             //如果本轮循环已经读取了15毫秒了  就先返回刷新ui
 | |
|             if (NowTime - StartTime >= 15) return false;
 | |
|             // Read a 32-bit integer (little endian) from the buffer
 | |
|             let anInt = dataView.getUint32(this.StringtableCurrentIndex, true);
 | |
|             // Perform the XOR operations
 | |
|             let val = anInt ^ num ^ this.StringtableCre32;
 | |
|             // Rotate right 6 bits
 | |
|             let jiemi = (val >>> 6) | (val << (32 - 6));
 | |
|             // Write the result back into the buffer
 | |
|             dataView.setUint32(this.StringtableCurrentIndex, jiemi, true);
 | |
|             this.StringtableCurrentIndex = this.StringtableCurrentIndex + 4;
 | |
|         }
 | |
| 
 | |
| 
 | |
|     }
 | |
| 
 | |
|     InitStringBin() {
 | |
|         //如果这个是空就读取一下
 | |
|         if (this.StringtableBaseBuf == undefined) {
 | |
|             const FileObject = this.TreeMap.get("stringtable.bin");
 | |
|             if (FileObject == undefined) return true;
 | |
|             this.StringtableBaseBuf = this.Script_Data_Buffer.slice(
 | |
|                 FileObject.StartPos + FileObject.Offset,
 | |
|                 FileObject.StartPos + FileObject.Offset + FileObject.Length
 | |
|             );
 | |
|             this.StringtableCre32 = FileObject.Cre32;
 | |
|         }
 | |
| 
 | |
|         const Flag = this.CrcDecodeSpecial();
 | |
| 
 | |
|         if (Flag) {
 | |
|             let Ro = new ReadStream(this.StringtableBaseBuf);
 | |
|             const Count = Ro.GetInt();
 | |
|             //开始时间
 | |
|             const StartTime = new Date().getTime();
 | |
|             while (true) {
 | |
|                 //当前时间减去开始时间
 | |
|                 const NowTime = new Date().getTime();
 | |
|                 //如果本轮循环已经读取了15毫秒了  就先返回刷新ui
 | |
|                 if (NowTime - StartTime >= 15) return false;
 | |
| 
 | |
|                 if (this.StringtableReadCurrentIndex < Count) {
 | |
|                     Ro.Seekg(this.StringtableReadCurrentIndex * 4 + 4);
 | |
|                     const StartPos = Ro.GetInt();
 | |
|                     const EndPos = Ro.GetInt();
 | |
|                     const Len = EndPos - StartPos;
 | |
|                     Ro.Seekg(StartPos + 4);
 | |
|                     const Str = Ro.GetString(Len);
 | |
|                     this.StringTable.set(this.StringtableReadCurrentIndex, Str);
 | |
|                     this.StringtableReadCurrentIndex++;
 | |
|                 } else {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     //读取字符串索引
 | |
|     Load_StringTable: Map<string, string> = new Map<string, string>();
 | |
|     InitLoad_String() {
 | |
|         const FileObject = this.TreeMap.get("n_string.lst");
 | |
|         if (FileObject == undefined) return;
 | |
|         let RealBuf = this.Script_Data_Buffer.slice(
 | |
|             FileObject.StartPos + FileObject.Offset,
 | |
|             FileObject.StartPos + FileObject.Offset + FileObject.Length
 | |
|         );
 | |
| 
 | |
|         GlobalTool.CrcDecode(RealBuf, FileObject.Cre32);
 | |
|         let Ro = new ReadStream(RealBuf);
 | |
| 
 | |
|         const Count = Ro.GetUShort();
 | |
|         if (Count != 53424) return;
 | |
| 
 | |
|         let i = 2;
 | |
|         while (i < Ro.len()) {
 | |
|             if (Ro.len() - i >= 10) {
 | |
|                 Ro.Seekg(i + 6);
 | |
|                 const Key = this.StringTable.get(Ro.GetInt());
 | |
|                 if (Key) {
 | |
|                     const File = this.TreeMap.get(Key.toLocaleLowerCase());
 | |
|                     let FileBuf = this.Script_Data_Buffer.slice(
 | |
|                         File.StartPos + File.Offset,
 | |
|                         File.StartPos + File.Offset + File.Length
 | |
|                     );
 | |
|                     GlobalTool.CrcDecode(FileBuf, File.Cre32);
 | |
| 
 | |
|                     let Str = GlobalTool.uint8ArrayToString(FileBuf, 'big5');
 | |
|                     let StrArr = Str.split('\r\n');
 | |
|                     StrArr.forEach((strobj, index) => {
 | |
|                         if (strobj.indexOf('>')) {
 | |
|                             let strobjarr = strobj.split('>', 2);
 | |
|                             this.Load_StringTable.set(strobjarr[0], strobjarr[1]);
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
|             else break;
 | |
|             i += 10;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //Pvf文件数据
 | |
|     ScriptFileData = new Map();
 | |
|     GetFileData(Path: string) {
 | |
|         //检查路径是否存在
 | |
|         const FileObject = this.TreeMap.get(Path);
 | |
|         if (FileObject == undefined) return false;
 | |
|         //如果读过直接返回数据
 | |
|         const FileData = this.ScriptFileData.get(Path);
 | |
|         if (FileData != undefined) return FileData;
 | |
| 
 | |
| 
 | |
|         //获取文件数据字节数组
 | |
|         let RealBuf = this.Script_Data_Buffer.slice(
 | |
|             FileObject.StartPos + FileObject.Offset,
 | |
|             FileObject.StartPos + FileObject.Offset + FileObject.Length
 | |
|         );
 | |
| 
 | |
|         GlobalTool.CrcDecode(RealBuf, FileObject.Cre32);
 | |
| 
 | |
|         //Ani的处理逻辑
 | |
|         if (Path.indexOf(".ani") != -1) {
 | |
|             if (Path.indexOf(".als") != -1) {
 | |
|                 const Ro = new ReadStream(RealBuf);
 | |
|                 const Str = Ro.GetString();
 | |
|                 this.ScriptFileData.set(Path, Str);
 | |
|                 return Str;
 | |
|             } else {
 | |
|                 let Buf = this.Decompile_ani(RealBuf);
 | |
|                 this.ScriptFileData.set(Path, Buf);
 | |
|                 return Buf;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             try {
 | |
|                 let Buf = this.Decompile_script(RealBuf);
 | |
|                 this.ScriptFileData.set(Path, Buf);
 | |
| 
 | |
|                 return Buf;
 | |
|             } catch (error) {
 | |
|                 // console.log(RealFilePath);
 | |
|             }
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Decompile_script(RealBuf: any) {
 | |
|         const Ro = new ReadStream(RealBuf);
 | |
|         let out: string = "";
 | |
|         if (Ro.len() >= 7) {
 | |
|             //以5为单步从第二位开始遍历字节
 | |
|             let i = 2;
 | |
|             while (i < Ro.len()) {
 | |
|                 //到最后了就不处理了防止内存越界
 | |
|                 if (Ro.len() - i >= 5) {
 | |
|                     Ro.Seekg(i); //内容指示位
 | |
|                     let currentByte = Number(Ro.GetBufferByLength(1)); //内容指示位
 | |
| 
 | |
| 
 | |
|                     let after = Ro.GetInt();
 | |
|                     switch (currentByte) {
 | |
|                         case 10:
 | |
|                             {
 | |
|                                 Ro.Seekg(i - 4);
 | |
|                                 const Before = Ro.GetInt();
 | |
|                                 let Buf = this.StringTable.get(after);
 | |
|                                 if (!Buf) {
 | |
|                                     Buf = "";
 | |
|                                 } else {
 | |
|                                     Buf = "<" + Before + "::" + Buf + "`" + this.Load_StringTable.get(Buf) + "`>";
 | |
|                                 }
 | |
|                                 Buf = Buf + "\r\n";
 | |
|                                 out += Buf;
 | |
|                                 break;
 | |
|                             }
 | |
|                         case 2:
 | |
|                             {
 | |
|                                 out += after + '\t';
 | |
|                                 break;
 | |
|                             }
 | |
|                         case 4:
 | |
|                             {
 | |
|                                 const buffer = new ArrayBuffer(4);
 | |
|                                 const view = new DataView(buffer);
 | |
|                                 view.setInt32(0, after, true);
 | |
|                                 const Buf = view.getFloat32(0);
 | |
|                                 out += after + '\t';
 | |
|                                 break;
 | |
|                             }
 | |
|                         case 6:
 | |
|                         case 8:
 | |
|                         case 7:
 | |
|                         case 5:
 | |
|                             {
 | |
|                                 let Buf = this.StringTable.get(after);
 | |
|                                 if (!Buf) Buf = "";
 | |
| 
 | |
|                                 if (currentByte == 5) {
 | |
|                                     Buf = "\r\n" + Buf + "\r\n";
 | |
|                                 }
 | |
|                                 else if (currentByte == 7) {
 | |
|                                     Buf = "`" + Buf + "`\r\n";
 | |
|                                 }
 | |
|                                 else if (currentByte == 6 || currentByte == 8) {
 | |
|                                     Buf = "{{" + currentByte + "=`" + Buf + "`}}\r\n";
 | |
|                                 }
 | |
|                                 out += Buf;
 | |
|                                 break;
 | |
|                             }
 | |
|                         default:
 | |
|                             out += "";
 | |
|                             break;
 | |
|                     }
 | |
|                 }
 | |
|                 i += 5;
 | |
|             }
 | |
|         }
 | |
|         return out;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     //解包数据
 | |
|     Unpack_Chr(pvfData, curr: number, after: number, before: number): string {
 | |
|         switch (curr) {
 | |
|             case 2:
 | |
|                 return after.toString(); //整数型
 | |
|             case 4:
 | |
|             // return new Float32Array([after]).buffer.slice(0, 4).readFloatLE().toString();
 | |
|             case 5:
 | |
|             case 6:
 | |
|             case 7:
 | |
|             case 8:
 | |
|                 if (pvfData.str_bin_map.has(after)) {
 | |
|                     return pvfData.str_bin_map.get(after);
 | |
|                 } else {
 | |
|                     return "";
 | |
|                 }
 | |
|             case 10:
 | |
|                 if (!pvfData.str_bin_map.has(after)) {
 | |
|                     return "";
 | |
|                 }
 | |
|                 let tempstr = pvfData.str_bin_map.get(after);
 | |
|             // return `<${before}::\`${tempstr}\`${_getNString(pvfData, before, tempstr)}.toString()}>`;
 | |
|             default:
 | |
|                 return "";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //读取Ani
 | |
|     Decompile_ani(RealBuf: any): any {
 | |
|         let AniObject: ScriptAni = {
 | |
|             Img_List: new Array<string>(),
 | |
|             Flag: new Map<string, number>(),
 | |
|             Frame: new Array<Ani_Frame>(),
 | |
|         };
 | |
| 
 | |
| 
 | |
|         const Ro = new ReadStream(RealBuf);
 | |
|         //总帧数
 | |
|         const Frame_Max = Ro.GetUShort();
 | |
|         //总共调用了多少个Img
 | |
|         const Img_Count = Ro.GetUShort();
 | |
| 
 | |
|         //Img的路径读取 存入数组
 | |
|         for (let index = 0; index < Img_Count; index++) {
 | |
|             const Buf = Ro.GetInt();
 | |
|             //有可能Img有空路径
 | |
|             AniObject.Img_List.push(Ro.GetString(Buf).toLowerCase());
 | |
|         }
 | |
| 
 | |
|         //Ani头部标签数量
 | |
|         const Ani_H_Item_Count = Ro.GetUShort();
 | |
| 
 | |
|         //处理标签
 | |
|         for (let index = 0; index < Ani_H_Item_Count; index++) {
 | |
|             //标签类型
 | |
|             const Type = Ro.GetUShort();
 | |
| 
 | |
|             switch (Type) {
 | |
|                 case 0:
 | |
|                 case 1: {
 | |
|                     const Key = this.Get_Ani_Flag(Type);
 | |
|                     const Value = Number(Ro.GetBufferByLength(1));
 | |
|                     AniObject.Flag.set(Key, Value);
 | |
|                     break;
 | |
|                 }
 | |
|                 case 3:
 | |
|                 case 28: {
 | |
|                     const Key = this.Get_Ani_Flag(Type);
 | |
|                     const Value = Ro.GetUShort();
 | |
|                     AniObject.Flag.set(Key, Value);
 | |
|                     break;
 | |
|                 }
 | |
|                 case 18:
 | |
|                     //此处无解析 暂时先保证运行  残影功能暂时用不上
 | |
|                     Ro.GetBufferByLength(1);
 | |
|                     Ro.GetInt();
 | |
|                     Ro.GetInt();
 | |
|                     Ro.GetInt();
 | |
|                     Ro.Get256();
 | |
|                     Ro.Get256();
 | |
|                     Ro.Get256();
 | |
|                     Ro.Get256();
 | |
|                     Ro.GetUShort();
 | |
|                     break;
 | |
|                 default:
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //读取每一个Img
 | |
|         for (let index = 0; index < Frame_Max; index++) {
 | |
|             //帧结构体对象
 | |
|             let FrameObject: Ani_Frame = {
 | |
|                 Box: new Map<number, Array<number>>(),
 | |
|                 Img_Path: null,
 | |
|                 Img_Index: null,
 | |
|                 Pos: null,
 | |
|                 Flag: new Map<string, any>(),
 | |
|                 Delay: null,
 | |
|             };
 | |
| 
 | |
|             //碰撞框项目数量
 | |
|             const Ani_Box_Item_Count = Ro.GetUShort();
 | |
|             for (let _i = 0; _i < Ani_Box_Item_Count; _i++) {
 | |
|                 const Box_Type = Ro.GetUShort();
 | |
|                 let D_Box_b = [];
 | |
|                 for (let _k = 0; _k < 6; _k++) {
 | |
|                     D_Box_b.push(Ro.GetInt());
 | |
|                 }
 | |
|                 //0是攻击框 1是受击框
 | |
|                 FrameObject.Box.set(15 - Box_Type, D_Box_b);
 | |
|             }
 | |
| 
 | |
|             //调用的第几个Img
 | |
|             const Index_Buf = Ro.GetShort();
 | |
|             //如果等于-1说明是img路径为空
 | |
|             if (Index_Buf >= 0) {
 | |
|                 FrameObject.Img_Path = AniObject.Img_List[Index_Buf];
 | |
|                 //Img中的PNG下标
 | |
|                 FrameObject.Img_Index = Ro.GetUShort();
 | |
|             }
 | |
|             else {
 | |
|                 FrameObject.Img_Path = "";
 | |
|                 FrameObject.Img_Index = 0;
 | |
|             }
 | |
| 
 | |
|             //坐标
 | |
|             FrameObject.Pos = v3(Ro.GetInt(), -Ro.GetInt(), 0);
 | |
| 
 | |
|             //Img中的项目数量
 | |
|             const Img_Flag_Count = Ro.GetUShort();
 | |
|             for (let _o = 0; _o < Img_Flag_Count; _o++) {
 | |
|                 const Img_Flag_Type = Ro.GetUShort();
 | |
|                 let Key;
 | |
|                 let Value;
 | |
|                 switch (Img_Flag_Type) {
 | |
|                     case 0:
 | |
|                     case 1:
 | |
|                     case 10:
 | |
|                         Key = this.Get_Ani_Flag(Img_Flag_Type);
 | |
|                         Value = Number(Ro.GetBufferByLength(1));
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 3:
 | |
|                         Key = "COORD";
 | |
|                         Value = Ro.GetUShort();
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 17:
 | |
|                         Key = "PRELOAD";
 | |
|                         Value = 1;
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 7:
 | |
|                         Key = "IMAGE_RATE";
 | |
|                         Value = { x: Ro.GetFloat(), y: Ro.GetFloat() };
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 8:
 | |
|                         Key = "IMAGE_ROTATE";
 | |
|                         Value = Ro.GetFloat();
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 9:
 | |
|                         Key = "RGBA";
 | |
|                         Value = [
 | |
|                             Ro.Get256(),
 | |
|                             Ro.Get256(),
 | |
|                             Ro.Get256(),
 | |
|                             Ro.Get256(),
 | |
|                         ];
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 11:
 | |
|                         const Effect_Type = Ro.GetUShort();
 | |
|                         Key = "GRAPHIC_EFFECT_" + this.Get_Ani_Effect_Type(Effect_Type);
 | |
|                         switch (Effect_Type) {
 | |
|                             case 5:
 | |
|                                 Value = [Ro.Get256(), Ro.Get256(), Ro.Get256()];
 | |
|                                 break;
 | |
|                             case 6:
 | |
|                                 Value = [Ro.GetShort(), Ro.GetShort()];
 | |
|                                 break;
 | |
|                         }
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 12:
 | |
|                         Value = Ro.GetInt();
 | |
|                         FrameObject.Delay = Value;
 | |
|                         break;
 | |
|                     case 13:
 | |
|                         Key = "DAMAGE_TYPE";
 | |
|                         Value = this.Get_Ani_Damage_Type(Ro.GetUShort());
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 16:
 | |
|                         const SoundTempSize = Ro.GetInt();
 | |
|                         Key = "PLAY_SOUND";
 | |
|                         Value = Ro.GetString(SoundTempSize);
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 23:
 | |
|                         Key = "SET_FLAG";
 | |
|                         Value = Ro.GetInt();
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 24:
 | |
|                         Key = "FLIP_TYPE";
 | |
|                         Value = this.Get_Ani_Flip_Type(Ro.GetUShort());
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 25:
 | |
|                         Key = "LOOP_START";
 | |
|                         FrameObject.Flag.set(Key, 1);
 | |
|                         break;
 | |
|                     case 26:
 | |
|                         Key = "LOOP_END";
 | |
|                         Value = Ro.GetInt();
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     case 27:
 | |
|                         Key = "CLIP";
 | |
|                         Value = [
 | |
|                             Ro.GetShort(),
 | |
|                             Ro.GetShort(),
 | |
|                             Ro.GetShort(),
 | |
|                             Ro.GetShort(),
 | |
|                         ];
 | |
|                         FrameObject.Flag.set(Key, Value);
 | |
|                         break;
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             //每一帧都是一个结构体 存入数组中
 | |
|             AniObject.Frame.push(FrameObject);
 | |
|         }
 | |
|         return AniObject;
 | |
|     }
 | |
| 
 | |
|     Get_Ani_Flip_Type(data: number): string {
 | |
|         switch (data) {
 | |
|             case 1:
 | |
|                 return "HORIZON";
 | |
|             case 2:
 | |
|                 return "VERTICAL";
 | |
|             case 3:
 | |
|                 return "ALL";
 | |
|             default:
 | |
|                 return "";
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     Get_Ani_Effect_Type(data: number): string {
 | |
|         switch (data) {
 | |
|             case 0:
 | |
|                 return "NONE";
 | |
|             case 1:
 | |
|                 return "DODGE";
 | |
|             case 2:
 | |
|                 return "LINEARDODGE";
 | |
|             case 3:
 | |
|                 return "DARK";
 | |
|             case 4:
 | |
|                 return "XOR";
 | |
|             case 5:
 | |
|                 return "MONOCHROME";
 | |
|             case 6:
 | |
|                 return "SPACEDISTORT";
 | |
|             default:
 | |
|                 return "";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Get_Ani_Damage_Type(data: number): any {
 | |
|         switch (data) {
 | |
|             case 0:
 | |
|                 return "NORMAL";
 | |
|             case 1:
 | |
|                 return "SUPERARMOR";
 | |
|             case 2:
 | |
|                 return "UNBREAKABLE";
 | |
|             default:
 | |
|                 return "";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Get_Ani_Flag(data: number): string {
 | |
|         switch (data) {
 | |
|             case 0:
 | |
|                 return "LOOP";
 | |
|             case 1:
 | |
|                 return "SHADOW";
 | |
|             case 3:
 | |
|                 return "COORD";
 | |
|             case 7:
 | |
|                 return "IMAGE_RATE";
 | |
|             case 8:
 | |
|                 return "IMAGE_ROTATE";
 | |
|             case 9:
 | |
|                 return "RGBA";
 | |
|             case 10:
 | |
|                 return "INTERPOLATION";
 | |
|             case 11:
 | |
|                 return "GRAPHIC_EFFECT";
 | |
|             case 12:
 | |
|                 return "DELAY";
 | |
|             case 13:
 | |
|                 return "DAMAGE_TYPE";
 | |
|             case 14:
 | |
|                 return "DAMAGE_BOX";
 | |
|             case 15:
 | |
|                 return "ATTACK_BOX";
 | |
|             case 16:
 | |
|                 return "PLAY_SOUND";
 | |
|             case 17:
 | |
|                 return "PRELOAD";
 | |
|             case 18:
 | |
|                 return "SPECTRUM";
 | |
|             case 23:
 | |
|                 return "SET_FLAG";
 | |
|             case 24:
 | |
|                 return "FLIP_TYPE";
 | |
|             case 25:
 | |
|                 return "LOOP_START";
 | |
|             case 26:
 | |
|                 return "LOOP_END";
 | |
|             case 27:
 | |
|                 return "CLIP";
 | |
|             case 28:
 | |
|                 return "OPERATION";
 | |
|             default:
 | |
|                 return "";
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| class ScriptData {
 | |
|     //Pvf数据
 | |
|     ScriptDataBuffer;
 | |
|     //读取UUID的长度
 | |
|     UUID_LENGTH;
 | |
|     //UUID  读 1 - 36位 构造 UTF8 string
 | |
|     UUID;
 | |
|     //版本号
 | |
|     Version;
 | |
|     // 文件路径数据的大小
 | |
|     AlignedIndexHeaderSize;
 | |
|     // 解密密钥
 | |
|     IndexHeaderCrc;
 | |
|     // 文件数量
 | |
|     IndexSize;
 | |
|     // 存放文件路径数据
 | |
|     Index_Header_Data;
 | |
| 
 | |
|     //Pvf解密出的数据
 | |
|     ScriptDataObject: ScriptTree = null;
 | |
| 
 | |
|     constructor(
 | |
|         public buffer: Uint8Array,
 | |
|         public uuidLength: number,
 | |
|         public uuid: string,
 | |
|         public version: number,
 | |
|         public alignedIndexHeaderSize: number,
 | |
|         public indexHeaderCrc: number,
 | |
|         public indexSize: number,
 | |
|         public indexHeaderData: Uint8Array
 | |
|     ) {
 | |
|         //Pvf数据
 | |
|         this.ScriptDataBuffer = buffer;
 | |
|         //读取UUID的长度
 | |
|         this.UUID_LENGTH = uuidLength;
 | |
|         //UUID  读 1 - 36位 构造 UTF8 string
 | |
|         this.UUID = uuid;
 | |
|         //版本号
 | |
|         this.Version = version;
 | |
|         // 文件路径数据的大小
 | |
|         this.AlignedIndexHeaderSize = alignedIndexHeaderSize;
 | |
|         // 解密密钥
 | |
|         this.IndexHeaderCrc = indexHeaderCrc;
 | |
|         // 文件数量
 | |
|         this.IndexSize = indexSize;
 | |
|         // 存放文件路径数据
 | |
|         this.Index_Header_Data = indexHeaderData;
 | |
|     }
 | |
| 
 | |
|     //初始化路径树  把所有文件路径建立起来还没有读
 | |
|     InitPathTree() {
 | |
|         //先进行Crc解密
 | |
|         GlobalTool.CrcDecode(this.Index_Header_Data, this.IndexHeaderCrc);
 | |
|         //构造PVF数据类
 | |
|         this.ScriptDataObject = new ScriptTree(
 | |
|             //文件数据
 | |
|             this.Index_Header_Data,
 | |
|             //整个Pvf的原始数据
 | |
|             this.ScriptDataBuffer
 | |
|         );
 | |
|     }
 | |
| 
 | |
| 
 | |
|     //当期读取树数据的Pos
 | |
|     CurrentTreePos = 0;
 | |
|     //当前读取文件下标
 | |
|     CurrentIndex = 0;
 | |
|     ReadPathTree() {
 | |
|         //开始时间
 | |
|         const StartTime = new Date().getTime();
 | |
|         //死循环读取树文件数据 但是每一次最多只读15毫秒 为了保证UI线程刷新
 | |
|         while (true) {
 | |
|             //当前时间减去开始时间
 | |
|             const NowTime = new Date().getTime();
 | |
|             if ((NowTime - StartTime) >= 15) break;
 | |
|             //当前读取的下标小于总数量
 | |
|             if (this.CurrentIndex < this.IndexSize) {
 | |
|                 const Length = this.ScriptDataObject.ReadTree(
 | |
|                     this.CurrentTreePos,
 | |
|                     this.AlignedIndexHeaderSize + 56,
 | |
|                     this.CurrentIndex
 | |
|                 );
 | |
|                 this.CurrentTreePos += Length;
 | |
|                 this.CurrentIndex++;
 | |
|             }
 | |
|             //如果不小于 说明读完了
 | |
|             else {
 | |
|                 //读取bin文件 bin Map
 | |
|                 const Flag = this.ScriptDataObject.InitStringBin();
 | |
|                 if (Flag) {
 | |
|                     //读取字符串索引
 | |
|                     this.ScriptDataObject.InitLoad_String();
 | |
|                     return true;
 | |
|                 }
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     GetDataByPath(Path: string) {
 | |
|         return this.ScriptDataObject.TreeMap.get(Path);
 | |
|     }
 | |
| }
 | |
| 
 | |
| @ccclass("GameScript")
 | |
| export class GameScript extends Component {
 | |
|     //全局单例类
 | |
|     private static instance: GameScript;
 | |
| 
 | |
|     private constructor() {
 | |
|         super();
 | |
|     }
 | |
| 
 | |
|     public static getInstance(): GameScript {
 | |
|         if (!GameScript.instance) {
 | |
|             GameScript.instance = new GameScript();
 | |
|         }
 | |
|         return GameScript.instance;
 | |
|     }
 | |
| 
 | |
|     //Pvf对象
 | |
|     PvfData: ScriptData;
 | |
|     //加载完成后的回调函数
 | |
|     LoadCallBack: Function;
 | |
| 
 | |
|     //初始化Pvf
 | |
|     Init(Func: Function) {
 | |
|         //储存回调
 | |
|         this.LoadCallBack = Func;
 | |
|         //读取Pvf
 | |
|         this.ReadPvf();
 | |
|     }
 | |
| 
 | |
|     //读取原始数据
 | |
|     ReadPvf() {
 | |
|         resources.load("Script/Rindro_Script", BufferAsset, (err, content) => {
 | |
|             //转化原始数据为Uint8数组
 | |
|             const Buf = new Uint8Array(content.buffer());
 | |
|             //构造一个 读取流对象
 | |
|             const ScriptObj = new ReadStream(Buf);
 | |
|             //读取UUID的长度
 | |
|             const UUID_LENGTH = ScriptObj.GetInt();
 | |
|             //UUID  读 1 - 36位 构造 UTF8 string
 | |
|             const UUID = ScriptObj.GetString(UUID_LENGTH);
 | |
|             //版本号
 | |
|             const Version = ScriptObj.GetInt();
 | |
|             // 文件路径数据的大小
 | |
|             const AlignedIndexHeaderSize = ScriptObj.GetInt();
 | |
|             // 解密密钥
 | |
|             const IndexHeaderCrc = ScriptObj.GetInt();
 | |
|             // 文件数量
 | |
|             const IndexSize = ScriptObj.GetInt();
 | |
|             // 存放文件路径数据
 | |
|             const Index_Header_Data = ScriptObj.GetBufferByLength(AlignedIndexHeaderSize);
 | |
| 
 | |
|             this.PvfData = new ScriptData(
 | |
|                 Buf,
 | |
|                 UUID_LENGTH,
 | |
|                 UUID,
 | |
|                 Version,
 | |
|                 AlignedIndexHeaderSize,
 | |
|                 IndexHeaderCrc,
 | |
|                 IndexSize,
 | |
|                 Index_Header_Data
 | |
|             );
 | |
| 
 | |
|             //建立文件索引树
 | |
|             this.PvfData.InitPathTree();
 | |
|             //可以开始读取PVF数据
 | |
|             this.StartInitFlag = true;
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     //可以开始读取PVF数据
 | |
|     StartInitFlag = false;
 | |
|     //是否已经读取完成
 | |
|     InitFlag = false;
 | |
|     Update() {
 | |
|         if (!this.InitFlag && this.StartInitFlag) {
 | |
|             const Flag = this.PvfData.ReadPathTree();
 | |
|             if (Flag) {
 | |
|                 this.LoadCallBack();
 | |
|                 this.InitFlag = true;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     GetDataByPath(Path: string) {
 | |
|         const Ret = this.PvfData.ScriptDataObject.GetFileData(Path);
 | |
|         if (Ret) return Ret;
 | |
|         else console.error("索引路径不存在: " + Path);
 | |
|     }
 | |
| 
 | |
| }
 |