DaFuWeng/assets/GlobalScript/GameScript/GameScript.ts

845 lines
28 KiB
TypeScript
Raw Normal View History

2024-03-06 22:06:49 +08:00
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");
2024-03-07 13:32:04 +08:00
if (FileObject == undefined) return true;
2024-03-06 22:06:49 +08:00
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");
2024-03-07 13:32:04 +08:00
if (FileObject == undefined) return;
2024-03-06 22:06:49 +08:00
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的处理逻辑
2024-03-09 13:19:32 +08:00
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;
}
2024-03-06 22:06:49 +08:00
}
else {
try {
let Buf = this.Decompile_script(RealBuf);
this.ScriptFileData.set(Path, Buf);
2024-03-06 22:06:49 +08:00
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有空路径
2024-03-09 13:19:32 +08:00
AniObject.Img_List.push(Ro.GetString(Buf).toLowerCase());
2024-03-06 22:06:49 +08:00
}
//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);
}
}