HonorLee 5 months ago
parent
commit
3b01548c18

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.DS_Stor
+*.meta

+ 0 - 351
CGTool/AudioTool.cs

@@ -1,351 +0,0 @@
-/**
- * 魔力宝贝图档解析脚本 - CGTool
- * 
- * @Author  HonorLee (dev@honorlee.me)
- * @Version 1.0 (2023-08-26)
- * @License GPL-3.0
- *
- * AudioTool.cs 音频工具
- * 本工具用于加载音频AudioClip,音频文件位于Assets/Resources/Audio目录下并使用Resources.Load加载
- * 请将Crossgate的音频目录bgm、se拷贝到Assets/Resources/Audio目录下
- * 如有其他需要可调整加载方式
- */
-using System.Collections.Generic;
-using UnityEngine;
-
-namespace CGTool
-{
-    public static class AudioTool
-    {
-
-        // 背景音频缓存
-        private static Dictionary<int, AudioClip> _bgmDic = new Dictionary<int, AudioClip>();
-        // 声效音频缓存
-        private static Dictionary<int, AudioClip> _effectDic = new Dictionary<int, AudioClip>();
-
-        public enum Type
-        {
-            BGM,
-            EFFECT
-        }
-        // 获取指定类型、编号的音频AudioClip
-        public static AudioClip GetAudio(Type type, int id)
-        {
-            AudioClip audioClip;
-            Dictionary<int,AudioClip> dic = type == Type.BGM ? _bgmDic : _effectDic;
-            if (dic.TryGetValue(id, out audioClip))
-            {
-                return audioClip;
-            }
-            else
-            {
-                Dictionary<int,string> map = type == Type.BGM ? _bgmMap : _effectMap;
-                if(map.TryGetValue(id, out string audioPath))
-                {
-                    audioClip = UnityEngine.Resources.Load<AudioClip>(audioPath);
-                    return audioClip;
-                }
-                else
-                {
-                    // Debug.LogError("Audio not found: " + id);
-                }
-            }
-
-            return null;
-        }
-
-        private static Dictionary<int, string> _bgmMap = new Dictionary<int, string>()
-        {
-            [200] = "Audio/bgm/cgbgm_m0",
-            [201] = "Audio/bgm/cgbgm_m1",
-            [202] = "Audio/bgm/cgbgm_m2",
-            [203] = "Audio/bgm/cgbgm_m3",
-            [204] = "Audio/bgm/cgbgm_m4",
-            [209] = "Audio/bgm/cgbgm_f0",
-            [210] = "Audio/bgm/cgbgm_f1",
-            [211] = "Audio/bgm/cgbgm_f2",
-            [212] = "Audio/bgm/cgbgm_d0",
-            [213] = "Audio/bgm/cgbgm_d1",
-            [214] = "Audio/bgm/cgbgm_d2",
-            [215] = "Audio/bgm/cgbgm_d3",
-            [216] = "Audio/bgm/cgbgm_d4",
-            [205] = "Audio/bgm/cgbgm_b0",
-            [206] = "Audio/bgm/cgbgm_b1",
-            [207] = "Audio/bgm/cgbgm_b2",
-            [208] = "Audio/bgm/cgbgm_b3",
-            [217] = "Audio/bgm/cgbgm_t0",
-            [219] = "Audio/bgm/exbgm_s0",
-            [220] = "Audio/bgm/exbgm_f0",
-            [221] = "Audio/bgm/exbgm_m0",
-            [222] = "Audio/bgm/v2bgm_f0",
-            [223] = "Audio/bgm/v2bgm_m0",
-            [224] = "Audio/bgm/v2bgm_ex",
-            [225] = "Audio/bgm/v2bgm_ex",
-            [226] = "Audio/bgm/puk2_battle1",
-            [227] = "Audio/bgm/puk2_battle2",
-            [228] = "Audio/bgm/puk2_field1",
-            [229] = "Audio/bgm/puk2_mati",
-            [230] = "Audio/bgm/puk2_sinden",
-            [231] = "Audio/bgm/puk2_yama",
-            [232] = "Audio/bgm/puk2_haikyo",
-            [233] = "Audio/bgm/puk2_m_town",
-            [234] = "Audio/bgm/puk2_OP",
-            [235] = "Audio/bgm/puk3_battle1",
-            [236] = "Audio/bgm/puk3_battle2",
-            [237] = "Audio/bgm/puk3_dungeon",
-            [238] = "Audio/bgm/puk3_kame",
-            [239] = "Audio/bgm/puk3_kujira",
-            [240] = "Audio/bgm/puk3_kumo",
-            [241] = "Audio/bgm/puk3_love",
-            [242] = "Audio/bgm/puk3_playerbattle",
-            [243] = "Audio/bgm/PUK3_title",
-        };
-
-        private static Dictionary<int, string> _effectMap = new Dictionary<int, string>()
-        {
-            [1] = "Audio/se/cgnat00",
-            [2] = "Audio/se/cgnat01",
-            [3] = "Audio/se/cgnat02",
-            [4] = "Audio/se/cgnat03",
-            [5] = "Audio/se/cgnat04",
-            [6] = "Audio/se/cgnat05a",
-            [7] = "Audio/se/cgnat05b",
-            [8] = "Audio/se/cgnat06a",
-            [9] = "Audio/se/cgnat06b",
-            [10] = "Audio/se/cgnat07",
-            [11] = "Audio/se/cgnat08",
-            [12] = "Audio/se/cgnat09",
-            [13] = "Audio/se/cgnat10",
-            [14] = "Audio/se/cgnat11",
-            [15] = "Audio/se/exnat00",
-            [16] = "Audio/se/v2mon150a",
-            [17] = "Audio/se/34sand_clock",
-            [18] = "Audio/se/35sand_clock",
-            [19] = "Audio/se/36wind",
-            [20] = "Audio/se/37bird",
-            [21] = "Audio/se/puk3_Wind01",
-            [22] = "Audio/se/puk3_Wind02",
-            [23] = "Audio/se/puk3_Wind03",
-            [24] = "Audio/se/puk3_gaya01",
-            [25] = "Audio/se/puk3_drop01",
-            [26] = "Audio/se/puk3_drop02",
-            [51] = "Audio/se/cgsys00",
-            [52] = "Audio/se/cgsys01",
-            [53] = "Audio/se/cgsys02",
-            [54] = "Audio/se/cgsys03",
-            [55] = "Audio/se/cgsys04",
-            [56] = "Audio/se/cgsys05",
-            [57] = "Audio/se/cgsys06",
-            [58] = "Audio/se/cgsys07",
-            [59] = "Audio/se/cgsys08",
-            [60] = "Audio/se/cgsys09",
-            [61] = "Audio/se/cgsys10a",
-            [62] = "Audio/se/cgsys10b",
-            [63] = "Audio/se/cgsys11",
-            [64] = "Audio/se/cgsys12",
-            [65] = "Audio/se/cgsys13a",
-            [66] = "Audio/se/cgsys13b",
-            [67] = "Audio/se/cgsys13c",
-            [68] = "Audio/se/cgsys14",
-            [69] = "Audio/se/cgsys15",
-            [71] = "Audio/se/cgsys17",
-            [72] = "Audio/se/cgsys18",
-            [73] = "Audio/se/cgsys19",
-            [74] = "Audio/se/cgsys20",
-            [75] = "Audio/se/cgsys21",
-            [76] = "Audio/se/cgsys22",
-            [77] = "Audio/se/cgsys23",
-            [78] = "Audio/se/cgsys24",
-            [79] = "Audio/se/cgsys25",
-            [101] = "Audio/se/cgply00a",
-            [102] = "Audio/se/cgply00b",
-            [103] = "Audio/se/cgply01a",
-            [104] = "Audio/se/cgply01b",
-            [105] = "Audio/se/cgply02a",
-            [106] = "Audio/se/cgply02b",
-            [107] = "Audio/se/cgply03a",
-            [108] = "Audio/se/cgply03b",
-            [109] = "Audio/se/cgply04a",
-            [110] = "Audio/se/cgply04b",
-            [111] = "Audio/se/cgply05a",
-            [112] = "Audio/se/cgply05b",
-            [113] = "Audio/se/cgply06a1",
-            [114] = "Audio/se/cgply06b1",
-            [115] = "Audio/se/cgply06a2",
-            [116] = "Audio/se/cgply06b2",
-            [117] = "Audio/se/cgply07a",
-            [118] = "Audio/se/cgply07b",
-            [131] = "Audio/se/cgply06a2",
-            [132] = "Audio/se/cgply06b2",
-            [133] = "Audio/se/cgply11a",
-            [134] = "Audio/se/cgply11b",
-            [135] = "Audio/se/cgply12a",
-            [136] = "Audio/se/cgply12b",
-            [137] = "Audio/se/cgply13a",
-            [138] = "Audio/se/cgply13b",
-            [139] = "Audio/se/cgply14a",
-            [140] = "Audio/se/cgply14b",
-            [141] = "Audio/se/cgply15",
-            [142] = "Audio/se/cgply16",
-            [143] = "Audio/se/cgply17",
-            [147] = "Audio/se/cgply00a",
-            [150] = "Audio/se/cgply11b",
-            [151] = "Audio/se/cgmon00a",
-            [152] = "Audio/se/cgmon00b",
-            [153] = "Audio/se/cgmon01",
-            [154] = "Audio/se/cgmon02a",
-            [155] = "Audio/se/cgmon02b",
-            [156] = "Audio/se/cgmon03b",
-            [157] = "Audio/se/cgmon10",
-            [158] = "Audio/se/cgmon20",
-            [159] = "Audio/se/cgmon24",
-            [160] = "Audio/se/cgmon30",
-            [161] = "Audio/se/cgmon31",
-            [162] = "Audio/se/cgmon41",
-            [163] = "Audio/se/cgmon43",
-            [164] = "Audio/se/cgmon50a",
-            [165] = "Audio/se/cgmon50b",
-            [166] = "Audio/se/cgmon51",
-            [167] = "Audio/se/cgmon52",
-            [168] = "Audio/se/cgmon60",
-            [169] = "Audio/se/cgmon61",
-            [171] = "Audio/se/cgmon63",
-            [172] = "Audio/se/cgmon90",
-            [173] = "Audio/se/cgmon91",
-            [174] = "Audio/se/cgmon92",
-            [175] = "Audio/se/cgmon93",
-            [180] = "Audio/se/cgmon_bs1",
-            [181] = "Audio/se/cgmon_bs2",
-            [182] = "Audio/se/cgmon_bs3",
-            [183] = "Audio/se/cgmon_bs4",
-            [184] = "Audio/se/cgmon_bh1",
-            [185] = "Audio/se/cgmon_bh2",
-            [186] = "Audio/se/cgmon_bh3",
-            [187] = "Audio/se/cgmon_bh4",
-            [190] = "Audio/se/cgmon_m00",
-            [191] = "Audio/se/cgmon_m01",
-            [192] = "Audio/se/cgmon_m02",
-            [198] = "Audio/se/cgmon_sample01",
-            [199] = "Audio/se/cgmon_sample02",
-            [200] = "Audio/se/cgmon_sample03",
-            [201] = "Audio/se/cgbtl00",
-            [202] = "Audio/se/cgbtl01",
-            [204] = "Audio/se/cgbtl03",
-            [205] = "Audio/se/cgbtl04",
-            [206] = "Audio/se/cgbtl05",
-            [207] = "Audio/se/cgbtl06",
-            [208] = "Audio/se/cgbtl07",
-            [209] = "Audio/se/cgbtl08",
-            [210] = "Audio/se/cgbtl09",
-            [211] = "Audio/se/cgbtl10",
-            [212] = "Audio/se/cgbtl11",
-            [213] = "Audio/se/cgbtl12",
-            [214] = "Audio/se/cgbtl13",
-            [215] = "Audio/se/cgbtl14",
-            [216] = "Audio/se/cgbtl15",
-            [217] = "Audio/se/cgbtl16",
-            [218] = "Audio/se/cgbtl17",
-            [251] = "Audio/se/cgefc00",
-            [252] = "Audio/se/cgefc01",
-            [253] = "Audio/se/cgefc02",
-            [254] = "Audio/se/cgefc03",
-            [255] = "Audio/se/cgefc04",
-            [256] = "Audio/se/cgefc05",
-            [257] = "Audio/se/cgefc06",
-            [258] = "Audio/se/cgefc07",
-            [259] = "Audio/se/cgefc08",
-            [260] = "Audio/se/cgefc09",
-            [261] = "Audio/se/cgefc10",
-            [262] = "Audio/se/cgefc11",
-            [263] = "Audio/se/cgefc12",
-            [264] = "Audio/se/cgefc13",
-            [266] = "Audio/se/cgefc15",
-            [267] = "Audio/se/cgefc16",
-            [268] = "Audio/se/cgefc17",
-            [269] = "Audio/se/cgefc18",
-            [270] = "Audio/se/cgefc19",
-            [271] = "Audio/se/cgefc20",
-            [272] = "Audio/se/cgefc21",
-            [273] = "Audio/se/cgefc22",
-            [274] = "Audio/se/cgefc23",
-            [275] = "Audio/se/cgefc24",
-            [276] = "Audio/se/cgefc25",
-            [277] = "Audio/se/cgefc26",
-            [278] = "Audio/se/cgefc27",
-            [279] = "Audio/se/cgefc28",
-            [280] = "Audio/se/cgefc29",
-            [281] = "Audio/se/cgefc30",
-            [282] = "Audio/se/cgefc31",
-            [283] = "Audio/se/cgefc32",
-            [284] = "Audio/se/cgefc33",
-            [285] = "Audio/se/cgefc34",
-            [286] = "Audio/se/cgefc35",
-            [287] = "Audio/se/cgefc36",
-            [288] = "Audio/se/cgefc37a",
-            [289] = "Audio/se/cgefc37b",
-            [290] = "Audio/se/cgefc37c",
-            [291] = "Audio/se/cgefc38",
-            [296] = "Audio/se/v2monex1",
-            [297] = "Audio/se/v2monex2",
-            [298] = "Audio/se/v2monex3",
-            [300] = "Audio/se/v2mon100",
-            [301] = "Audio/se/v2mon110",
-            [302] = "Audio/se/v2mon111a",
-            [303] = "Audio/se/v2mon111b",
-            [304] = "Audio/se/v2mon120",
-            [305] = "Audio/se/v2mon121a",
-            [306] = "Audio/se/v2mon121b",
-            [307] = "Audio/se/v2mon121c",
-            [308] = "Audio/se/v2mon130",
-            [309] = "Audio/se/v2mon140",
-            [310] = "Audio/se/v2mon150a",
-            [311] = "Audio/se/v2mon150b",
-            [312] = "Audio/se/v2mon161",
-            [313] = "Audio/se/v2mon170a",
-            [314] = "Audio/se/v2mon170b",
-            [315] = "Audio/se/v2mon171a",
-            [316] = "Audio/se/v2mon171b",
-            [317] = "Audio/se/v2mon190",
-            [318] = "Audio/se/v2mon191",
-            [319] = "Audio/se/v2monex0",
-            [400] = "Audio/se/01small_amae_new",
-            [401] = "Audio/se/02small_normal",
-            [402] = "Audio/se/02small_normal_new",
-            [403] = "Audio/se/03small_iyaiya",
-            [404] = "Audio/se/03small_iyaiya_new",
-            [405] = "Audio/se/04fish_normal",
-            [406] = "Audio/se/05fish_shout",
-            [407] = "Audio/se/06fish_amae",
-            [408] = "Audio/se/09kame_amae",
-            [409] = "Audio/se/10yagi_shout",
-            [410] = "Audio/se/11yagi_normal",
-            [411] = "Audio/se/12yagi_amae",
-            [412] = "Audio/se/13bird_normal",
-            [413] = "Audio/se/14bird_shout",
-            [414] = "Audio/se/15bird_amae",
-            [415] = "Audio/se/16fish_normal",
-            [416] = "Audio/se/17fish_shout",
-            [417] = "Audio/se/18kame_normal",
-            [418] = "Audio/se/19kame_shout",
-            [419] = "Audio/se/20animal_normal",
-            [420] = "Audio/se/21animal_shout",
-            [421] = "Audio/se/22bird_normal",
-            [422] = "Audio/se/23bird_shout",
-            [423] = "Audio/se/24Monstor",
-            [424] = "Audio/se/25_1_off",
-            [425] = "Audio/se/26ground_on",
-            [426] = "Audio/se/27ground_off",
-            [427] = "Audio/se/28_water_on",
-            [428] = "Audio/se/29_water_of",
-            [429] = "Audio/se/30fire_on",
-            [430] = "Audio/se/31fire_of",
-            [431] = "Audio/se/32_wind_on",
-            [432] = "Audio/se/32_wind_on2",
-            [433] = "Audio/se/33_wind_off",
-            [435] = "Audio/se/36wind",
-            [436] = "Audio/se/37bird",
-            [437] = "Audio/se/38make_gild",
-            [438] = "Audio/se/39levelup",
-        };
-    }
-}

