/*
文件名:ScriptManager.nut
路径:Dps_A/BaseClass/ScriptManager/ScriptManager.nut
创建日期:2024-10-11	12:24
文件用途:pvf 管理器
*/
class Script {

    constructor(Path = "/home/neople/game/Script.pvf") {
        print("正在初始化PVF...");
        local StartTime = time();
        //文件
        local FileIo = null;
        try {
            FileIo = file(Path, "rb");
        } catch (exception) {
            error("打不开Script文件!");
        }
        if (!FileIo) return;
        local FileRo = BlobEx(FileIo.readblob(FileIo.len()));
        InitPvfTreeHeader(FileRo);
        FileIo.close();

        InitStringBin(FileRo);
        InitLoadString(FileRo);

        ScriptData.IO = FileRo;
        ScriptData.Init();

        print("PVF初始化完毕!!!");
        print("用时: " + (time() - StartTime) + "秒");
    }

    function charPtrToInt(arr) {
        local value = ((arr[0]) << 0) | ((arr[1]) << 8) | ((arr[2]) << 16) | ((arr[3]) << 24);
        return value;
    }

    function CrcDecode(Ro, Length, crc32) {
        local num = 0x81A79011;
        for (local i = 0; i< Length; i += 4) {
            local Pos = Ro.tell();
            local anInt = charPtrToInt([Ro[Pos], Ro[Pos + 1], Ro[Pos + 2], Ro[Pos + 3]]);
            local val = (anInt ^ num ^ crc32);
            local jiemi = (val >>> 6) | ((val << (32 - 6)) & 0xFFFFFFFF);

            Ro[Pos] = ((jiemi >>> 0) & 0xFF);
            Ro[Pos + 1] = ((jiemi >>> 8) & 0xFF);
            Ro[Pos + 2] = ((jiemi >>> 16) & 0xFF);
            Ro[Pos + 3] = ((jiemi >>> 24) & 0xFF);
            Ro.seek(4, 'c');
        }
    }

    //初始化PVF文件树
    function InitPvfTreeHeader(HeaderRo) {
        //读取UUID的长度
        local UUID_LENGTH = HeaderRo.GetInt();
        //UUID  读 1 - 36位 构造 UTF8 string
        local UUID = HeaderRo.GetString(UUID_LENGTH);
        //版本号
        local Version = HeaderRo.GetInt();
        // 文件路径数据的大小
        local AlignedIndexHeaderSize = HeaderRo.GetInt();
        // 解密密钥
        local IndexHeaderCrc = HeaderRo.GetInt();
        // 文件数量
        local IndexSize = HeaderRo.GetInt();
        local FristPos = HeaderRo.tell();


        CrcDecode(HeaderRo, AlignedIndexHeaderSize, IndexHeaderCrc)
        // HeaderRo.CrcDecode(AlignedIndexHeaderSize, IndexHeaderCrc);


        local CurrPos = 0;
        ScriptData.StartPos = AlignedIndexHeaderSize + 56;

        for (local i = 0; i< IndexSize; i++) {
            HeaderRo.seek(FristPos + CurrPos);
            local FileNumber = HeaderRo.GetInt();
            local FilePathLength = HeaderRo.GetInt();
            local FileName = HeaderRo.GetString(FilePathLength);
            local FileLength = HeaderRo.GetInt();
            local Cre32 = HeaderRo.GetInt();
            local RelativeOffset = HeaderRo.GetInt();
            if (FileLength > 0) {
                local RealFileLength = (FileLength + 3) & 4294967292;
                ScriptData.PvfFileInfo[FileName] <- {
                    ROffset = RelativeOffset,
                    Cr32 = Cre32,
                    Length = RealFileLength,
                    DecodeFlag = 0
                }
            }
            CurrPos += 20;
            CurrPos += FilePathLength;
        }
    }

    function InitStringBin(Ro) {
        local Info = ScriptData.GetFileInfo("stringtable.bin");
        if (!Info) return;

        Ro.seek(ScriptData.StartPos + Info.ROffset);
        CrcDecode(Ro, Info.Length, Info.Cr32);
        //解密完需要重新调整指针位置
        Ro.seek(ScriptData.StartPos + Info.ROffset);

        local FileHPos = Ro.tell();
        local Count = Ro.GetInt();


        local CurrentIndex = 0;
        for (local i = 0; i< Count; i++) {
            Ro.seek(FileHPos + CurrentIndex * 4 + 4);
            local StartPos = Ro.GetInt();
            local EndPos = Ro.GetInt();
            local Len = EndPos - StartPos;
            Ro.seek(FileHPos + StartPos + 4);
            local Str = Ro.GetString(Len);
            ScriptData.BinString[CurrentIndex] <- Str;
            CurrentIndex++;
        }
        ScriptData.RemoveFileInfo("stringtable.bin");
        // print("初始化StringTable完成,数量: " + ScriptData.BinString.len());
    }

