841 lines
28 KiB
TypeScript
841 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) {
|
|
// try {
|
|
let Buf = this.Decompile_ani(RealBuf);
|
|
this.ScriptFileData.set(Path, Buf);
|
|
return Buf;
|
|
// } catch (error) {
|
|
// console.log(Path);
|
|
// }
|
|
}
|
|
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));
|
|
}
|
|
|
|
//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);
|
|
}
|
|
|
|
}
|