+ 0 - 52
CGTool/CGTool.cs

@@ -1,52 +0,0 @@
-/**
- * 魔力宝贝图档解析脚本 - CGTool
- * 
- * @Author  HonorLee (dev@honorlee.me)
- * @Version 1.0 (2023-04-15)
- * @License GPL-3.0
- *
- * CGTool.cs 入口文件
- */
-
-using UnityEngine;
-
-namespace CGTool
-{
-    public static class CGTool
-    {
-        //Bin基础目录
-        public static string BaseFolder = System.Environment.CurrentDirectory + "/bin";
-        //Palet调色板目录
-        public static string PaletFolder = BaseFolder + "/pal";
-        //Map地图文件目录
-        public static string MapFolder = BaseFolder + "/map";
-
-        //初始化CGTool
-        public static void Init(string binPath = null)
-        {
-            if (!string.IsNullOrEmpty(binPath))
-            {
-                BaseFolder = binPath;
-                PaletFolder = BaseFolder + "/pal";
-                MapFolder = BaseFolder + "/map";
-            }
-            //初始化加载并缓存 0-15 调色板文件
-            for (int i = 0; i < 16; i++) Palet.GetPalet(i);
-            
-            //初始化加载并缓存GraphicInfo配置表
-            GraphicInfo.Init();
-            
-            //初始化图档解析器
-            Graphic.Init();
-            
-            //初始化加载动画序列信息
-            Anime.Init();
-
-            //地图索引初始化
-            Map.Init();
-
-            Debug.Log("CGTool初始化完成");
-        }
-
-    }
-}

+ 0 - 206
CGTool/GraphicInfo.cs

@@ -1,206 +0,0 @@
-/**
- * 魔力宝贝图档解析脚本 - CGTool
- * 
- * @Author  HonorLee (dev@honorlee.me)
- * @Version 1.0 (2023-04-15)
- * @License GPL-3.0
- *
- * GraphicInfo.cs 图档索引解析类
- */
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text.RegularExpressions;
-using UnityEngine;
-
-namespace CGTool
-{
-    //GraphicInfo数据块
-    public class GraphicInfoData
-    {
-        //版本号
-        public int Version;
-        //4 bytes   索引
-        public uint Index;
-        //4 bytes   Graphic 地址
-        public uint Addr;
-        //4 bytes   Graphic 数据长度
-        public uint Length;
-        //4 bytes   Graphic 偏移 - X
-        public int OffsetX;
-        //4 bytes   Graphic 偏移 - Y
-        public int OffsetY;
-        //4 bytes   Graphic 宽
-        public uint Width;
-        //4 bytes   Graphic 高
-        public uint Height;
-        //4 bytes   Graphic East占地
-        public int East;
-        //4 bytes   Graphic South 占地
-        public int South;
-        //bool      穿越标识
-        public bool Blocked;
-        //1 byte    作为地面无层级遮挡[Test]
-        public bool AsGround;
-        //4 bytes   未知标识
-        public byte[] Unknow;
-        //4 bytes   编号
-        public uint Serial;
-        public int[] UnpackedPaletIndex;
-    }
-
-    public class GraphicInfo:MonoBehaviour
-    {
-        // private static Logger _logger = new Logger("GraphicInfo", false);
-        //版本索引字典    版本编号
-        private static Dictionary<int, List<GraphicInfoData>> _cache = new Dictionary<int, List<GraphicInfoData>>();
-
-        //版本-Addr映射字典   版本编号 -> Index -> GraphicInfoData
-        private static Dictionary<int, Dictionary<uint, GraphicInfoData>>
-            _indexDict = new Dictionary<int, Dictionary<uint, GraphicInfoData>>();
-        
-        //版本-Map编号映射字典  版本编号 -> MapSerial -> GraphicInfoData
-        private static Dictionary<int, Dictionary<uint, GraphicInfoData>>
-            _SerialDict = new Dictionary<int, Dictionary<uint, GraphicInfoData>>();
-
-        
-        private static Dictionary<int,string> _graphicInfoVersionPrefix = new Dictionary<int, string>()
-        {
-            //龙之沙漏 之前版本前Info数据
-            {0,@"GraphicInfo_\d+"},
-            //龙之沙漏 版本Info数据
-            {1,@"GraphicInfoEx_\d+"}
-        };
-        
-        private static List<string> _graphicInfoPaths = new List<string>();
-
-        public static void Init()
-        {
-            DirectoryInfo directoryInfo = new DirectoryInfo(CGTool.BaseFolder);
-            FileInfo[] files = directoryInfo.GetFiles();
-            //查找所有GraphicInfo数据文件
-            for (int i = 0; i < _graphicInfoVersionPrefix.Count; i++)
-            {
-                foreach (FileInfo fileInfo in files)
-                {
-                    if (Regex.IsMatch(fileInfo.Name, _graphicInfoVersionPrefix[i]))
-                    {
-                        _graphicInfoPaths.Add(fileInfo.Name);
-                        List<GraphicInfoData> list = GetGraphicInfo(i);
-                        Debug.Log("初始化GraphicInfo数据,版本号:" + i + ",数据量:" + list.Count + "条");
-                        break;
-                    }
-                }
-            }
-        }
-
-        //获取GraphicInfo数据,Info数据加载后会缓存
-        public static List<GraphicInfoData> GetGraphicInfo(int Version)
-        {
-            //返回缓存数据
-            if (_cache.ContainsKey(Version)) return _cache[Version];
-            
-            //初始化映射库
-            _indexDict.Add(Version,new Dictionary<uint, GraphicInfoData>());
-            _SerialDict.Add(Version,new Dictionary<uint, GraphicInfoData>());
-            //加载并初始化数据
-            List<GraphicInfoData> infoDatas = _loadGraphicInfo(Version);
-            _cache.Add(Version, infoDatas);
-            
-            return infoDatas;
-        }
-        //通过编号获取GraphicInfo数据
-        public static GraphicInfoData GetGraphicInfoDataBySerial(int Version, uint Serial)
-        {
-            GraphicInfoData graphicInfoData = null;
-            if (_SerialDict.ContainsKey(Version))
-            {
-                _SerialDict[Version].TryGetValue(Serial, out graphicInfoData);
-                // graphicInfoData = _mapSerialDict[Version][MapSerial];
-            }
-
-            return graphicInfoData;
-        }
-        //通过编号获取GraphicInfo数据
-        public static GraphicInfoData GetGraphicInfoDataBySerial(uint Serial)
-        {
-            int Version = Serial >= 2000000 ? 1 : 0;
-            GraphicInfoData graphicInfoData = null;
-            if (_SerialDict.ContainsKey(Version) && _SerialDict[Version].ContainsKey(Serial))
-            {
-                
-                graphicInfoData = _SerialDict[Version][Serial];
-            }
-
-            return graphicInfoData;
-        }
-        //通过索引获取GraphicInfo数据
-        public static GraphicInfoData GetGraphicInfoDataByIndex(int Version, uint Index)
-        {
-            GraphicInfoData graphicInfoData = null;
-            if (_indexDict.ContainsKey(Version) && _indexDict[Version].ContainsKey(Index))
-            {
-                graphicInfoData = _indexDict[Version][Index];
-            }
-
-            return graphicInfoData;
-        }
-        
-        
-        
-        //初始化加载GraphicInfo
-        private static List<GraphicInfoData> _loadGraphicInfo(int Version)
-        {
-            //查找Info文件
-            string fileName = _graphicInfoPaths[Version];
-            FileInfo file = new FileInfo(CGTool.BaseFolder + "/" + fileName);
-            if (!file.Exists) return null;
-
-            //创建流读取器
-            FileStream fileStream = file.OpenRead();
-            BinaryReader fileReader = new BinaryReader(fileStream); 
-            
-            //解析Info数据表
-            List<GraphicInfoData> infoDatas = new List<GraphicInfoData>();
-            long DataLength = fileStream.Length/40;
-            for (int i = 0; i < DataLength; i++)
-            {
-                GraphicInfoData graphicInfoData = new GraphicInfoData();
-                graphicInfoData.Version = Version;
-                graphicInfoData.Index = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.Addr = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.Length = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.OffsetX = BitConverter.ToInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.OffsetY = BitConverter.ToInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.Width = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.Height = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-                graphicInfoData.East = fileReader.ReadByte();
-                graphicInfoData.South = fileReader.ReadByte();
-                graphicInfoData.Blocked =  fileReader.ReadByte() == 0;
-                graphicInfoData.AsGround = fileReader.ReadByte() == 1;
-                graphicInfoData.Unknow = fileReader.ReadBytes(4);
-                graphicInfoData.Serial = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
-
-                //建立映射表
-                if(!_indexDict[Version].ContainsKey(graphicInfoData.Index)) _indexDict[Version].Add(graphicInfoData.Index, graphicInfoData);
-                if(graphicInfoData.Serial > 0 && !_SerialDict[Version].ContainsKey(graphicInfoData.Serial)) _SerialDict[Version].Add(graphicInfoData.Serial, graphicInfoData);
-                
-                infoDatas.Add(graphicInfoData);
-
-                // _logger.Write("Index: " + graphicInfoData.Index + " Addr: " + graphicInfoData.Addr + 
-                //               " Width: " + graphicInfoData.Width + 
-                //               " Height: " + graphicInfoData.Height +
-                //               " OffsetX: " + graphicInfoData.OffsetX +
-                //               " OffsetY: " + graphicInfoData.OffsetY +
-                //               " East: " + graphicInfoData.East +
-                //               " South: " + graphicInfoData.South +
-                //               " Blocked: " + graphicInfoData.Blocked +
-                //               " Unknow: " + BitConverter.ToString(graphicInfoData.Unknow).Replace("-", ",") +
-                //               " MapSerial: " + graphicInfoData.MapSerial);
-            }
-            // CGTool.Logger.Write("加载GraphicInfo - 版本: " + Version + " 文件: " + fileName + " 贴图总量: "+ infoDatas.Count);
-            return infoDatas;
-        }
-    }
-}

+ 142 - 228
CGTool/Anime.cs

@@ -11,17 +11,17 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Text.RegularExpressions;
 using UnityEngine;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
     //动画信息
     public class AnimeInfo
     {
-        public int Version;
-        //4 bytes   动画索引
-        public uint Index;
+        // 版本
+        public string Version;
+        //4 bytes   动画序号
+        public uint Serial;
         //4 bytes   动画文件地址
         public uint Addr;
         //2 bytes   动作数量
@@ -58,8 +58,8 @@ namespace CGTool
     //动画数据
     public class AnimeDetail
     {
-        public uint Index;
-        public int Version;
+        public uint Serial;
+        public string Version;
         public int Direction;
         public int ActionType;
         public uint CycleTime;
@@ -75,15 +75,15 @@ namespace CGTool
         //方向
         public enum DirectionType
         {
-            NULL=-1,
-            North=0,
-            NorthEast=1,
-            East=2,
-            SouthEast=3,
-            South=4,
-            SouthWest=5,
-            West=6,
-            NorthWest=7
+            NULL        = -1,
+            North       = 0,
+            NorthEast   = 1,
+            East        = 2,
+            SouthEast   = 3,
+            South       = 4,
+            SouthWest   = 5,
+            West        = 6,
+            NorthWest   = 7
         }
         //方向九宫映射表
         public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3]
@@ -95,35 +95,35 @@ namespace CGTool
         //动作
         public enum ActionType
         {
-            NULL=-1,
-            Stand=0,
-            Walk=1,
-            BeforeRun=2,
-            Run=3,
-            AfterRun=4,
-            Attack=5,
-            Magic=6,
-            Throw=7,
-            Hurt=8,
-            Defence=9,
-            Dead=10,
-            Sit=11,
-            Hi=12,
-            Happy=13,
-            Angry=14,
-            Sad=15,
-            Shake=16,
-            Rock=17,
-            Scissors=18,
-            Paper=19,
-            Fishing=20,
+            NULL        = -1,
+            Stand       = 0,
+            Walk        = 1,
+            BeforeRun   = 2,
+            Run         = 3,
+            AfterRun    = 4,
+            Attack      = 5,
+            Magic       = 6,
+            Throw       = 7,
+            Hurt        = 8,
+            Defence     = 9,
+            Dead        = 10,
+            Sit         = 11,
+            Hi          = 12,
+            Happy       = 13,
+            Angry       = 14,
+            Sad         = 15,
+            Shake       = 16,
+            Rock        = 17,
+            Scissors    = 18,
+            Paper       = 19,
+            Fishing     = 20,
             
         }
         //动效
         public enum EffectType
         {
-            Hit=1,
-            HitOver=2
+            Hit     =1,
+            HitOver =2
         }
 
         public enum PlayType
@@ -132,72 +132,100 @@ namespace CGTool
             Once,
             OnceAndDestroy
         }