    function InitLoadString(Ro) {
        local Info = ScriptData.GetFileInfo("n_string.lst");
        if (!Info) return;

        Ro.seek(ScriptData.StartPos + Info.ROffset);
        CrcDecode(Ro, Info.Length, Info.Cr32);
        //解密完需要重新调整指针位置
        Ro.seek(ScriptData.StartPos + Info.ROffset);

        local FileHPos = Ro.tell();
        local Flag = Ro.GetUShort();
        // print("Flag :" + Flag);
        local i = 2;
        while (i< Info.Length) {
            if ((Info.Length - i) >= 10) {
                Ro.seek(FileHPos + i + 6);
                local FindKey = Ro.GetInt();
                local Key = ScriptData.GetBinString(FindKey);
                if (Key) {
                    local FileInfo = ScriptData.GetFileInfo(Key.tolower());

                    Ro.seek(ScriptData.StartPos + FileInfo.ROffset);
                    CrcDecode(Ro, FileInfo.Length, FileInfo.Cr32);
                    //解密完需要重新调整指针位置
                    Ro.seek(ScriptData.StartPos + FileInfo.ROffset);
                    local Str = Ro.GetString(FileInfo.Length);
                    local StrArr = split(Str, "\r\n");
                    foreach(index, strobj in StrArr) {
                        if (strobj.find(">") != null) {
                            local strobjarr = split(strobj, ">");
                            if (strobjarr.len() > 1)
                                ScriptData.LoadString[strobjarr[0]] <- strobjarr[1];
                        }
                    }
                    ScriptData.RemoveFileInfo(Key.tolower());
                }
            } else break;
            i += 10;
        }
        ScriptData.RemoveFileInfo("n_string.lst");
        // print("初始化LoadString完成,数量: " + ScriptData.LoadString.len());
    }
}






class GlobaData {
    //加载完成的Flag
    InitFlag = false;
    //PVF的文件解析集合
    PvfFileInfo = null;
    //PVF文件的开始下标
    StartPos = null;
    //PVF文件的IO
    IO = null;

    AniPathTable = null;
    Ani = null;
    LoadString = null;
    BinString = null;

    //怪物List
    MonsterLst = null;
    MonsterConfigLst = null;
    //地图List
    MapLst = null;
    MapConfigLst = null;
    //地板List
    TileConfigLst = null;
    //被动对象List
    PassiveObjectLst = null;
    PassiveObjectConfigLst = null;
    //角色配置信息路径List
    CharacterLst = null;
    CharacterConfigLst = null;
    //装备List
    EquipmentLst = null;
    EquipmentConfigLst = null;
    //APC List
    AICharacterLst = null;
    AICharacterConfigLst = null;
    //Atk List
    AttackinfoConfigLst = null;

    constructor() {
        PvfFileInfo = {};
        Ani = {};
        AniPathTable = {};
        LoadString = {};
        BinString = {};
        MonsterConfigLst = {};
        MapConfigLst = {};
        TileConfigLst = {};
        PassiveObjectConfigLst = {};
        CharacterConfigLst = {};
        EquipmentConfigLst = {};
        AICharacterConfigLst = {};
        AttackinfoConfigLst = {};
    }

    function InitList(Path, ErrorStr, TableName) {
        this[TableName] = {};
        local HeaderPath = Path + "/";
        local Info = ScriptData.GetFileInfo(HeaderPath + Path + ".lst");
        if (!Info) return error(ErrorStr + "列表不存在。加载失败！");
        IO.seek(ScriptData.StartPos + Info.ROffset);

        local FileHPos = IO.tell();
        local Flag = IO.GetUShort();

        local i = 2;
        while (i< Info.Length) {
            if ((Info.Length - i) >= 10) {
                IO.seek(FileHPos + i + 1);
                local Id;
                if (Path == "equipment") {
                    Id = IO.GetInt();
                    IO.seek(1, 'c');
                } else {
                    Id = IO.GetShort();
                    IO.seek(3, 'c');
                }
                local FindKey = IO.readn('i');
                local Key = ScriptData.GetBinString(FindKey);
                Key = HeaderPath + Key.tolower();
                this[TableName][Id] <- Key;
            } else break;
            i += 10;
        }
    }