-        //动画列表缓存    Index -> AnimeInfo
+        //动画列表缓存    Serial -> AnimeInfo
         private static Dictionary<uint, AnimeInfo> _animeInfoCache = new Dictionary<uint, AnimeInfo>();
-
-        //动画序列文件前缀    Direction -> Action -> AnimeData
-        private static Dictionary<int,string> _animeInfoVersionPrefex = new Dictionary<int, string>()
-        {
-            //龙之沙漏 之前版本前Info数据
-            {0,@"AnimeInfo_\d+"},
-            //龙之沙漏 版本Info数据
-            {1,@"AnimeInfoEx_\d+"}
-        };
-        private static List<string> _animeInfoFilePaths = new List<string>();
-
-        //动画数据文件前缀
-        private static Dictionary<int,string> _animeDataVersionPrefex = new Dictionary<int, string>()
+        
+        //加载动画数据
+        public static void Init(string Version,FileInfo animeInfoFile,FileInfo animeFile)
         {
-            //龙之沙漏 之前版本前Data数据
-            {0,@"Anime_\d+"},
-            //龙之沙漏 版本Data数据
-            {1,@"AnimeEx_\d+"}
-        };
-        private static List<string> _animeDataFilePaths = new List<string>();
+            //创建流读取器
+            FileStream infoFileStream = animeInfoFile.OpenRead();
+            FileStream dataFileStream = animeFile.OpenRead();
+            BinaryReader infoFileReader = new BinaryReader(infoFileStream);
+            BinaryReader dataFileReader = new BinaryReader(dataFileStream);
 
-        //初始化并缓存动画信息
-        public static void Init()
-        {
-            DirectoryInfo directoryInfo = new DirectoryInfo(CGTool.BaseFolder);
-            FileInfo[] files = directoryInfo.GetFiles();
-            
-            for (int i = 0; i < _animeInfoVersionPrefex.Count; i++)
+            // Dictionary<uint, AnimeInfo> animeInfos = new Dictionary<uint, AnimeInfo>();
+            long DataLength = infoFileStream.Length / 12;
+            for (int i = 0; i < DataLength; i++)
             {
-                foreach (FileInfo fileInfo in files)
+                //初始化对象
+                AnimeInfo animeInfo = new AnimeInfo();
+                animeInfo.Version = Version;
+                animeInfo.Serial = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
+                // Debug.Log(animeInfo.Serial);
+                animeInfo.Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
+                animeInfo.ActionCount = infoFileReader.ReadUInt16();
+                animeInfo.Unknow = infoFileReader.ReadBytes(2);
+                dataFileStream.Position = animeInfo.Addr;
+                for (int j = 0; j < animeInfo.ActionCount; j++)
                 {
-                    if (Regex.IsMatch(fileInfo.Name, _animeInfoVersionPrefex[i]))
-                    {
-                        _animeInfoFilePaths.Add(fileInfo.Name);
-                    }
-                    if(Regex.IsMatch(fileInfo.Name,_animeDataVersionPrefex[i]))
+                    AnimeDetail animeData = new AnimeDetail();
+                    animeData.Version = Version;
+                    animeData.Serial = animeInfo.Serial;
+                    animeData.Direction = dataFileReader.ReadUInt16();
+                    animeData.ActionType = dataFileReader.ReadUInt16();
+                    animeData.CycleTime = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
+                    animeData.FrameCount = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
+                    animeData.AnimeFrameInfos = new AnimeFrameInfo[animeData.FrameCount];
+
+                    
+                    
+                    // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
+                    for (int k = 0; k < animeData.FrameCount; k++)
                     {
-                        _animeDataFilePaths.Add(fileInfo.Name);
+                        animeData.AnimeFrameInfos[k] = new AnimeFrameInfo();
+                        //GraphicIndex序号
+                        animeData.AnimeFrameInfos[k].GraphicIndex = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
+                        animeData.AnimeFrameInfos[k].OffsetX = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
+                        animeData.AnimeFrameInfos[k].OffsetY = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
+                        
+                        //标识位
+                        int flag = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
+
+                        // if (animeData.Index == 110053) Debug.Log("FLAG---" + " " + k + "  " + flag);
+
+                        if (flag>20000)
+                        {
+                            //击打判定
+                            animeData.AnimeFrameInfos[k].Effect = EffectType.Hit;
+                            animeData.AnimeFrameInfos[k].AudioIndex = flag - 20000;
+                        }
+                        else if(flag>10000)
+                        {
+                            //攻击动作结束判定
+                            animeData.AnimeFrameInfos[k].Effect = EffectType.HitOver;
+                            animeData.AnimeFrameInfos[k].AudioIndex = flag - 10000;
+                        }
+                        else
+                        {
+                            animeData.AnimeFrameInfos[k].AudioIndex = flag;
+                        }
                     }
+
+                    if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
+                        animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
+
+                    animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
+                    
+                    _animeInfoCache[animeInfo.Serial] = animeInfo;
                 }
+
             }
-            if(_animeInfoFilePaths.Count==0) Debug.LogError("未找到动画信息文件");
-            if(_animeDataFilePaths.Count==0) Debug.LogError("未找到动画数据文件");
-            if(_animeDataFilePaths.Count!=_animeInfoFilePaths.Count) Debug.LogError("动画信息文件与动画数据文件数量不匹配");
+            infoFileReader.Dispose();
+            infoFileReader.Close();
+            dataFileReader.Dispose();
+            dataFileReader.Close();
+            infoFileStream.Close();
+            dataFileStream.Close();
             
-            //加载动画信息
-            for (int i = 0; i < _animeInfoFilePaths.Count; i++)
-            {
-                
-                Dictionary<uint, AnimeInfo> animeInfos = _loadAnimeInfo(i);
-                Debug.Log("加载动画信息版本:[" + i + "]  动画数量:" + animeInfos.Count);
-            }
+            Debug.Log("[CGTool] 加载AnimeInfo - 文件: " + animeInfoFile.Name + " 动画总量: " + DataLength);
         }
+        
         //获取动画数据信息
-        public static AnimeInfo GetAnimeInfo(uint Index)
+        public static AnimeInfo GetAnimeInfo(uint serial)
         {
-            //返回缓存
-            if (_animeInfoCache.ContainsKey(Index)) return _animeInfoCache[Index];
-            //动画编号大于105000的属于 龙之沙漏 版本
-            int Version = 0;
-            if (Index >= 105000) Version = 1;
-            Dictionary<uint, AnimeInfo> animeInfos = _loadAnimeInfo(Version);
-            if (animeInfos.ContainsKey(Index)) return animeInfos[Index];
-            return null;
+            _animeInfoCache.TryGetValue(serial, out var animeInfo);
+            return animeInfo;
         }
 
         //获取动画数据
@@ -211,7 +239,7 @@ namespace CGTool
                 {
                     AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action];
                     // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail);
-                    return animeInfo.AnimeDatas[(int)Direction][(int) Action];
+                    return animeDetail;
                 }
             }
 
@@ -219,11 +247,11 @@ namespace CGTool
         }
 
         //预处理动画图形合批烘焙
-        public static void BakeAnimeFrames(AnimeDetail animeDetail,int paletIndex = 0)
+        public static void BakeAnimeFrames(AnimeDetail animeDetail,int palet = 0)
         {
-            if(animeDetail.AnimeTextures.ContainsKey(paletIndex)) return;
+            if(animeDetail.AnimeTextures.ContainsKey(palet)) return;
             //所有帧的图形数据
-            GraphicData[] graphicDatas = new GraphicData[animeDetail.FrameCount];
+            GraphicDetail[] graphicDetails = new GraphicDetail[animeDetail.FrameCount];
             
             //合并后的Texture2D尺寸
             uint textureWidth = 0;
@@ -235,13 +263,13 @@ namespace CGTool
                 //载入图档
                 GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex);
                 if (graphicInfoData == null) continue;
-                GraphicData graphicData = Graphic.GetGraphicData(graphicInfoData, paletIndex);
-                if(graphicData == null) continue;
-                graphicDatas[i] = graphicData;
-                if(graphicData.Height > textureHeight) textureHeight = graphicData.Height;
-                textureWidth += graphicData.Width + 5;
-                animeDetail.AnimeFrameInfos[i].Width = (int) graphicData.Width;
-                animeDetail.AnimeFrameInfos[i].Height = (int) graphicData.Height;
+                GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData, palet);
+                if(graphicDetail == null) continue;
+                graphicDetails[i] = graphicDetail;
+                if(graphicDetail.Height > textureHeight) textureHeight = graphicDetail.Height;
+                textureWidth += graphicDetail.Width + 5;
+                animeDetail.AnimeFrameInfos[i].Width = (int) graphicDetail.Width;
+                animeDetail.AnimeFrameInfos[i].Height = (int) graphicDetail.Height;
                 animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX;
                 animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY;
                 animeDetail.AnimeFrameInfos[i].GraphicInfo = graphicInfoData;
@@ -260,22 +288,22 @@ namespace CGTool
             int offsetX = 0;
             for (var i = 0; i < animeDetail.FrameCount; i++)
             {
-                GraphicData graphicData = graphicDatas[i];
-                if(graphicData == null) continue;
-                texture2dMix.SetPixels32((int) offsetX, 0, (int) graphicData.Width,
-                    (int) graphicData.Height,
-                    graphicData.Sprite.texture.GetPixels32());
-                offsetX += (int) graphicData.Width + 5;
+                GraphicDetail graphicDetail = graphicDetails[i];
+                if(graphicDetail == null) continue;
+                texture2dMix.SetPixels32((int) offsetX, 0, (int) graphicDetail.Width,
+                    (int) graphicDetail.Height,
+                    graphicDetail.Sprite.texture.GetPixels32());
+                offsetX += (int) graphicDetail.Width + 5;
             }
             texture2dMix.Apply();
             
-            animeDetail.AnimeTextures.Add(paletIndex,texture2dMix);
+            animeDetail.AnimeTextures.Add(palet,texture2dMix);
             
             //创建动画每帧Sprite
             offsetX = 0;
             for (var l = 0; l < animeDetail.FrameCount; l++)
             {
-                if(graphicDatas[l] == null) continue;
+                if(graphicDetails[l] == null) continue;
                 AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[l];
                 Vector2 pivot = new Vector2(0f, 1f);
                 pivot.x += -(animeFrameInfo.OffsetX * 1f) / animeFrameInfo.Width;
@@ -284,125 +312,11 @@ namespace CGTool
                         animeDetail.AnimeFrameInfos[l].Width, animeDetail.AnimeFrameInfos[l].Height),
                     pivot, 1, 1, SpriteMeshType.FullRect);
                 offsetX += animeDetail.AnimeFrameInfos[l].Width + 5;
-                animeFrameInfo.AnimeSprites.Add(paletIndex, sprite);
+                animeFrameInfo.AnimeSprites.Add(palet, sprite);
             }
             
         }
         
-        //加载动画数据
-        private static Dictionary<uint, AnimeInfo> _loadAnimeInfo(int Version)
-        {
-            //查找Info文件
-            string infoFileName = _animeInfoFilePaths[Version];
-            string dataFileName = _animeDataFilePaths[Version];
-            FileInfo infoFile = new FileInfo(CGTool.BaseFolder + "/" + infoFileName);
-            FileInfo dataFile = new FileInfo(CGTool.BaseFolder + "/" + dataFileName);
-            if (!infoFile.Exists || !dataFile.Exists) return null;
-
-            //创建流读取器
-            FileStream infoFileStream = infoFile.OpenRead();
-            FileStream dataFileStream = dataFile.OpenRead();
-            BinaryReader infoFileReader = new BinaryReader(infoFileStream);
-            BinaryReader dataFileReader = new BinaryReader(dataFileStream);
-
-            // Dictionary<uint, AnimeInfo> animeInfos = new Dictionary<uint, AnimeInfo>();
-            long DataLength = infoFileStream.Length / 12;
-            for (int i = 0; i < DataLength; i++)
-            {
-                //初始化对象
-                AnimeInfo animeInfo = new AnimeInfo();
-                animeInfo.Version = Version;
-                animeInfo.Index = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
-                animeInfo.Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
-                animeInfo.ActionCount = infoFileReader.ReadUInt16();
-                animeInfo.Unknow = infoFileReader.ReadBytes(2);
-                dataFileStream.Position = animeInfo.Addr;
-                for (int j = 0; j < animeInfo.ActionCount; j++)
-                {
-                    AnimeDetail animeData = new AnimeDetail();
-                    animeData.Index = animeInfo.Index;
-                    animeData.Version = Version;
-                    animeData.Direction = dataFileReader.ReadUInt16();
-                    animeData.ActionType = dataFileReader.ReadUInt16();
-                    animeData.CycleTime = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
-                    animeData.FrameCount = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
-                    animeData.AnimeFrameInfos = new AnimeFrameInfo[animeData.FrameCount];
-                    
-                    
-                    // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
-                    for (int k = 0; k < animeData.FrameCount; k++)
-                    {
-                        animeData.AnimeFrameInfos[k] = new AnimeFrameInfo();
-                        //GraphicIndex序号
-                        animeData.AnimeFrameInfos[k].GraphicIndex = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
-                        //未知字节
-                        // animeData.unknown = dataFileReader.ReadBytes(6);
-                        // if (animeInfo.Index == 101201)
-                        // {
-                        //     byte[] tt = dataFileReader.ReadBytes(6);
-                        // }
-                        // else
-                        // {
-                        //     dataFileReader.ReadBytes(6);
-                        // }
-                        animeData.AnimeFrameInfos[k].OffsetX = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
-                        animeData.AnimeFrameInfos[k].OffsetY = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
-                        
-                        //标识位
-                        int flag = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
-
-                        // if (animeData.Index == 110053) Debug.Log("FLAG---" + " " + k + "  " + flag);
-
-                        if (flag>20000)
-                        {
-                            //击打判定
-                            animeData.AnimeFrameInfos[k].Effect = EffectType.Hit;
-                            animeData.AnimeFrameInfos[k].AudioIndex = flag - 20000;
-                        }
-                        else if(flag>10000)
-                        {
-                            //攻击动作结束判定
-                            animeData.AnimeFrameInfos[k].Effect = EffectType.HitOver;
-                            animeData.AnimeFrameInfos[k].AudioIndex = flag - 10000;
-                        }
-                        else
-                        {
-                            animeData.AnimeFrameInfos[k].AudioIndex = flag;
-                        }
-                    }
-
-                    if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
-                        animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
-
-                    if (animeInfo.AnimeDatas[animeData.Direction].ContainsKey(animeData.ActionType))
-                    {
-                        animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
-                    }
-                    else
-                    {
-                        animeInfo.AnimeDatas[animeData.Direction].Add(animeData.ActionType, animeData);
-                    }
-
-                    if (_animeInfoCache.ContainsKey(animeInfo.Index))
-                    {
-                        _animeInfoCache[animeInfo.Index] = animeInfo;
-                    }
-                    else
-                    {
-                        _animeInfoCache.Add(animeInfo.Index, animeInfo);
-                    }
-                }
-
-            }
-
-            infoFileReader.Dispose();
-            infoFileReader.Close();
-            dataFileReader.Dispose();
-            dataFileReader.Close();
-            infoFileStream.Close();
-            dataFileStream.Close();
-
-            return _animeInfoCache;
-        }
+        
     }
 }

+ 8 - 7
CGTool/AnimePlayer.cs

@@ -12,7 +12,7 @@ using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
     //动画周期回调
     public delegate void AnimeCallback(Anime.ActionType actionType);