    function Init() {
        //初始化怪物列表
        InitList("monster", "怪物", "MonsterLst");
        //初始化地图列表
        InitList("map", "地图", "MapLst");
        //初始化被动对象列表
        InitList("passiveobject", "被动对象", "PassiveObjectLst");
        //初始化角色配置信息列表
        InitList("character", "角色配置", "CharacterLst");
        //初始化角色配置信息列表
        InitList("equipment", "装备", "EquipmentLst");
        // Util.PrintTable(EquipmentLst);
        //初始化APC列表
        InitList("aicharacter", "APC", "AICharacterLst");

        ScriptData.InitFlag = true;
    }

    function RegRealPath(Path) {
        if (Path.find("../") != null) {
            while (true) {
                local rbuf = regexp("[^/]+/../");
                local Ret = rbuf.capture(Path);
                if (Ret) {
                    Path = Path.slice(0, Ret[0].begin) + Path.slice(Ret[0].end);
                } else {
                    return Path;
                }
            }
        }
        return Path;
    }

    function GetFileInfo(Path) {
        Path = RegRealPath(Path);
        if (!PvfFileInfo.rawin(Path)) return null;
        else {
            //如果是未解密的需要先解密
            if (Path != "stringtable.bin" && Path != "n_string.lst" && !(endswith(Path, ".str")) && PvfFileInfo[Path].DecodeFlag == 0) {
                local Info = PvfFileInfo[Path];
                IO.seek(StartPos + Info.ROffset);
                Script.CrcDecode(IO, Info.Length, Info.Cr32);
                // 解密完需要重新调整指针位置
                // FileRo.seek(StartPos + Info.ROffset);
            }
            return PvfFileInfo[Path];
        }
    }

    function RemoveFileInfo(Path) {
        if (PvfFileInfo.rawin(Path)) {
            delete PvfFileInfo[Path]
        }
    }

    function GetAni(Path) {
        Path = RegRealPath(Path);
        if (Path in Ani)
            return Ani[Path];
        else {
            try {
                IO.seek(AniPathTable[Path].Pos);
                CrcDecode(IO, AniPathTable[Path].Length, AniPathTable[Path].Cr32);
                IO.seek(AniPathTable[Path].Pos);
                Ani[Path] <- InitPvfAni(IO);
                return Ani[Path];
            } catch (exception) {
                print(Path + "找不到文件！");
                error(exception);
            }
            // print(Path + "找不到文件！");
            return null;
        }
    }


    function GetBinString(Path) {
        if (Path in BinString)
            return BinString[Path];
        else {
            print(Path + "找不到文件！");
            return null;
        }
    }

    function GetLoadString(Path) {
        if (Path in LoadString)
            return LoadString[Path];
        else {
            print(Path + "找不到文件！");
            return null;
        }
    }

    function UnpackData(FilePos, i) {
        local out = "";
        IO.seek(FilePos + i); //内容指示位
        local currentByte = IO.readn('c'); //内容指示位
        local after = IO.GetInt();
        switch (currentByte) {
            case 10: {
                IO.seek(FilePos + i - 4);
                local Before = IO.GetInt();
                local Buf = GetBinString(after);
                if (!Buf) {
                    Buf = "";
                } else {
                    Buf = "<" + Before + "::" + Buf + "`" + GetLoadString(Buf) + "`>";
                }
                Buf = Buf + "\r\n";
                out += Buf;
                break;
            }
            case 2: {
                out += after + '\t';
                break;
            }
            case 4: {
                local Bbuf = blob(4);
                Bbuf.writen(after, 'i');
                Bbuf.seek(0);
                local Buf = Bbuf.readn('f');
                out += after + '\t';
                break;
            }
            case 6:
            case 8:
            case 7:
            case 5: {
                local Buf = GetBinString(after);
                if (!Buf) Buf = "";
                return Buf;
            }
            default:
                out += "";
                break;
        }

        return out;
    }