@@ -336,19 +336,20 @@ namespace CGTool
                 for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Length; i++)
                 {
                     AnimeFrameInfo animeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
-                    GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeOption.AnimeDetail.Version, animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex);
+                    GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(
+                        animeOption.AnimeDetail.Version, animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex);
                     if (graphicInfoData == null)
                     {
-                        Debug.Log("GraphicInfo Version:" + animeOption.AnimeDetail.Version + " Index:" +
-                                  animeOption.AnimeDetail.AnimeFrameInfos[i] + " is null");
+                        Debug.Log("GraphicInfo Serial:" +
+                                  animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
                         continue;
                     }
 
-                    GraphicData graphicData = Graphic.GetGraphicData(graphicInfoData, _paletIndex);
+                    GraphicDetail graphicData = GraphicData.GetGraphicDetail(graphicInfoData, _paletIndex);
                     if (graphicData == null)
                     {
-                        Debug.Log("GraphicData Version:" + animeOption.AnimeDetail.Version + " Index:" +
-                                  animeOption.AnimeDetail.AnimeFrameInfos[i] + " is null");
+                        Debug.Log("GraphicData Serial:" +
+                                  animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
                         continue;
                     }
                 

+ 411 - 0
CrossgateToolkit/Audio.cs

@@ -0,0 +1,411 @@
+/**
+ * 魔力宝贝图档解析脚本 - CGTool
+ * 
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 1.0 (2023-08-26)
+ * @License GPL-3.0
+ *
+ * AudioTool.cs 音频工具
+ * 本工具用于加载音频AudioClip,音频文件位于Assets/Resources/Audio目录下并使用Resources.Load加载
+ * 请将Crossgate的音频目录bgm、se拷贝到Assets/Resources/Audio目录下
+ * 如有其他需要可调整加载方式
+ */
+
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using Unity.VisualScripting;
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace CrossgateToolkit
+{
+    public static class Audio
+    {
+
+        // 背景音频缓存
+        private static Dictionary<int, AudioClip> _bgmDic = new Dictionary<int, AudioClip>();
+        // 声效音频缓存
+        private static Dictionary<int, AudioClip> _effectDic = new Dictionary<int, AudioClip>();
+
+        public enum Type
+        {
+            BGM,
+            EFFECT
+        }
+        // 获取指定类型、编号的音频AudioClip
+        public static void Play(AudioSource audioSource,Type type, int id)
+        {
+            AudioClip audioClip;
+            Dictionary<int,AudioClip> dic = type == Type.BGM ? _bgmDic : _effectDic;
+            if (dic.TryGetValue(id, out audioClip))
+            {
+                return;
+            }
+            else
+            {
+                Dictionary<int,string> map = type == Type.BGM ? _bgmMap : _effectMap;
+                if(map.TryGetValue(id, out string audioName))
+                {
+                    string path = type == Type.BGM ? CGTool.PATH.BGM : CGTool.PATH.AUDIO;
+                    if (string.IsNullOrEmpty(path))
+                    {
+                        path = type == Type.BGM ? "Audio/bgm" : "Audio/se";
+                        audioClip = Resources.Load<AudioClip>(path + "/" + audioName);
+                        if (audioClip == null) return;
+                        
+                        dic.Add(id, audioClip);
+                        _playAudio(audioSource, audioClip);
+                    }
+                    else
+                    {
+                        DirectoryInfo directoryInfo = new DirectoryInfo(path);
+                        FileInfo[] files = directoryInfo.GetFiles(audioName + ".wav", SearchOption.AllDirectories);
+                        if (files.Length > 0)
+                        {
+                            string filePath = files[0].FullName;
+                            
+                            CoroutineRunner.instance.StartCoroutine(LoadAudioClipAsync(filePath, loadedAudioClip =>
+                            {
+                                if (loadedAudioClip != null)
+                                {
+                                    dic.Add(id, loadedAudioClip);
+                                    _playAudio(audioSource, loadedAudioClip);
+                                }
+                            }));
+                        }
+                    }
+                    
+                }
+            }
+        }
+
+        private static void _playAudio(AudioSource audioSource, AudioClip audioClip)
+        {
+            audioSource.Stop();
+            audioSource.clip = audioClip;
+            audioSource.Play();
+        }
+        
+        private delegate void AudioClipLoaded(AudioClip audioClip);
+        private static IEnumerator LoadAudioClipAsync(string filePath, AudioClipLoaded onAudioLoaded)
+        {
+            if (File.Exists(filePath))
+            {
+                string audioURL = "file://" + filePath;
+
+                using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(audioURL, AudioType.UNKNOWN))
+                {
+                    yield return www.SendWebRequest();
+                    if (www.result == UnityWebRequest.Result.Success)
+                    {
+                        AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
+                        onAudioLoaded?.Invoke(audioClip);
+                    }
+                    else
+                    {
+                        onAudioLoaded?.Invoke(null);
+                    }
+                }
+            }
+            else
+            {
+                onAudioLoaded?.Invoke(null);
+            }
+        }
+
+        private static Dictionary<int, string> _bgmMap = new Dictionary<int, string>()
+        {
+            [200] = "cgbgm_m0",
+            [201] = "cgbgm_m1",
+            [202] = "cgbgm_m2",
+            [203] = "cgbgm_m3",
+            [204] = "cgbgm_m4",
+            [209] = "cgbgm_f0",
+            [210] = "cgbgm_f1",
+            [211] = "cgbgm_f2",
+            [212] = "cgbgm_d0",
+            [213] = "cgbgm_d1",
+            [214] = "cgbgm_d2",
+            [215] = "cgbgm_d3",
+            [216] = "cgbgm_d4",
+            [205] = "cgbgm_b0",
+            [206] = "cgbgm_b1",
+            [207] = "cgbgm_b2",
+            [208] = "cgbgm_b3",
+            [217] = "cgbgm_t0",
+            [219] = "exbgm_s0",
+            [220] = "exbgm_f0",
+            [221] = "exbgm_m0",
+            [222] = "v2bgm_f0",
+            [223] = "v2bgm_m0",
+            [224] = "v2bgm_ex",
+            [225] = "v2bgm_ex",
+            [226] = "puk2_battle1",
+            [227] = "puk2_battle2",
+            [228] = "puk2_field1",
+            [229] = "puk2_mati",
+            [230] = "puk2_sinden",
+            [231] = "puk2_yama",
+            [232] = "puk2_haikyo",
+            [233] = "puk2_m_town",
+            [234] = "puk2_OP",
+            [235] = "puk3_battle1",
+            [236] = "puk3_battle2",
+            [237] = "puk3_dungeon",
+            [238] = "puk3_kame",
+            [239] = "puk3_kujira",
+            [240] = "puk3_kumo",
+            [241] = "puk3_love",
+            [242] = "puk3_playerbattle",
+            [243] = "PUK3_title",
+        };
+
+        private static Dictionary<int, string> _effectMap = new Dictionary<int, string>()
+        {
+            [1] = "cgnat00",
+            [2] = "cgnat01",
+            [3] = "cgnat02",
+            [4] = "cgnat03",
+            [5] = "cgnat04",
+            [6] = "cgnat05a",
+            [7] = "cgnat05b",
+            [8] = "cgnat06a",
+            [9] = "cgnat06b",
+            [10] = "cgnat07",
+            [11] = "cgnat08",
+            [12] = "cgnat09",
+            [13] = "cgnat10",
+            [14] = "cgnat11",
+            [15] = "exnat00",
+            [16] = "v2mon150a",
+            [17] = "34sand_clock",
+            [18] = "35sand_clock",
+            [19] = "36wind",
+            [20] = "37bird",
+            [21] = "puk3_Wind01",
+            [22] = "puk3_Wind02",
+            [23] = "puk3_Wind03",
+            [24] = "puk3_gaya01",
+            [25] = "puk3_drop01",
+            [26] = "puk3_drop02",
+            [51] = "cgsys00",
+            [52] = "cgsys01",
+            [53] = "cgsys02",
+            [54] = "cgsys03",
+            [55] = "cgsys04",
+            [56] = "cgsys05",
+            [57] = "cgsys06",
+            [58] = "cgsys07",
+            [59] = "cgsys08",
+            [60] = "cgsys09",
+            [61] = "cgsys10a",
+            [62] = "cgsys10b",
+            [63] = "cgsys11",
+            [64] = "cgsys12",
+            [65] = "cgsys13a",
+            [66] = "cgsys13b",
+            [67] = "cgsys13c",
+            [68] = "cgsys14",
+            [69] = "cgsys15",
+            [71] = "cgsys17",
+            [72] = "cgsys18",
+            [73] = "cgsys19",
+            [74] = "cgsys20",
+            [75] = "cgsys21",
+            [76] = "cgsys22",
+            [77] = "cgsys23",
+            [78] = "cgsys24",
+            [79] = "cgsys25",
+            [101] = "cgply00a",
+            [102] = "cgply00b",
+            [103] = "cgply01a",
+            [104] = "cgply01b",
+            [105] = "cgply02a",
+            [106] = "cgply02b",
+            [107] = "cgply03a",
+            [108] = "cgply03b",
+            [109] = "cgply04a",
+            [110] = "cgply04b",
+            [111] = "cgply05a",
+            [112] = "cgply05b",
+            [113] = "cgply06a1",
+            [114] = "cgply06b1",
+            [115] = "cgply06a2",
+            [116] = "cgply06b2",
+            [117] = "cgply07a",
+            [118] = "cgply07b",
+            [131] = "cgply06a2",
+            [132] = "cgply06b2",
+            [133] = "cgply11a",
+            [134] = "cgply11b",
+            [135] = "cgply12a",
+            [136] = "cgply12b",
+            [137] = "cgply13a",
+            [138] = "cgply13b",
+            [139] = "cgply14a",
+            [140] = "cgply14b",
+            [141] = "cgply15",
+            [142] = "cgply16",
+            [143] = "cgply17",
+            [147] = "cgply00a",
+            [150] = "cgply11b",
+            [151] = "cgmon00a",
+            [152] = "cgmon00b",
+            [153] = "cgmon01",
+            [154] = "cgmon02a",
+            [155] = "cgmon02b",
+            [156] = "cgmon03b",
+            [157] = "cgmon10",
+            [158] = "cgmon20",
+            [159] = "cgmon24",
+            [160] = "cgmon30",
+            [161] = "cgmon31",
+            [162] = "cgmon41",
+            [163] = "cgmon43",
+            [164] = "cgmon50a",
+            [165] = "cgmon50b",
+            [166] = "cgmon51",
+            [167] = "cgmon52",
+            [168] = "cgmon60",
+            [169] = "cgmon61",
+            [171] = "cgmon63",
+            [172] = "cgmon90",
+            [173] = "cgmon91",
+            [174] = "cgmon92",
+            [175] = "cgmon93",
+            [180] = "cgmon_bs1",
+            [181] = "cgmon_bs2",
+            [182] = "cgmon_bs3",
+            [183] = "cgmon_bs4",
+            [184] = "cgmon_bh1",
+            [185] = "cgmon_bh2",
+            [186] = "cgmon_bh3",
+            [187] = "cgmon_bh4",
+            [190] = "cgmon_m00",
+            [191] = "cgmon_m01",
+            [192] = "cgmon_m02",
+            [198] = "cgmon_sample01",
+            [199] = "cgmon_sample02",
+            [200] = "cgmon_sample03",
+            [201] = "cgbtl00",
+            [202] = "cgbtl01",
+            [204] = "cgbtl03",
+            [205] = "cgbtl04",
+            [206] = "cgbtl05",
+            [207] = "cgbtl06",
+            [208] = "cgbtl07",
+            [209] = "cgbtl08",
+            [210] = "cgbtl09",
+            [211] = "cgbtl10",
+            [212] = "cgbtl11",
+            [213] = "cgbtl12",
+            [214] = "cgbtl13",
+            [215] = "cgbtl14",
+            [216] = "cgbtl15",
+            [217] = "cgbtl16",
+            [218] = "cgbtl17",
+            [251] = "cgefc00",
+            [252] = "cgefc01",
+            [253] = "cgefc02",
+            [254] = "cgefc03",
+            [255] = "cgefc04",
+            [256] = "cgefc05",
+            [257] = "cgefc06",
+            [258] = "cgefc07",
+            [259] = "cgefc08",
+            [260] = "cgefc09",
+            [261] = "cgefc10",
+            [262] = "cgefc11",
+            [263] = "cgefc12",
+            [264] = "cgefc13",
+            [266] = "cgefc15",
+            [267] = "cgefc16",
+            [268] = "cgefc17",
+            [269] = "cgefc18",
+            [270] = "cgefc19",
+            [271] = "cgefc20",
+            [272] = "cgefc21",
+            [273] = "cgefc22",
+            [274] = "cgefc23",
+            [275] = "cgefc24",
+            [276] = "cgefc25",
+            [277] = "cgefc26",
+            [278] = "cgefc27",
+            [279] = "cgefc28",
+            [280] = "cgefc29",
+            [281] = "cgefc30",
+            [282] = "cgefc31",
+            [283] = "cgefc32",
+            [284] = "cgefc33",
+            [285] = "cgefc34",
+            [286] = "cgefc35",
+            [287] = "cgefc36",
+            [288] = "cgefc37a",
+            [289] = "cgefc37b",
+            [290] = "cgefc37c",
+            [291] = "cgefc38",
+            [296] = "v2monex1",
+            [297] = "v2monex2",
+            [298] = "v2monex3",
+            [300] = "v2mon100",
+            [301] = "v2mon110",
+            [302] = "v2mon111a",
+            [303] = "v2mon111b",
+            [304] = "v2mon120",
+            [305] = "v2mon121a",
+            [306] = "v2mon121b",
+            [307] = "v2mon121c",
+            [308] = "v2mon130",
+            [309] = "v2mon140",
+            [310] = "v2mon150a",
+            [311] = "v2mon150b",
+            [312] = "v2mon161",
+            [313] = "v2mon170a",
+            [314] = "v2mon170b",
+            [315] = "v2mon171a",
+            [316] = "v2mon171b",
+            [317] = "v2mon190",
+            [318] = "v2mon191",
+            [319] = "v2monex0",
+            [400] = "01small_amae_new",
+            [401] = "02small_normal",
+            [402] = "02small_normal_new",
+            [403] = "03small_iyaiya",
+            [404] = "03small_iyaiya_new",
+            [405] = "04fish_normal",
+            [406] = "05fish_shout",
+            [407] = "06fish_amae",
+            [408] = "09kame_amae",
+            [409] = "10yagi_shout",
+            [410] = "11yagi_normal",
+            [411] = "12yagi_amae",
+            [412] = "13bird_normal",
+            [413] = "14bird_shout",
+            [414] = "15bird_amae",
+            [415] = "16fish_normal",
+            [416] = "17fish_shout",
+            [417] = "18kame_normal",
+            [418] = "19kame_shout",
+            [419] = "20animal_normal",
+            [420] = "21animal_shout",
+            [421] = "22bird_normal",
+            [422] = "23bird_shout",
+            [423] = "24Monstor",
+            [424] = "25_1_off",
+            [425] = "26ground_on",
+            [426] = "27ground_off",
+            [427] = "28_water_on",
+            [428] = "29_water_of",
+            [429] = "30fire_on",
+            [430] = "31fire_of",
+            [431] = "32_wind_on",
+            [432] = "32_wind_on2",
+            [433] = "33_wind_off",
+            [435] = "36wind",
+            [436] = "37bird",
+            [437] = "38make_gild",
+            [438] = "39levelup",
+        };
+    }
+}

+ 63 - 0
CrossgateToolkit/CGTool.cs

@@ -0,0 +1,63 @@
+/**
+ * 魔力宝贝图档解析脚本 - CGTool
+ * 
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 2.0 (2023-11-19)
+ * @License GPL-3.0
+ *
+ * CGTool.cs 入口文件
+ */
+
+using System;
+using System.IO;
+using UnityEngine;
+
+namespace CrossgateToolkit
+{
+    public static class CGTool
+    {
+        // 路径配置
+        public class CGPath
+        {
+            // 调色板目录
+            public string PAL;
+            // 图档目录
+            public string BIN;
+            // 地图目录
+            public string MAP;
+            // BGM目录
+            public string BGM;
+            // 音效目录
+            public string AUDIO;
+            
+        }
+        
+        // 基础路径默认配置 
+        public static CGPath PATH = new CGPath()
+        {
+            BIN = Environment.CurrentDirectory + "/bin",
+            PAL = Environment.CurrentDirectory + "/pal",
+            MAP = Environment.CurrentDirectory + "/map",
+            BGM = Environment.CurrentDirectory + "/bgm",
+            AUDIO = Environment.CurrentDirectory + "/se"
+        };
+
+        /**
+         * 初始化CGTool,并按顺序加载并初始化指定模块
+         * Graphic加载顺序以Bin目录中的文件名排序
+         * 其中Bin目录根目录下优先级最高,其次是Bin目录下的子目录
+         */
+        public static void Init()
+        {
+            // 初始化调色板
+            if (PATH.PAL != null) Palet.Init();
+            // 初始化图档解析器
+            if (PATH.BIN != null) Graphic.Init();
+            // 初始化地图索引
+            if (PATH.MAP != null) Map.Init();
+            Debug.Log("[CGTool] CGTool初始化完成");
+        }
+
+    }
+
+}

+ 147 - 0
CrossgateToolkit/Graphic.cs

@@ -0,0 +1,147 @@
+/**
+ * 魔力宝贝图档解析脚本 - CGTool
+ * 
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 1.0 (2023-04-15)
+ * @License GPL-3.0
+ *
+ * Graphic.cs 图档解析类
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEngine;
+
+namespace CrossgateToolkit
+{
+    //图档类
+    public static class Graphic
+    {
+        private class FilePair
+        {
+            public FileInfo InfoFile;
+            public FileInfo DataFile;
+            public string Version;
+        }
+        
+        // 临时文件列表缓存
+        private static List<FilePair> _graphicFilePairs = new List<FilePair>();
+        private static List<FilePair> _animeFilePairs = new List<FilePair>();
+        
+        // 初始化
+        public static void Init()
+        {
+            // 解析Bin文件目录结构
+            if(!Directory.Exists(CGTool.PATH.BIN)) throw new Exception("图档目录不存在,请检查CGTool中是否配置相应PATH路径");
+
+            // 整理目录结构,生成对应待处理文件列表
+            List<DirectoryInfo> _directorys = new List<DirectoryInfo>();
+            _directorys.Add(new DirectoryInfo(CGTool.PATH.BIN));
+            _directorys.AddRange(new DirectoryInfo(CGTool.PATH.BIN).GetDirectories().OrderBy(d => d.Name).ToList());
+            foreach (DirectoryInfo directory in _directorys)
+            {
+                AnalysisDirectory(directory);
+            }
+
+            Debug.Log("[CGTool] 图档资源查找完毕,共找到: (" + _graphicFilePairs.Count + ") 个图档文件, (" + _animeFilePairs.Count +
+                      ") 个动画文件");
+            
+            // 预加载 GraphicInfo
+            foreach (FilePair graphicFilePair in _graphicFilePairs)
+            {
+                GraphicInfo.Init(graphicFilePair.Version,graphicFilePair.InfoFile, graphicFilePair.DataFile);
+            }
+            
+            // 预加载 Anime
+            foreach (FilePair animeFilePair in _animeFilePairs)
+            {
+                Anime.Init(animeFilePair.Version, animeFilePair.InfoFile, animeFilePair.DataFile);
+            }
+        }
+
+        // 分析目录,并获取对应配对文件
+        private static void AnalysisDirectory(DirectoryInfo directoryInfo)
+        {
+            Debug.Log("[CGTool] 开始分析目录: " + directoryInfo.FullName);
+            string Version = directoryInfo.Name;
+            FileInfo[] fileInfos = directoryInfo.GetFiles();
+            fileInfos = fileInfos.OrderBy(f => f.Name).ToArray();
+            foreach (FileInfo fileInfo in fileInfos)
+            {
+                if (!fileInfo.Name.EndsWith(".bin",StringComparison.OrdinalIgnoreCase)) continue;
+                int suffixIndex = fileInfo.Name.LastIndexOf('.');
+                string versionStr;
+                if (fileInfo.Name.StartsWith("graphicinfo", StringComparison.OrdinalIgnoreCase))
+                {
+                    // 找到GraphicInfo文件
+                    // 获取对应版本号 GraphicInfo(*).bin
+                    versionStr = fileInfo.Name.Substring(11, suffixIndex - 11);
+                    // 判断是否存在对应graphic文件,忽略大小写
+                    string graphicFileName = "graphic" + versionStr + ".bin";
+                    FileInfo graphicFileInfo = GetFileInfoByName(fileInfo.Directory, graphicFileName);
+                    if (!graphicFileInfo.Exists)
+                    {
+                        throw new Exception("找不到对应的图档文件: " + fileInfo.FullName);
+                    }
+                    FilePair filePair = new FilePair()
+                    {
+                        InfoFile = fileInfo,
+                        DataFile = graphicFileInfo,
+                        Version = Version
+                    };
+                    _graphicFilePairs.Add(filePair);
+                }else if (fileInfo.Name.StartsWith("animeinfo", StringComparison.OrdinalIgnoreCase))
+                {
+                    // 找到AnimeInfo文件
+                    // 获取对应版本号 AnimeInfo(*).bin
+                    versionStr = fileInfo.Name.Substring(9, suffixIndex - 9);
+                    // 判断是否存在对应anime文件
+                    string animeFileName = "anime" + versionStr + ".bin";
+                    FileInfo animeFileInfo = GetFileInfoByName(fileInfo.Directory, animeFileName);
+                    if (!animeFileInfo.Exists)
+                    {
+                        throw new Exception("找不到对应的动画文件: " + fileInfo.FullName);
+                    }
+                    FilePair filePair = new FilePair()
+                    {
+                        InfoFile = fileInfo,
+                        DataFile = animeFileInfo,
+                        Version = Version
+                    };
+                    _animeFilePairs.Add(filePair);
+                }
+            }
+        }
+        
+        // 忽略大小写获取对应文件
+        private static FileInfo GetFileInfoByName(DirectoryInfo directoryInfo,string fileName)
+        {
+            FileInfo[] fileInfos = directoryInfo.GetFiles();
+            foreach (FileInfo fileInfo in fileInfos)
+            {
+                if (fileInfo.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase))
+                {
+                    return fileInfo;
+                }
+            }
+
+            return null;
+        }
+        
+        // 获取图档数据
+        public static GraphicDetail GetGraphicDetail(uint serial,int palet = 0)
+        {
+            GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(serial);
+            return GraphicData.GetGraphicDetail(graphicInfoData, palet);
+        }
+        
+        // 获取图档数据
+        public static GraphicDetail GetGraphicDetailByIndex(string Version,uint index,int palet = 0)
+        {
+            GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(Version, index);
+            return GraphicData.GetGraphicDetail(graphicInfoData, palet);
+        }
+    }
+}

+ 154 - 214
CGTool/Graphic.cs

@@ -2,33 +2,30 @@
  * 魔力宝贝图档解析脚本 - CGTool
  * 
  * @Author  HonorLee (dev@honorlee.me)
- * @Version 1.0 (2023-04-15)
+ * @Version 1.0 (2023-11-20)
  * @License GPL-3.0
  *
- * Graphic.cs 图档解析类
+ * GraphicData.cs 图档解析类
  */
 
-using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Text.RegularExpressions;
 using Unity.Burst;
 using Unity.Collections;
 using Unity.Jobs;
 using UnityEngine;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
-    public class GraphicData
+    //图档数据详情
+    public class GraphicDetail
     {
-        //版本号
-        public int Version;
         //索引
         public uint Index;
-        //地图编号
-        public uint MapSerial;
+        //编号
+        public uint Serial;
         //图档宽度
         public uint Width;
         //图档高度
@@ -37,113 +34,58 @@ namespace CGTool
         public int OffsetX;
         //图档偏移Y
         public int OffsetY;
-        //图档合批偏移X
-        public int BatchOffsetX;
-        //图档合批偏移Y
-        public int BatchOffsetY;
         //Palet调色板Index
-        public int PaletIndex;
+        public int Palet;
         //图档Sprite
         public Sprite Sprite;
         //图档主色调,用于小地图绘制
         public Color32 PrimaryColor;
     }
-    public class Graphic
+    // 图档数据
+    public static class GraphicData
     {
-        //缓存Addr  Version -> Addr -> PaletIndex -> GraphicData
-        private static Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>> _cache =
-            new Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>>();
+        // // 图档缓存  Serial -> Palet -> GraphicDetail
+        // public static Dictionary<uint,Dictionary<int,GraphicDetail>> _cache = new Dictionary<uint, Dictionary<int, GraphicDetail>>();
         //
-        // //缓存Index映射 Version -> Index -> PaletIndex -> GraphicData
-        // private static Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>> _indexCache =
-        //     new Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>>();
-        //
-        // //缓存MapSerial映射 Version -> MapSerial -> PaletIndex -> GraphicData
-        // private static Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>> _serialCache =
-        //     new Dictionary<int, Dictionary<uint, Dictionary<int, GraphicData>>>();
-        
-        private static Dictionary<int,string> _graphicVersionPrefix = new Dictionary<int, string>()
-        {
-            //龙之沙漏 之前版本前图档数据
-            {0,@"Graphic_\d+"},
-            //龙之沙漏 版本图档数据
-            {1,@"GraphicEx_\d+"}
-        };
+        // // 图档索引缓存 Index -> Palet -> GraphicDetail
+        // public static Dictionary<uint,Dictionary<int,GraphicDetail>> _indexCache = new Dictionary<uint, Dictionary<int, GraphicDetail>>();
         
-        private static List<string> _graphicPaths = new List<string>();
+        public static Dictionary<GraphicInfoData,Dictionary<int,GraphicDetail>> _cache = new Dictionary<GraphicInfoData, Dictionary<int, GraphicDetail>>();
         
-        //地图地面Texture合批
-        //地图图档PaletIndex -> MapS 索引
-        // private static Dictionary<int,int> _mapPaletMap = new Dictionary<int, int>();
-        //地图图档Serial -> Palet ->MapIndex 索引
-        private static Dictionary<int,Dictionary<int,int>> _mapSerialMap = new Dictionary<int,Dictionary<int,int>>();
-        //地图图档MapIndex -> Palet -> Texture 索引
-        private static Dictionary<int,Dictionary<int,Texture2D>> _mapTextureMap = new Dictionary<int,Dictionary<int,Texture2D>>();
-        //地图图档MapIndex -> MapIndexList 索引库存,索引库容量为 2048x2048尺寸Texture可存储64x48地面图档的数量,即 2048/48(42) * 2048/64(32) ~= 1344
-        //解压地面图档时动态分配索引库存 MapIndex -> Count
-        private static List<int> _mapIndexLib = new List<int>();
-        //Graphic字节读取器缓存
-        private static BinaryReader[] _fileReaderCache = new BinaryReader[_graphicVersionPrefix.Count];
-
-        // 初始化
-        public static void Init()
+        // 获取图档
+        public static GraphicDetail GetGraphicDetail(GraphicInfoData graphicInfoData, int palet = 0)
         {
-            //查找目录文件
-            DirectoryInfo directoryInfo = new DirectoryInfo(CGTool.BaseFolder);
-            FileInfo[] files = directoryInfo.GetFiles();
-            for (int i = 0; i < _graphicVersionPrefix.Count; i++)
+            GraphicDetail graphicDetail = null;
+            if (_cache.ContainsKey(graphicInfoData))
             {
-                foreach (FileInfo file in files)
+                if (_cache[graphicInfoData].ContainsKey(palet))
                 {
-                    if (Regex.IsMatch(file.Name, _graphicVersionPrefix[i]))
-                    {
-                        _graphicPaths.Add(file.Name);
-                        BinaryReader fileReader;
-                        string fileName = _graphicPaths[i];
-                        FileInfo fileInfo = new FileInfo(CGTool.BaseFolder + "/" + fileName);
-                        if (!fileInfo.Exists) return;
-                        //创建流读取器
-                        FileStream fileStream = fileInfo.OpenRead();
-                        fileReader = new BinaryReader(fileStream);
-                        _fileReaderCache[i] = fileReader;
-                        break;
-                    }    
+                    graphicDetail = _cache[graphicInfoData][palet];
                 }
-                
-            }
-        }
-
-        //根据地址获取GraphicData
-        public static GraphicData GetGraphicData(GraphicInfoData graphicInfoData,int PaletIndex=0,bool asMapGround=false)
-        {
-            GraphicData graphicData = null;
-
-            //缓存数据
-            if (_cache.ContainsKey(graphicInfoData.Version))
-            {
-                if (_cache[graphicInfoData.Version].ContainsKey(graphicInfoData.Addr))
+                else
                 {
-                    if (_cache[graphicInfoData.Version][graphicInfoData.Addr].ContainsKey(PaletIndex))
-                    {
-                        graphicData = _cache[graphicInfoData.Version][graphicInfoData.Addr][PaletIndex];
-                    }
+                    graphicDetail = _loadGraphicDetail(graphicInfoData, palet);
+                    _cache[graphicInfoData].Add(palet, graphicDetail);
                 }
             }
-            //无缓存则加载数据
-            if (graphicData == null) graphicData = _loadGraphicData(graphicInfoData, PaletIndex, asMapGround);
+            else
+            {
+                graphicDetail = _loadGraphicDetail(graphicInfoData, palet);
+                _cache.Add(graphicInfoData, new Dictionary<int, GraphicDetail>());
+                _cache[graphicInfoData].Add(palet, graphicDetail);
+            }
             
-            return graphicData;
+            return graphicDetail;
         }
-
-        //初始化加载GraphicData
-        private static GraphicData _loadGraphicData(GraphicInfoData graphicInfoData, int PaletIndex = 0,
-            bool asMapGround = false)
+        
+        // 解析图档
+        private static GraphicDetail _loadGraphicDetail(GraphicInfoData graphicInfoData,int palet = 0)
         {
-            GraphicData graphicData = new GraphicData();
-
+            GraphicDetail graphicDetail = new GraphicDetail();
+            
             //获取图像数据
-            List<Color32> pixels = UnpackGraphic(graphicInfoData, PaletIndex);
-            graphicData.PrimaryColor = pixels.Last();
+            List<Color32> pixels = UnpackGraphic(graphicInfoData, palet);
+            graphicDetail.PrimaryColor = pixels.Last();
             pixels.RemoveAt(pixels.Count - 1);
 
             //直接通过Texture2D做偏移,并转为Sprite的偏移量
@@ -155,9 +97,10 @@ namespace CGTool
             Texture2D texture2D;
             Sprite sprite;
 
+            // RGBA4444 减少内存占用
             texture2D = new Texture2D((int) graphicInfoData.Width, (int) graphicInfoData.Height,
                 TextureFormat.RGBA4444, false, false);
-            
+            // 固定点过滤
             texture2D.filterMode = FilterMode.Point;
             texture2D.SetPixels32(pixels.ToArray());
             // texture2D.LoadRawTextureData(rawTextureData);
@@ -165,43 +108,33 @@ namespace CGTool
             
             sprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), offset, 1,1,SpriteMeshType.FullRect);
 
-
             //写入数据
-            graphicData.Version = graphicInfoData.Version;
-            graphicData.Index = graphicInfoData.Index;
-            graphicData.MapSerial = graphicInfoData.Serial;
-            graphicData.Width = graphicInfoData.Width;
-            graphicData.Height = graphicInfoData.Height;
-            graphicData.OffsetX = graphicInfoData.OffsetX;
-            graphicData.OffsetY = graphicInfoData.OffsetY;
-            graphicData.PaletIndex = PaletIndex;
-            graphicData.Sprite = sprite;
-
-            //缓存
-            if (!_cache.ContainsKey(graphicInfoData.Version))
-                _cache.Add(graphicInfoData.Version, new Dictionary<uint, Dictionary<int, GraphicData>>());
-            if(!_cache[graphicInfoData.Version].ContainsKey(graphicInfoData.Addr)) _cache[graphicInfoData.Version].Add(graphicInfoData.Addr,new Dictionary<int, GraphicData>());
-            if (!_cache[graphicInfoData.Version][graphicInfoData.Addr].ContainsKey(PaletIndex))
-                _cache[graphicInfoData.Version][graphicInfoData.Addr].Add(PaletIndex, graphicData);
-            
-            return graphicData;
+            graphicDetail.Index = graphicInfoData.Index;
+            graphicDetail.Serial = graphicInfoData.Serial;
+            graphicDetail.Width = graphicInfoData.Width;
+            graphicDetail.Height = graphicInfoData.Height;
+            graphicDetail.OffsetX = graphicInfoData.OffsetX;
+            graphicDetail.OffsetY = graphicInfoData.OffsetY;
+            graphicDetail.Palet = palet;
+            graphicDetail.Sprite = sprite;
+            return graphicDetail;
         }
-    
-        //地图sprite缓存  <地图索引,<调色板索引,Sprite>>
-        // private static Dictionary<int,Dictionary<int,Dictionary<int,GraphicData>>> _mapSpriteMap = new Dictionary<int, Dictionary<int, Dictionary<int, GraphicData>>>();
 
+        #region 地图合批
+        private class BatchData
+        {
+            public int BatchOffsetX;
+            public int BatchOffsetY;
+            public GraphicDetail GraphicDetail;
+        }
         //预备地图缓存
-        public static Dictionary<int, GraphicData> PrepareMapGroundTexture(int MapID, int PaletIndex,
-            List<GraphicInfoData> groundInfos)
+        public static Dictionary<uint, GraphicDetail> BakeAsGround(List<GraphicInfoData> groundInfos,int palet=0)
         {
-            //如果已经缓存过,则直接返回
-            // if(_mapSpriteMap.ContainsKey(MapID) && _mapSpriteMap[MapID].ContainsKey(PaletIndex)) return _mapSpriteMap[MapID][PaletIndex];
-            //如果没有缓存过,则创建缓存
-            // if(!_mapSpriteMap.ContainsKey(MapID)) _mapSpriteMap.Add(MapID,new Dictionary<int, Dictionary<int, GraphicData>>());
-            Dictionary<int, GraphicData> graphicDataDic = new Dictionary<int, GraphicData>();
+            
+            Dictionary<uint, GraphicDetail> graphicDataDic = new Dictionary<uint, GraphicDetail>();
             // _mapSpriteMap[MapID].Add(PaletIndex, graphicDataDic);
             
-            List<GraphicData> graphicDatas = new List<GraphicData>();
+            List<BatchData> batchDatas = new List<BatchData>();
             Texture2D texture2D = null;
             
             for (var i = 0; i < groundInfos.Count; i++)
@@ -210,10 +143,10 @@ namespace CGTool
                 if (i % 1344 == 0)
                 {
                     //合并
-                    if (i != 0) Combine(texture2D, graphicDatas);
+                    if (i != 0) Combine(texture2D, batchDatas);
                     
                     //清空
-                    graphicDatas.Clear();
+                    batchDatas.Clear();
                     int height = 2048;
 
                     if (i + 1344 > groundInfos.Count-1)
@@ -228,43 +161,40 @@ namespace CGTool
                 }
                 
                 GraphicInfoData graphicInfoData = groundInfos[i];
-                GraphicData graphicData = new GraphicData();
-                
-                //获取图像数据
-                List<Color32> pixels = UnpackGraphic(graphicInfoData, PaletIndex);
-                graphicData.PrimaryColor = pixels.Last();
-                pixels.RemoveAt(pixels.Count - 1);
+                GraphicDetail graphicData = GetGraphicDetail(graphicInfoData, palet);
                 
                 int x = i % 32 * 64;
                 int y = i / 32 * 48;
 
-                texture2D.SetPixels32(x, y, (int) graphicInfoData.Width, (int) graphicInfoData.Height,
-                    pixels.ToArray());
-
-                //写入数据
-                graphicData.Version = graphicInfoData.Version;
-                graphicData.Index = graphicInfoData.Index;
-                graphicData.MapSerial = graphicInfoData.Serial;
-                graphicData.Width = graphicInfoData.Width;
-                graphicData.Height = graphicInfoData.Height;
-                graphicData.OffsetX = graphicInfoData.OffsetX;
-                graphicData.OffsetY = graphicInfoData.OffsetY;
-                graphicData.PaletIndex = PaletIndex;
-                graphicData.BatchOffsetX = x;
-                graphicData.BatchOffsetY = y;
-
-                graphicDatas.Add(graphicData);
+                if(graphicData!=null && graphicData.Sprite!=null)
+                {
+                    Color32[] pixels = graphicData.Sprite.texture.GetPixels32();
+                    texture2D.SetPixels32(x, y, (int) graphicInfoData.Width, (int) graphicInfoData.Height,
+                        pixels.ToArray());    
+                }
+                BatchData batchData = new BatchData();
+                
+
+                batchData.BatchOffsetX = x;
+                batchData.BatchOffsetY = y;
+                batchData.GraphicDetail = graphicData;
+
+                batchDatas.Add(batchData);
             }
             
             //最后一次合并
-            if (graphicDatas.Count > 0) Combine(texture2D, graphicDatas);
+            if (batchDatas.Count > 0)
+            {
+                Combine(texture2D, batchDatas);
+                batchDatas.Clear();
+            }
 
-            void Combine(Texture2D texture2D,List<GraphicData> graphicDatas)
+            void Combine(Texture2D texture2D,List<BatchData> batchDatas)
             {
                 texture2D.Apply();
-                for (var i = 0; i < graphicDatas.Count; i++)
+                for (var i = 0; i < batchDatas.Count; i++)
                 {
-                    GraphicData graphicDataPiece = graphicDatas[i];
+                    GraphicDetail graphicDataPiece = batchDatas[i].GraphicDetail;
                     //直接通过Texture2D做偏移,并转为Sprite的偏移量
                     Vector2 offset = new Vector2(0f, 1f);
                     offset.x += -(graphicDataPiece.OffsetX * 1f) / graphicDataPiece.Width;
@@ -272,11 +202,25 @@ namespace CGTool
                         
                     int X = i % 32 * 64;
                     int Y = i / 32 * 48;
-                        
-                    Sprite sprite = Sprite.Create(texture2D, new Rect(X, Y, (int)graphicDataPiece.Width, (int)graphicDataPiece.Height),offset, 1, 1, SpriteMeshType.FullRect);
-                    graphicDataPiece.Sprite = sprite;
 
-                    graphicDataDic.Add((int) graphicDataPiece.MapSerial, graphicDataPiece);
+                    Sprite sprite = Sprite.Create(texture2D,
+                        new Rect(X, Y, (int)graphicDataPiece.Width, (int)graphicDataPiece.Height), offset, 1, 1,
+                        SpriteMeshType.FullRect);
+                    
+                    GraphicDetail graphicData = new GraphicDetail()
+                    {
+                        Index = graphicDataPiece.Index,
+                        Serial = graphicDataPiece.Serial,
+                        Width = graphicDataPiece.Width,
+                        Height = graphicDataPiece.Height,
+                        OffsetX = graphicDataPiece.OffsetX,
+                        OffsetY = graphicDataPiece.OffsetY,
+                        Palet = graphicDataPiece.Palet,
+                        Sprite = sprite,
+                        PrimaryColor = graphicDataPiece.PrimaryColor
+                    };
+
+                    graphicDataDic.Add(graphicData.Serial, graphicData);
                 }
             }
 
@@ -284,28 +228,21 @@ namespace CGTool
         }
         
         //预备地图物件缓存
-        partial class TextureData
+        private class TextureData
         {
             public int MaxHeight;
             public int MaxWidth;
-            public List<GraphicData> GraphicDatas = new List<GraphicData>();
+            public List<BatchData> BatchDatas = new List<BatchData>();
             public List<GraphicInfoData> GraphicInfoDatas = new List<GraphicInfoData>();
         }