    function Decompile_attackinfo(DirPath, FileRealName, Info) {
        local AttackinfoAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;
                    //攻击类型 攻击属性类型 损伤反应
                    if (str == "[attack type]" || str == "[elemental property]" || str == "[damage reaction]") {
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt[str.slice(1, -1)] <- Ret.slice(1, -1);
                    }
                    //武器伤害应用 推力  抬起
                    else if (str == "[weapon damage apply]" || str == "[push aside]" || str == "[lift up]") {
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt[str.slice(1, -1)] <- ((Ret.tointeger() - 9).tofloat());
                    }
                    //打击音效
                    else if (str == "[hit wav]") {
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt[str.slice(1, -1)] <- Ret;
                    }
                    //打击效果
                    else if (str == "[hit info]") {
                        AttackinfoAtt["hit_info"] <- {};
                        local HitType = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt["hit_info"].Type <- HitType;
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt["hit_info"].BloodType <- Ret.slice(1, -1);
                        local Value0 = UnpackData(FilePos, i);
                        i += 5;
                        local Value1 = UnpackData(FilePos, i);
                        i += 5;
                        AttackinfoAtt["hit_info"].Value <- [Value0, Value1];
                    }
                } else break;
            }

        }
        return AttackinfoAtt;
    }

    //获取ATK
    function GetAtk(Path) {
        Path = RegRealPath(Path);
        if (AttackinfoConfigLst.rawin(Path)) return AttackinfoConfigLst[Path];
        local Pos = 0;
        while (true) {
            local Buf = Path.find("/", Pos + 1);
            if (Buf != null)
                Pos = Buf;
            else break;
        }
        local DirPath = Path.slice(0, Pos + 1);
        local FileRealName = Path.slice(Pos + 1);
        local Info = GetFileInfo(Path);
        if (Info) {
            local InfoObj = Decompile_attackinfo(DirPath, FileRealName, Info);
            AttackinfoConfigLst[Path] <- InfoObj;
            return InfoObj;
        } else error(Path + " AttackInfo不存在!");
    }

    function Decompile_monster(DirPath, FileRealName, Info) {
        local MonsterAtt = {};
        //属性表
        MonsterAtt.Attributes <- {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;
                    //大小
                    if (str == "[size]") {
                        local gx = UnpackData(FilePos, i);
                        i += 5;
                        local gy = UnpackData(FilePos, i);
                        i += 5;
                        MonsterAtt.size <- {
                            x = gx.tointeger(),
                            y = gy.tointeger()
                        };
                    }
                    //属性
                    else if (str == "[HpMax]" || str == "[Attack]" || str == "[Speed]" || str == "[Defense]" || str == "[DeployCost]" || str == "[Resilience]" || str == "[FirePower]" || str == "[IcePower]" || str == "[LightningPower]" || str == "[DarkPower]" || str == "[FireResistance]" || str == "[IceResistance]" || str == "[LightningResistance]" || str == "[DarkResistance]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MonsterAtt.Attributes[RealKey] <- UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                    }
                    // //属性
                    // else if (str == "[ability]") {
                    //     MonsterAtt.ability <- {};
                    //     while (true) {
                    //         local Ret = UnpackData(FilePos, i);
                    //         i += 5;
                    //         if (Ret == "[/ability]") break;
                    //         if (endswith(Ret, "]")) {
                    //             local Value = UnpackData(FilePos, i);
                    //             i += 5;
                    //             MonsterAtt.ability[Ret.slice(1, Ret.len() - 1)] <- Value.tointeger();
                    //         }
                    //     }
                    // }
                    //标签
                    else if (str == "[category]") {
                        MonsterAtt.category <- {};
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/category]") break;
                            if (endswith(Ret, "]")) {
                                MonsterAtt.category[Ret.slice(1, Ret.len() - 1)] <- true;
                            }
                        }
                    }
                    //等级 移动速度 攻击速度 释放速度 硬直 重量
                    else if (str == "[level]" || str == "[move speed]" || str == "[attack speed]" || str == "[cast speed]" || str == "[hit recovery]" || str == "[weight]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MonsterAtt[RealKey] <- {};
                        MonsterAtt[RealKey].min <- UnpackData(FilePos, i).tointeger();
                        i += 5;
                        MonsterAtt[RealKey].max <- UnpackData(FilePos, i).tointeger();
                        i += 5;
                    }
                    //视力 针对最近 好战 攻击延迟(僵值) 名字
                    else if (str == "[sight]" || str == "[targeting nearest]" || str == "[warlike]" || str == "[attack delay]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MonsterAtt[RealKey] <- UnpackData(FilePos, i).tointeger();
                        i += 5;
                    }
                    //名字
                    else if (str == "[name]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MonsterAtt[RealKey] <- UnpackData(FilePos, i);
                        i += 5;
                    }
                    //头像
                    else if (str == "[face image]") {
                        local buf1 = UnpackData(FilePos, i);
                        i += 5;
                        local buf2 = UnpackData(FilePos, i);
                        i += 5;
                        MonsterAtt.face <- {
                            path = buf1,
                            index = buf2
                        };
                    }
                    //Ani
                    else if (str == "[animotion]") {
                        MonsterAtt.animotion <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/animotion]") break;
                            MonsterAtt.animotion.append(DirPath + Ret.tolower());
                        }
                    }
                    //Atk
                    else if (str == "[attack info]") {
                        MonsterAtt.attackinfo <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/attack info]") break;
                            MonsterAtt.attackinfo.append(DirPath + Ret.tolower());
                        }
                    }
                } else break;
            }

        }
        return MonsterAtt;
    }


    function GetMonster(Idx) {
        if (MonsterLst.rawin(Idx)) {
            local Path = MonsterLst[Idx];
            if (MonsterConfigLst.rawin(Path)) return MonsterConfigLst[Path];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_monster(DirPath, FileRealName, Info);
            MonsterConfigLst[Path] <- InfoObj;
            return InfoObj;
        } else error(Idx + " 号怪物不存在!");
    }


    function Decompile_map(DirPath, FileRealName, Info) {
        local MapAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;
                    //远景速度 中景速度 近景速度
                    if (str == "[far sight scroll]" || str == "[middle sight scroll]" || str == "[near sight scroll]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MapAtt[RealKey] <- UnpackData(FilePos, i).tointeger();
                        i += 5;
                    }
                    //名字
                    else if (str == "[map name]" || str == "[map type]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        MapAtt[RealKey] <- UnpackData(FilePos, i);
                        i += 5;
                    }
                    //地板
                    else if (str == "[tile]") {
                        MapAtt.tile <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/tile]") break;
                            MapAtt.tile.append(DirPath + Ret.tolower());
                        }
                    }
                    //音乐
                    else if (str == "[sound]") {
                        MapAtt.sound <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/sound]") break;
                            MapAtt.sound.append(Ret);
                        }
                    }
                    //对象
                    else if (str == "[passive object]") {
                        MapAtt.passiveobject <- [];
                        while (true) {
                            local Id = UnpackData(FilePos, i);
                            i += 5;
                            if (Id == "[/passive object]") break;
                            local XPos = UnpackData(FilePos, i);
                            i += 5;
                            local YPos = UnpackData(FilePos, i);
                            i += 5;
                            local ZPos = UnpackData(FilePos, i);
                            i += 5;
                            local Tbuf = {
                                id = Id.tointeger() - 9,
                                x = XPos.tointeger() - 9,
                                y = YPos.tointeger() - 9,
                                z = ZPos.tointeger() - 9,
                            }
                            MapAtt.passiveobject.append(Tbuf);
                        }
                    }
                    //Ani
                    else if (str == "[animation]") {
                        MapAtt.animation <- [];
                        while (true) {
                            local Path = UnpackData(FilePos, i);
                            i += 5;
                            if (Path == "[/animation]") break;
                            local Layer = UnpackData(FilePos, i);
                            i += 5;
                            local XPos = UnpackData(FilePos, i).tointeger();
                            i += 5;
                            local YPos = UnpackData(FilePos, i).tointeger();
                            i += 5;
                            local ZPos = UnpackData(FilePos, i).tointeger();
                            i += 5;
                            local Tbuf = {
                                path = DirPath + Path.tolower(),
                                layer = Layer,
                                x = XPos - 9,
                                y = YPos - 9,
                                z = ZPos - 9
                            }
                            MapAtt.animation.append(Tbuf);
                        }
                    }
                    //背景动画
                    else if (str == "[background animation]") {
                        MapAtt.backgroundani <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/background animation]") break;
                            if (Ret == "[ani info]") {
                                local AniBuf = {};
                                while (true) {
                                    local Key = UnpackData(FilePos, i);
                                    i += 5;
                                    if (Key == "[/ani info]") break;
                                    local Value = UnpackData(FilePos, i);
                                    i += 5;
                                    if (Key == "[filename]") Value = DirPath + Value.tolower();
                                    AniBuf[Key] <- Value;
                                }
                                MapAtt.backgroundani.append(AniBuf);
                            }
                        }
                    }
                } else break;
            }

        }
        return MapAtt;
    }

    function GetMap(Idx) {
        if (MapLst.rawin(Idx)) {
            local Path = MapLst[Idx];
            if (MapConfigLst.rawin(Path)) return MapConfigLst[Path];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_map(DirPath, FileRealName, Info);
            MapConfigLst[Path] <- InfoObj;
            return InfoObj;
        } else error(Idx + " 号地图不存在!");
    }

    function Decompile_tile(Info) {
        local TileAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;
                    if (str == "[IMAGE]") {
                        local gpath = "sprite/" + UnpackData(FilePos, i).tolower();
                        i += 5;
                        local gidx = UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                        TileAtt.image <- {
                            path = gpath,
                            idx = gidx
                        }
                    }
                    //偏移
                    else if (str == "[img pos]") {
                        TileAtt.pos <- UnpackData(FilePos, i).tointeger();
                        i += 5;
                    }
                } else break;
            }

        }
        return TileAtt;
    }


    //读取地板
    function GetTile(Path) {
        if (TileConfigLst.rawin(Path)) return TileConfigLst[Path];
        local Info = GetFileInfo(Path);
        local InfoObj = Decompile_tile(Info);
        TileConfigLst[Path] <- InfoObj;
        return InfoObj;
    }

    function Decompile_passiveobject(DirPath, FileRealName, Info) {
        local PassiveobjectAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;
                    //大小
                    if (str == "[size]") {
                        local gx = UnpackData(FilePos, i);
                        i += 5;
                        local gy = UnpackData(FilePos, i);
                        i += 5;
                        PassiveobjectAtt.size <- {
                            x = gx.tointeger(),
                            y = gy.tointeger()
                        };
                    }
                    //浮动高度 图层 通过类型 名字
                    else if (str == "[floating height]" || str == "[layer]" || str == "[pass type]" || str == "[name]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        PassiveobjectAtt[RealKey] <- UnpackData(FilePos, i);
                        i += 5;
                    }
                    //Ani
                    else if (str == "[animotion]") {
                        PassiveobjectAtt.animotion <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/animotion]") break;
                            PassiveobjectAtt.animotion.append(DirPath + Ret.tolower());
                        }
                    }
                    //Atk
                    else if (str == "[attack info]") {
                        PassiveobjectAtt.attackinfo <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/attack info]") break;
                            PassiveobjectAtt.attackinfo.append(DirPath + Ret.tolower());
                        }
                    }
                    //回调函数
                    else if (str == "[create function]" || str == "[proc function]" || str == "[destroy function]" || str == "[attack function]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        local Path = UnpackData(FilePos, i);
                        i += 5;
                        // Path = "sqr/PassiveObjectFunc/" + Path + ".nut";
                        // PassiveobjectAtt[RealKey] <- dofile(Path);
                        Path = "PassiveObject_" + Path;
                        if (getroottable().PassiveObjectFunction.rawin(Path))
                            PassiveobjectAtt[RealKey] <- getroottable().PassiveObjectFunction[Path];
                    }
                } else break;
            }

        }
        return PassiveobjectAtt;
    }

    //获取被动对象
    function GetPassiveObject(Idx) {
        if (PassiveObjectLst.rawin(Idx)) {
            local Path = PassiveObjectLst[Idx];
            if (PassiveObjectConfigLst.rawin(Path)) return PassiveObjectConfigLst[Path];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_passiveobject(DirPath, FileRealName, Info);
            PassiveObjectConfigLst[Path] <- InfoObj;
            return InfoObj;
        } else error(Idx + " 号被动对象不存在!");
    }



    function Decompile_character(DirPath, FileRealName, Info) {
        local CharacterAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;

                    //职业
                    if (str == "[job]") {
                        local RealKey = str.slice(1, -1);
                        CharacterAtt[RealKey] <- UnpackData(FilePos, i).slice(1, -1);
                        i += 5;
                    }
                    //基础属性
                    else if (str == "[HP MAX]]" || str == "[MP MAX]]" || str == "[physical attack]]" || str == "[physical defense]]" || str == "[magical attack]]" || str == "[magical defense]]" || str == "[inventory limit]]" || str == "[MP regen speed]]" || str == "[move speed]]" || str == "[attack speed]]" || str == "[cast speed]]" || str == "[hit recovery]]" || str == "[jump power]]" || str == "[weight]]" || str == "[jump speed]]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        CharacterAtt[RealKey] <- UnpackData(FilePos, i).tofloat();
                        i += 5;
                    }
                    //基础Ani
                    else if (str == "[waiting motion]" || str == "[move motion]" || str == "[sit motion]" || str == "[damage motion 1]" || str == "[damage motion 2]" || str == "[down motion]" || str == "[overturn motion]" || str == "[jump motion]" || str == "[jumpattack motion]" || str == "[rest motion]" || str == "[throw motion 1-1]" || str == "[throw motion 1-2]" || str == "[throw motion 2-1]" || str == "[throw motion 2-2]" || str == "[throw motion 3-1]" || str == "[throw motion 3-2]" || str == "[throw motion 4-1]" || str == "[throw motion 4-2]" || str == "[dash motion]" || str == "[dashattack motion]" || str == "[getitem motion]" || str == "[buff motion]" || str == "[simple rest motion]" || str == "[simple move motion]" || str == "[back motion]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        CharacterAtt[RealKey] <- (UnpackData(FilePos, i).tolower());
                        i += 5;
                    }
                    //普攻Ani
                    else if (str == "[attack motion]") {
                        CharacterAtt.attack_motion <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/attack motion]") break;
                            CharacterAtt.attack_motion.append(Ret.tolower());
                        }
                    }
                    //进阶Ani
                    else if (str == "[etc motion]") {
                        CharacterAtt.etc_motion <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/etc motion]") break;
                            CharacterAtt.etc_motion.append(Ret.tolower());
                        }
                    }
                    //基础Atk
                    else if (str == "[jumpattack info]" || str == "[dashattack info]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        CharacterAtt[RealKey] <- (DirPath + UnpackData(FilePos, i).tolower());
                        i += 5;
                    }
                    //普攻Atk
                    else if (str == "[attack info]") {
                        CharacterAtt.attack_info <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/attack info]") break;
                            CharacterAtt.attack_info.append(DirPath + Ret.tolower());
                        }
                    }
                    //进阶Atk
                    else if (str == "[etc attack info]") {
                        CharacterAtt.etc_attack_info <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/etc attack info]") break;
                            CharacterAtt.etc_attack_info.append(DirPath + Ret.tolower());
                        }
                    }

                } else break;
            }

        }
        return CharacterAtt;
    }
    //获取角色配置
    function GetCharacter(Idx) {
        //如果已经读取过配置 直接返回配置
        if (CharacterConfigLst.rawin(Idx)) return CharacterConfigLst[Idx];
        if (CharacterLst.rawin(Idx)) {
            local Path = CharacterLst[Idx];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_character(DirPath, FileRealName, Info);
            InfoObj.DirPath <- DirPath;
            CharacterConfigLst[Idx] <- InfoObj;
            // Util.PrintTable(InfoObj);
            return InfoObj;
        } else error(Idx + " 号角色配置不存在!");
    }


    function Decompile_equipment(DirPath, FileRealName, Info) {
        local EquipmentAtt = {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;

                    //名称
                    if (str == "[name]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        EquipmentAtt[RealKey] <- UnpackData(FilePos, i);
                        i += 5;
                    }
                    //grade 套装Id
                    else if (str == "[grade]" || str == "[part set index]" || str == "[anti evil]" || str == "[sb dongcai]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        EquipmentAtt[RealKey] <- UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                    }
                    //适用角色
                    else if (str == "[usable job]") {
                        EquipmentAtt.usable_job <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/usable job]") break;
                            EquipmentAtt.usable_job.append(Ret.slice(1, -1).tolower());
                        }
                    }
                    //图标
                    else if (str == "[icon]") {
                        EquipmentAtt.icon <- {};
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        EquipmentAtt.icon.path <- Ret.tolower();
                        Ret = UnpackData(FilePos, i);
                        i += 5;
                        EquipmentAtt.icon.index <- Ret.tointeger();
                    }
                    //装备类型
                    else if (str == "[equipment type]") {
                        EquipmentAtt.type <- {};
                        local Ret = UnpackData(FilePos, i);
                        i += 5;
                        EquipmentAtt.type.path <- Ret.tolower().slice(1, -1);
                        Ret = UnpackData(FilePos, i);
                        i += 5;
                        EquipmentAtt.type.index <- Ret.tointeger();
                    }
                    //Ani
                    else if (str == "[animation job]") {
                        local Job = UnpackData(FilePos, i).slice(1, -1);
                        i += 5;
                        EquipmentAtt["Ani_" + Job] <- {};
                        i += 5;

                        local Index1 = UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                        local Index2 = UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                        EquipmentAtt["Ani_" + Job].variation <- [Index1, Index2];
                        EquipmentAtt["Ani_" + Job].layer_variation <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[animation job]" || (endswith(Ret, "]") && Ret != "[equipment ani script]" && Ret != "[layer variation]")) {
                                i -= 5;
                                break;
                            } else if (Ret == "[layer variation]") {
                                local InfoBuf = {};
                                InfoBuf.Zorder <- UnpackData(FilePos, i).tointeger() - 9;
                                i += 5;
                                InfoBuf.Path <- UnpackData(FilePos, i);
                                i += 5;
                                EquipmentAtt["Ani_" + Job].layer_variation.append(InfoBuf);
                            }
                        }
                    }



                } else break;
            }

        }
        return EquipmentAtt;
    }

    //获取装备配置
    function GetEquipment(Idx) {
        //如果已经读取过配置 直接返回配置
        if (EquipmentConfigLst.rawin(Idx)) return EquipmentConfigLst[Idx];
        if (EquipmentLst.rawin(Idx)) {
            local Path = EquipmentLst[Idx];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_equipment(DirPath, FileRealName, Info);
            InfoObj.DirPath <- DirPath;
            EquipmentConfigLst[Idx] <- InfoObj;
            // Util.PrintTable(InfoObj);
            return InfoObj;
        } else error(Idx + " 号装备配置不存在!");
    }


    function Decompile_aicharacter(DirPath, FileRealName, Info) {
        local AICharacterAtt = {};
        //属性表
        AICharacterAtt.Attributes <- {};
        IO.seek(StartPos + Info.ROffset);
        local FilePos = IO.tell();
        local out = "";
        if (Info.Length >= 7) {
            //以5为单步从第二位开始遍历字节
            local i = 2;
            while (true) {
                //到最后了就不处理了防止内存越界
                if (i< Info.Length && Info.Length - i >= 5) {
                    local str = UnpackData(FilePos, i);
                    i += 5;

                    //名称
                    if (str == "[name]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        AICharacterAtt[RealKey] <- UnpackData(FilePos, i);
                        i += 5;
                    }
                    //属性
                    else if (str == "[HpMax]" || str == "[Attack]" || str == "[Speed]" || str == "[Defense]" || str == "[DeployCost]" || str == "[Resilience]" || str == "[FirePower]" || str == "[IcePower]" || str == "[LightningPower]" || str == "[DarkPower]" || str == "[FireResistance]" || str == "[IceResistance]" || str == "[LightningResistance]" || str == "[DarkResistance]") {
                        local RealKey = str.slice(1, str.len() - 1);
                        AICharacterAtt.Attributes[RealKey] <- UnpackData(FilePos, i).tointeger() - 9;
                        i += 5;
                    }
                    //装备
                    else if (str == "[equipment]") {
                        AICharacterAtt.equipment <- [];
                        while (true) {
                            local Ret = UnpackData(FilePos, i);
                            i += 5;
                            if (Ret == "[/equipment]") break;
                            AICharacterAtt.equipment.append(Ret.tointeger() - 9);
                        }
                    }
                    //基础信息
                    else if (str == "[minimum info]") {
                        AICharacterAtt["minimum info"] <- [];
                        for (local o = 0; o< 16; o++) {
                            local Buf = UnpackData(FilePos, i);
                            i += 5;
                            if (o == 0 || o == 12) {
                                AICharacterAtt["minimum info"].append(Buf);
                            } else {
                                AICharacterAtt["minimum info"].append(Buf.tointeger() - 9);
                            }
                        }
                    }
                } else break;
            }

        }
        return AICharacterAtt;
    }

    //获取APC配置
    function GetAICharacter(Idx) {
        //如果已经读取过配置 直接返回配置
        if (AICharacterConfigLst.rawin(Idx)) return AICharacterConfigLst[Idx];
        if (AICharacterLst.rawin(Idx)) {
            local Path = AICharacterLst[Idx];
            local Pos = 0;
            while (true) {
                local Buf = Path.find("/", Pos + 1);
                if (Buf != null)
                    Pos = Buf;
                else break;
            }
            local DirPath = Path.slice(0, Pos + 1);
            local FileRealName = Path.slice(Pos + 1);
            local Info = GetFileInfo(Path);
            local InfoObj = Decompile_aicharacter(DirPath, FileRealName, Info);
            InfoObj.DirPath <- DirPath;
            AICharacterConfigLst[Idx] <- InfoObj;
            // Util.PrintTable(InfoObj);
            return InfoObj;
        } else error(Idx + " 号APC配置不存在!");
    }

}
getroottable().ScriptData <- GlobaData();