-        public static Dictionary<int, GraphicData> PrepareMapObjectTexture(int MapID, int PaletIndex,
-            List<GraphicInfoData> objectInfos)
+        public static Dictionary<uint, GraphicDetail> BakeAsObject(List<GraphicInfoData> objectInfos,int palet = 0)
         {
-            //如果已经缓存过,则直接返回
-            // if(_mapSpriteMap.ContainsKey(MapID) && _mapSpriteMap[MapID].ContainsKey(PaletIndex)) return _mapSpriteMap[MapID][PaletIndex];
-            //如果没有缓存过,则创建缓存
-            // if(!_mapSpriteMap.ContainsKey(MapID)) _mapSpriteMap.Add(MapID,new Dictionary<int, Dictionary<int, GraphicData>>());
-            
             // 单个Texture最大尺寸
             int maxWidth = 4096;
             int maxHeight = 4096;
             
             List<TextureData> textureDatas = new List<TextureData>();
-            Dictionary<int, GraphicData> graphicDataDic = new Dictionary<int, GraphicData>();
-            // _mapSpriteMap[MapID].Add(PaletIndex, graphicDataDic);
+            Dictionary<uint, GraphicDetail> graphicDataDic = new Dictionary<uint, GraphicDetail>();
 
             // 根据objectInfos的内,GraphicInfoData的Width,Height进行排序,优先排序Width,使图档从小到大排列
             objectInfos = objectInfos.OrderBy(obj => obj.Width).ThenBy(obj => obj.Height).ToList();
@@ -335,34 +272,26 @@ namespace CGTool
                     textureDatas.Add(textureData);
                     textureData = new TextureData();
                 }
-
-                GraphicData graphicData = new GraphicData();
-                //写入数据
-                graphicData.Version = graphicInfoData.Version;
-                graphicData.Index = graphicInfoData.Index;
-                graphicData.MapSerial = graphicInfoData.Serial;
-                graphicData.Width = graphicInfoData.Width;
-                graphicData.Height = graphicInfoData.Height;
-                graphicData.OffsetX = graphicInfoData.OffsetX;
-                graphicData.OffsetY = graphicInfoData.OffsetY;
-                graphicData.PaletIndex = PaletIndex;
-                graphicData.BatchOffsetX = offsetX;
-                graphicData.BatchOffsetY = offsetY;
+                
+                BatchData batchData = new BatchData();
+                batchData.BatchOffsetX = offsetX;
+                batchData.BatchOffsetY = offsetY;
+                batchData.GraphicDetail = GetGraphicDetail(graphicInfoData, palet);
 
                 // graphicDatas.Add(graphicData);
                 
-                textureData.GraphicDatas.Add(graphicData);
+                textureData.BatchDatas.Add(batchData);
                 textureData.GraphicInfoDatas.Add(graphicInfoData);
                 
                 
-                maxRowHeight = Mathf.Max(maxRowHeight, (int) graphicData.Height);
+                maxRowHeight = Mathf.Max(maxRowHeight, (int) graphicInfoData.Height);
                 textureData.MaxHeight = Mathf.Max(textureData.MaxHeight, offsetY + maxRowHeight);
-                textureData.MaxWidth = Mathf.Max(textureData.MaxWidth, offsetX + (int) graphicData.Width);
-                offsetX += (int) graphicData.Width + 5;
+                textureData.MaxWidth = Mathf.Max(textureData.MaxWidth, offsetX + (int) graphicInfoData.Width);
+                offsetX += (int) graphicInfoData.Width + 5;
             }
             
             //最后一次合并
-            if (textureData.GraphicDatas.Count > 0) textureDatas.Add(textureData);
+            if (textureData.BatchDatas.Count > 0) textureDatas.Add(textureData);
             
             //合并Texture2D
             for (var i = 0; i < textureDatas.Count; i++)
@@ -373,49 +302,63 @@ namespace CGTool
                 Texture2D texture2DPiece = new Texture2D(textureDataPiece.MaxWidth, textureDataPiece.MaxHeight, TextureFormat.RGBA4444, false, false);
                 texture2DPiece.filterMode = FilterMode.Point;
                 texture2DPiece.SetPixels32(colors);
-                for (var n = 0; n < textureDataPiece.GraphicDatas.Count; n++)
+                for (var n = 0; n < textureDataPiece.BatchDatas.Count; n++)
                 {
-                    GraphicData graphicData = textureDataPiece.GraphicDatas[n];
+                    BatchData batchData = textureDataPiece.BatchDatas[n];
                     GraphicInfoData graphicInfoData = textureDataPiece.GraphicInfoDatas[n];
-                    
-                    //设置图像数据
-                    List<Color32> pixels = UnpackGraphic(graphicInfoData, PaletIndex);
-                    graphicData.PrimaryColor = pixels.Last();
-                    pixels.RemoveAt(pixels.Count - 1);
-                
-                    texture2DPiece.SetPixels32(graphicData.BatchOffsetX, graphicData.BatchOffsetY, (int) graphicInfoData.Width, (int) graphicInfoData.Height,
-                        pixels.ToArray());
+
+                    if (batchData.GraphicDetail!=null)
+                    {
+                        Color32[] pixels = batchData.GraphicDetail.Sprite.texture.GetPixels32();
+                        texture2DPiece.SetPixels32(batchData.BatchOffsetX, batchData.BatchOffsetY, (int) graphicInfoData.Width, (int) graphicInfoData.Height,
+                            pixels.ToArray());
+                    }
                 }
                 texture2DPiece.Apply();
-                Combine(texture2DPiece, textureDataPiece.GraphicDatas);
+                Combine(texture2DPiece, textureDataPiece.BatchDatas);
             }
 
-            void Combine(Texture2D texture2D,List<GraphicData> graphicDatas)
+            void Combine(Texture2D texture2D,List<BatchData> batchDatas)
             {
-                for (var i = 0; i < graphicDatas.Count; i++)
+                for (var i = 0; i < batchDatas.Count; i++)
                 {
-                    GraphicData graphicDataPiece = graphicDatas[i];
+                    BatchData batchData = batchDatas[i];
                     //直接通过Texture2D做偏移,并转为Sprite的偏移量
                     Vector2 offset = new Vector2(0f, 1f);
-                    offset.x += -(graphicDataPiece.OffsetX * 1f) / graphicDataPiece.Width;
-                    offset.y -= (-graphicDataPiece.OffsetY * 1f) / graphicDataPiece.Height;
+                    offset.x += -(batchData.GraphicDetail.OffsetX * 1f) / batchData.GraphicDetail.Width;
+                    offset.y -= (-batchData.GraphicDetail.OffsetY * 1f) / batchData.GraphicDetail.Height;
 
-                    Sprite sprite = Sprite.Create(texture2D, new Rect(graphicDataPiece.BatchOffsetX, graphicDataPiece.BatchOffsetY, (int)graphicDataPiece.Width, (int)graphicDataPiece.Height),offset, 1, 1, SpriteMeshType.FullRect);
-                    graphicDataPiece.Sprite = sprite;
-                    graphicDataDic.Add((int) graphicDataPiece.MapSerial, graphicDataPiece);
+                    Sprite sprite = Sprite.Create(texture2D, new Rect(batchData.BatchOffsetX, batchData.BatchOffsetY, (int)batchData.GraphicDetail.Width, (int)batchData.GraphicDetail.Height),offset, 1, 1, SpriteMeshType.FullRect);
+                    GraphicDetail graphicDetail = new GraphicDetail()
+                    {
+                        Index = batchData.GraphicDetail.Index,
+                        Serial = batchData.GraphicDetail.Serial,
+                        Width = batchData.GraphicDetail.Width,
+                        Height = batchData.GraphicDetail.Height,
+                        OffsetX = batchData.GraphicDetail.OffsetX,
+                        OffsetY = batchData.GraphicDetail.OffsetY,
+                        Palet = batchData.GraphicDetail.Palet,
+                        Sprite = sprite,
+                        PrimaryColor = batchData.GraphicDetail.PrimaryColor
+                    };
+                    
+                    // graphicDataPiece.Sprite = sprite;
+                    graphicDataDic.Add(graphicDetail.Serial, graphicDetail);
                 }
             }
 
             return graphicDataDic;
         }
+        #endregion
         
-        private static List<Color32> UnpackGraphic(GraphicInfoData graphicInfoData,int PaletIndex){
+        //解压图像数据
+        private static List<Color32> UnpackGraphic(GraphicInfoData graphicInfoData,int PaletIndex=0){
             List<Color32> pixels = new List<Color32>();
             //获取调色板
             List<Color32> palet = Palet.GetPalet(PaletIndex);
 
             //调整流指针
-            BinaryReader fileReader = _fileReaderCache[graphicInfoData.Version];
+            BinaryReader fileReader = graphicInfoData.GraphicReader;
             fileReader.BaseStream.Position = graphicInfoData.Addr;
 
             //读入目标字节集
@@ -513,14 +456,11 @@ namespace CGTool
             
             //主色调加入最后
             pixels.Add(new Color32((byte) r, (byte) g, (byte) b, 255));
-
-                
             return pixels;
         }
     }
     
-    
-    //解压缩交给IJob处理
+        //解压缩交给IJob处理
     [BurstCompile]
     public struct DecompressJob : IJob
     {
@@ -658,4 +598,4 @@ namespace CGTool
             }
         }
     }
-}
+}

+ 132 - 0
CrossgateToolkit/GraphicInfo.cs

@@ -0,0 +1,132 @@
+/**
+ * 魔力宝贝图档解析脚本 - CGTool
+ * 
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 1.0 (2023-04-15)
+ * @License GPL-3.0
+ *
+ * GraphicInfo.cs 图档索引解析类
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using UnityEngine;
+
+namespace CrossgateToolkit
+{
+    //GraphicInfo数据块
+    public class GraphicInfoData
+    {
+        // GraphicInfo基础数据
+        //4 bytes   索引
+        public uint Index;
+        //4 bytes   Graphic 地址
+        public uint Addr;
+        //4 bytes   Graphic 数据长度
+        public uint Length;
+        //4 bytes   Graphic 偏移 - X
+        public int OffsetX;
+        //4 bytes   Graphic 偏移 - Y
+        public int OffsetY;
+        //4 bytes   Graphic 宽
+        public uint Width;
+        //4 bytes   Graphic 高
+        public uint Height;
+        //4 bytes   Graphic East占地
+        public int East;
+        //4 bytes   Graphic South 占地
+        public int South;
+        //bool      穿越标识
+        public bool Blocked;
+        //1 byte    作为地面无层级遮挡[Test]
+        public bool AsGround;
+        //4 bytes   未知标识
+        public byte[] Unknow;
+        //4 bytes   编号
+        public uint Serial;
+        
+        // GraphicInfo附加数据
+        // GraphicInfo对应Graphic文件流读取器
+        public BinaryReader GraphicReader;
+        //已解压的调色板索引
+        public int[] UnpackedPaletIndex;
+    }
+
+    public class GraphicInfo:MonoBehaviour
+    {
+        //索引字典    Serial -> GraphicInfoData
+        private static readonly Dictionary<uint,GraphicInfoData> _cache = new Dictionary<uint, GraphicInfoData>();
+        // private static readonly Dictionary<uint,GraphicInfoData> _indexCache = new Dictionary<uint, GraphicInfoData>();
+        
+        private static readonly Dictionary<string,Dictionary<uint,GraphicInfoData>> _indexCache = new Dictionary<string, Dictionary<uint, GraphicInfoData>>();
+        public static void Init(string Version,FileInfo graphicInfoFile,FileInfo graphicFile)
+        {
+            if(!_indexCache.ContainsKey(Version)) _indexCache.Add(Version,new Dictionary<uint, GraphicInfoData>());
+            //创建流读取器
+            FileStream fileStream = graphicInfoFile.OpenRead();
+            BinaryReader fileReader = new BinaryReader(fileStream);
+            
+            FileStream graphicFileStream = graphicFile.OpenRead();
+            BinaryReader graphicFileReader = new BinaryReader(graphicFileStream);
+            
+            //解析Info数据表
+            // List<GraphicInfoData> infoDatas = new List<GraphicInfoData>();
+            long DataLength = fileStream.Length/40;
+            for (int i = 0; i < DataLength; i++)
+            {
+                GraphicInfoData graphicInfoData = new GraphicInfoData();
+                graphicInfoData.Index = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.Addr = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.Length = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.OffsetX = BitConverter.ToInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.OffsetY = BitConverter.ToInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.Width = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.Height = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.East = fileReader.ReadByte();
+                graphicInfoData.South = fileReader.ReadByte();
+                graphicInfoData.Blocked =  fileReader.ReadByte() == 0;
+                graphicInfoData.AsGround = fileReader.ReadByte() == 1;
+                graphicInfoData.Unknow = fileReader.ReadBytes(4);
+                graphicInfoData.Serial = BitConverter.ToUInt32(fileReader.ReadBytes(4),0);
+                graphicInfoData.GraphicReader = graphicFileReader;
+
+                //建立Index映射表
+                _indexCache[Version][graphicInfoData.Index] = graphicInfoData;
+                
+                //建立Serial映射表
+                if (graphicInfoData.Serial != 0) _cache[graphicInfoData.Serial] = graphicInfoData;
+
+
+
+                // _logger.Write("Index: " + graphicInfoData.Index + " Addr: " + graphicInfoData.Addr + 
+                //               " Width: " + graphicInfoData.Width + 
+                //               " Height: " + graphicInfoData.Height +
+                //               " OffsetX: " + graphicInfoData.OffsetX +
+                //               " OffsetY: " + graphicInfoData.OffsetY +
+                //               " East: " + graphicInfoData.East +
+                //               " South: " + graphicInfoData.South +
+                //               " Blocked: " + graphicInfoData.Blocked +
+                //               " Unknow: " + BitConverter.ToString(graphicInfoData.Unknow).Replace("-", ",") +
+                //               " MapSerial: " + graphicInfoData.MapSerial);
+            }
+            Debug.Log("[CGTool] 加载GraphicInfo - 文件: " + graphicInfoFile.Name + " 贴图总量: " + DataLength);
+        }
+        
+        //获取GraphicInfoData
+        public static GraphicInfoData GetGraphicInfoData(uint Serial)
+        {
+            _cache.TryGetValue(Serial, out var graphicInfoData);
+            return graphicInfoData;
+        }
+        
+        public static GraphicInfoData GetGraphicInfoDataByIndex(string Version,uint Index)
+        {
+            _indexCache.TryGetValue(Version, out var indexDict);
+            if(indexDict == null) throw new Exception("找不到对应版本的GraphicInfo数据");
+            indexDict.TryGetValue(Index, out var graphicInfoData);
+            return graphicInfoData;
+        }
+    }
+}

CGTool/LICENSE → CrossgateToolkit/LICENSE


+ 12 - 10
CGTool/Map.cs

@@ -15,7 +15,7 @@ using System.Linq;
 using System.Text.RegularExpressions;
 using UnityEngine;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
     //地图文件信息
     public class MapFileInfo
@@ -71,7 +71,7 @@ namespace CGTool
         //初始化地图文件列表
         public static void Init()
         {
-            DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.MapFolder);
+            DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.PATH.MAP);
             FileInfo[] mapFiles = mapDirectory.GetFiles();
             string match = @"^(\d+)_?(.+)?$";
             foreach (var fileInfo in mapFiles)
@@ -86,6 +86,7 @@ namespace CGTool
                 _file.FileName = filename;
                 _mapIndexFiles.Add(_file.Serial, _file);
             }
+            Debug.Log("[CGTool] 地图列表初始化完成,共" + _mapIndexFiles.Count + "个地图文件");
         }
 
         //获取全部地图列表
@@ -117,7 +118,7 @@ namespace CGTool
             if (!_mapIndexFiles.ContainsKey(serial)) return null;
             
             // print("找到地图文件: " + mapFileInfo.Name);
-            FileStream mapFileStream = new FileStream(CGTool.MapFolder + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
+            FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
             BinaryReader mapFileReader = new BinaryReader(mapFileStream);
             
             MapInfo mapInfo = new MapInfo();
@@ -129,17 +130,16 @@ namespace CGTool
             byte[] mapHeader = mapFileReader.ReadBytes( 6);
             if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
                 isClientMapFile = false;
-                Debug.Log("地图文件头: 服务端地图");
+                Debug.Log("[CGTool] 地图文件头: 服务端地图");
             }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
                 isClientMapFile = true;
-                Debug.Log("地图文件头: 客户端地图");
+                Debug.Log("[CGTool] 地图文件头: 客户端地图");
             }
             else
             {
-                Debug.Log("地图文件头错误: " + _mapIndexFiles[serial].FileName);
+                Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName);
                 return null;
             }
-
             byte[] bytes;
             if (isClientMapFile)
             {
@@ -186,7 +186,7 @@ namespace CGTool
                 mapInfo.Height = BitConverter.ToUInt16(bytes,0);
             }
             
-            Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
+            
 
             byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
             byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
@@ -220,7 +220,7 @@ namespace CGTool
                     mapGraphicSerial += 200000;
                     Version = 1;
                 }
-                GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataBySerial(Version, mapGraphicSerial);
+                GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial);
                 if (graphicInfoData != null)
                 {
                     mapTile = new MapBlockData();
@@ -239,7 +239,7 @@ namespace CGTool
                     mapCoverGraphicSerial += 200000;
                     Version = 1;
                 }
-                graphicInfoData = GraphicInfo.GetGraphicInfoDataBySerial(Version, mapCoverGraphicSerial);
+                graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial);
                 if (graphicInfoData != null)
                 {
                     mapCoverTile = new MapBlockData();
@@ -356,6 +356,8 @@ namespace CGTool
             mapInfo.FixPlayerZs = fixPlayerZs;
             _cache[serial] = mapInfo;
             
+            Debug.Log("[CGTool] 读取地图: " + mapInfo.Name);
+            Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
             // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
             return mapInfo;
         }

+ 1 - 1
CGTool/MapExtra.cs

@@ -1,6 +1,6 @@
 using System.Collections.Generic;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
     public class MapExtra
     {

+ 18 - 27
CGTool/Palet.cs

@@ -13,7 +13,7 @@ using System.Collections.Generic;
 using System.IO;
 using UnityEngine;
 
-namespace CGTool
+namespace CrossgateToolkit
 {
     public class Palet
     {
@@ -24,43 +24,34 @@ namespace CGTool
         public static List<Color32> GetPalet(int index)
         {
             //返回缓存数据
-            if (_cache.ContainsKey(index)) return _cache[index];
-            //获取新调色板
-            List<Color32> paletData = _loadPalet(index);
-            //加入缓存
-            if (paletData != null) _cache.Add(index, paletData);
-            if (paletData == null) paletData = GetPalet(0);
+            _cache.TryGetValue(index, out List<Color32> paletData);
             return paletData;
         }
 
-        //将数字生成指定长度字符串,不足位数补进行填充
-        private static string NumToString(uint num, int len, bool fillZero)
+        //调色板初始化
+        public static void Init()
         {
-            string numStr = num.ToString();
+            DirectoryInfo folderInfo = new DirectoryInfo(CGTool.PATH.PAL);
+
+            if (!folderInfo.Exists) throw new Exception("调色板目录不存在,请检查CGTool中是否配置相应PATH路径");
             
-            if (numStr.Length < len && fillZero)
+            FileInfo[] files = folderInfo.GetFiles();
+            foreach (FileInfo file in files)
             {
-                int count = len - numStr.Length;
-                for (int i = 0; i < count; i++)
-                {
-                    numStr = "0" + numStr;
-                }
+                if (!file.Name.StartsWith("palet_") || !file.Name.EndsWith(".cgp")) continue;
+                string indexStr = file.Name.Substring(6, 2);
+                int index = Convert.ToInt32(indexStr);
+                List<Color32> paletData = _loadPalet(file);
+                if (paletData != null) _cache.Add(index, paletData);
             }
-            return numStr;
+
+            Debug.Log("[CGTool] 调色板初始化完成,共加载" + _cache.Count + "个调色板");
         }
         
         //加载缓存数据
-        private static List<Color32> _loadPalet(int index)
+        private static List<Color32> _loadPalet(FileInfo paletFile)
         {
-            //查找调色板文件
-            DirectoryInfo paletFolderInfo = new DirectoryInfo(CGTool.PaletFolder);
-            string filledIndex = NumToString((uint)index, 2, true);
-            FileInfo[] files = paletFolderInfo.GetFiles("palet_" + filledIndex + ".cgp");
-            if (files.Length == 0) return null;
-            // CGTool.Logger.Write("加载调色板 - 编号: " + filledIndex);
-            //创建流读取器
-            FileInfo paletFileInfo = files[0];
-            FileStream paletFileStream = paletFileInfo.OpenRead();
+            FileStream paletFileStream = paletFile.OpenRead();
             BinaryReader paletReader = new BinaryReader(paletFileStream);
             
             //调色板解析表

+ 58 - 41
README.md

@@ -26,10 +26,10 @@
 > 目前版本支持以下功能:
 > 
 > * `GraphicInfo` [图档索引解析](#获取图档索引数据)
-> * `Graphic` [图档数据解析](#获取指定索引图档数据)
+> * `GraphicData` [图档数据解析](#获取指定索引图档数据)
 > * `Palet` 调色板数据解析
 > * `Map` [服务端/客户端 图数据解析](#获取地图数据)
-> * `AudioTool` [音频索引及加载](#获取音频)
+> * `Audio` [音频索引及加载](#获取音频)
 > * `AnimeInfo` 动画索引解析
 > * `Anime` 动画数据解析
 > * `AnimePlayer` [动画播放器挂载组件](#动画播放) 
@@ -42,27 +42,41 @@
 
 ## 3、使用说明
 
-克隆当前仓库或下载zip包解压,将CGTool文件夹放置于Unity项目文件夹内引用
+克隆当前仓库或下载zip包解压,将 CrossgateToolkit 文件夹放置于Unity项目文件夹内引用
 
+最新 V2.0 版本已移除对魔力宝贝原版本的强绑定,初始化程序将根据目标路径进行自动分析
 
-下文示例中,所涉及到的版本号均对应:
+规划图档目录结构时,图档根目录下建议以数字版本号方式命名不同版本图档子目录
 
-```0``` 龙之沙漏前版本
+CGTool在初始化时对所配置图档根目录进行扫描,并按照``根目录优先``、``子目录按字符排序``方式依次加载并初始化图档数据
 
-```1``` 龙之沙漏
-
-所涉及的所有index、serial均指代图档或动画的具体编号而非索引档中序号
+所涉及的所有Index则为图档序号、Serial为图档或动画的具体编号而非索引档中序号,实际使用时请注意区分
 
 其他相关部分会逐渐更新完善
 
 ### 框架初始化
 在入口或初始化脚本头部引入CGTool初始化文件
 ```csharp
-using CGTool;
+using CrossgateToolkit;
 ```
 并在相关初始化位置对CGTool进行初始化
 ```csharp
-CGTool.CGTool.Init();
+// 配置Crossgate相关资源路径,如跳过则默认为 Environment.CurrentDirectory 下相关 目录
+CGTool.PATH = new CGTool.CGPath()
+{
+    // 调色板目录,不可省略
+    PAL = Application.persistentDataPath + "/pal",
+    // BIN图档目录,包含图档索引、图档文件、动画索引、动画文件等根目录
+    // 初始化时会自动便利查询分析所有文件数据,不可省略
+    BIN = Application.persistentDataPath + "/bin",
+    // 地图文件目录,省略则不对地图数据初始化
+    MAP = Application.persistentDataPath + "/map",
+    // 音频文件目录,省略则不对音频初始化
+    BGM = Application.persistentDataPath + "/bgm",
+    AUDIO = Application.persistentDataPath + "/se"
+};
+// 初始化
+CGTool.Init();
 ```
 CGTool初始化时,会自动对相关索引Info文件进行解析,请根据实际所采用版本情况,对脚本代码中解析相关的文件名称进行修改调整
 
@@ -70,25 +84,20 @@ CGTool初始化时,会自动对相关索引Info文件进行解析,请根据
 ### 获取图档索引数据
 (图档基本索引数据属性信息)
 ```csharp
-// 通过编号获取图档,无需版本号(推荐方法)
-GraphicInfo.GetGraphicInfoDataBySerial(uint Serial);
-
-// 通过编号获取图档,带版本号
-GraphicInfo.GetGraphicInfoDataBySerial(int version, uint Serial);
+// 正常通过编号获取图档信息,无需版本号(常规图档)
+GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(uint Serial);
 
-// 通过地面编号获取GraphicInfo数据
-GraphicInfo.GetGraphicInfoDataByMapSerial(int Version, uint MapSerial);
-
-// 通过索引获取GraphicInfo数据
-GraphicInfo.GetGraphicInfoDataByIndex(int Version, uint Index);
+// 通过索引获取图档信息,带版本号(特殊无编号图档获取,如动画获取每帧图档时)
+GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(string version, uint Serial);
 ```
 
-### 获取指定索引图档数据
+### 获取图档实体数据
 (图档实际数据,包含图像Sprite资源)
 ```csharp
-// 通过图档索引编号获取GraphicData数据
-Graphic.GetGraphicData(GraphicInfoData graphicInfoData,int PaletIndex=0);
-
+// 直接通过编号获取
+GraphicDetail graphicDetail = Graphic.GetGraphicDetail(uint serial,int palet = 0);
+// 或 通过GraphicInfoData获取
+GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(GraphicInfoData graphicInfoData, int palet = 0);
 /**
  * 使用说明:
  * 所有通过Graphic获取的图档Sprite均已做偏移处理,可直接使用
@@ -98,9 +107,9 @@ Graphic.GetGraphicData(GraphicInfoData graphicInfoData,int PaletIndex=0);
  * 3.使用图档数据中的Sprite资源进行绘制
  */
 
-GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataBySerial(Serial);
-GraphicData graphicData = Graphic.GetGraphicData(graphicInfoData);
-SpriteRenderer(Image).sprite = graphicData.Sprite;
+GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(Serial);
+GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData ,0);
+SpriteRenderer(Image).sprite = graphicDetail.Sprite;
 ```
 
 ### 获取地图数据
@@ -123,32 +132,31 @@ Map.MapInfo mapInfo = Map.GetMap(uint Serial);
  */
 
 // 地面合批
-Dictionary<int, GraphicData> MapGroundSerialDic =
-    Graphic.PrepareMapGroundTexture(    // <= 合并地面图形
-        int MapID,
-        int PaletIndex,
-        List<GraphicInfoData> graphicInfoDataList
+Dictionary<int, GraphicDetail> MapGroundSerialDic =
+    GraphicData.BakeAsGround(    // <= 合并地面图形
+        List<GraphicInfoData> graphicInfoDataList,
+        int PaletIndex = 0
     );
 
 // 物件合批
-Dictionary<int, GraphicData> MapObjectSerialDic =
-    Graphic.PrepareMapObjectTexture(    // <= 合并物件图形
-        int MapID,
-        int PaletIndex,
-        List<GraphicInfoData> graphicInfoDataList
+Dictionary<int, GraphicDetail> MapObjectSerialDic =
+    Graphic.BakeAsObject(    // <= 合并物件图形
+        List<GraphicInfoData> graphicInfoDataList,
+        int PaletIndex = 0
     );
 ```
 ![地面合并效果](Preview/MapGroundMix.png)
 ![物件合并效果](Preview/MapObjectMix.png)
 ![资源合并后效果](Preview/batches.png)
 
-### 获取音频
+### 播放音频
 ```csharp
-//获取背景音乐
-AudioClip clip = AudioTool.GetAudio(AudioTool.Type.BGM,int serial);
+CGTool.Audio.Play(AudioSource audioSource,Type type, int serial)
 
+//播放背景音乐
+CGTool.Audio.Play(AudioSource audioSource,Audio.Type.BGM,int serial);
 //获取音效音频
-AudioClip clip = AudioTool.GetAudio(AudioTool.Type.EFFECT,int serial);
+CGTool.Audio.Play(AudioSource audioSource,Audio.Type.EFFECT,int serial);
 ```
 
 ### 动画播放
@@ -265,6 +273,15 @@ player.Stop();
 
 
 ## 4、更新日志
+### v 2.0
+> `ADD` 修改初始化方法以支持更复杂的图档文件建构
+>
+> `UPD` 图档解析支持多层目录结构并能自动识别加载,方便对图档进行扩充升级,建议根据版本号对图档子目录进行命名
+>
+> `UPD` 图档获取和加载方法优化,减少无用参数
+>
+> `UPD` 根据新的加载方式调整相关工具库代码以适应新的加载方式
+
 ### v 1.7
 > `ADD` 加入地图物件合批处理