Map.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-04-15)
  6. * @License GPL-3.0
  7. *
  8. * Map.cs 服务端地图解析类
  9. */
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Linq;
  14. using System.Text.RegularExpressions;
  15. using UnityEngine;
  16. using Object = System.Object;
  17. namespace CrossgateToolkit
  18. {
  19. //地图文件信息
  20. public class MapFileInfo
  21. {
  22. public uint Serial;
  23. public string Name;
  24. public string FileName;
  25. }
  26. //地图块数据
  27. public class MapBlockData
  28. {
  29. public GraphicInfoData GraphicInfo;
  30. public int MapIndex;
  31. public uint MapSerial;
  32. public float ObjectZIndex = 0;
  33. public int x;
  34. public int y;
  35. }
  36. //地图信息
  37. public class MapInfo
  38. {
  39. //地图编号
  40. public uint Serial;
  41. //地图宽度
  42. public int Width;
  43. //地图高度
  44. public int Height;
  45. // 地图名称
  46. public string Name;
  47. // 调色板号 - 默认 -1 表示自动
  48. public int Palet = -1;
  49. //未知数据
  50. public byte[] Unknow;
  51. //地面数据
  52. public List<MapBlockData> GroundDatas = new List<MapBlockData>();
  53. //地表数据
  54. public List<MapBlockData> ObjectDatas = new List<MapBlockData>();
  55. public bool[] BlockedIndexs;
  56. public float[] FixPlayerZs;
  57. //地图坐标二维数组,用以记录可行走区域并作为自动寻路的数据参考
  58. public bool[,] MapNodes;
  59. }
  60. public class Map
  61. {
  62. //缓存数据
  63. private static Dictionary<uint, MapInfo> _cache = new Dictionary<uint, MapInfo>();
  64. private static Dictionary<uint, MapFileInfo> _mapIndexFiles = new Dictionary<uint, MapFileInfo>();
  65. private static Dictionary<uint,Dictionary<uint,GraphicDetail>> _mapGroundGraphicBatch = new Dictionary<uint, Dictionary<uint, GraphicDetail>>();
  66. private static Dictionary<uint,Dictionary<uint,GraphicDetail>> _mapObjectGraphicBatch = new Dictionary<uint, Dictionary<uint, GraphicDetail>>();
  67. //初始化地图文件列表
  68. public static void Init()
  69. {
  70. DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.PATH.MAP);
  71. FileInfo[] mapFiles = mapDirectory.GetFiles();
  72. string match = @"^(\d+)_?(.+)?$";
  73. foreach (var fileInfo in mapFiles)
  74. {
  75. string filename = fileInfo.Name;
  76. Match matchRet = Regex.Match(filename, match);
  77. if(!matchRet.Success) continue;
  78. MapFileInfo _file = new MapFileInfo();
  79. _file.Serial = uint.Parse(matchRet.Groups[1].Value);
  80. if(matchRet.Groups.Count > 1) _file.Name = matchRet.Groups[1].Value;
  81. _file.FileName = filename;
  82. _mapIndexFiles.Add(_file.Serial, _file);
  83. }
  84. Debug.Log("[CGTool] 地图列表初始化完成,共" + _mapIndexFiles.Count + "个地图文件");
  85. }
  86. //获取全部地图列表
  87. public static List<MapFileInfo> GetMapList()
  88. {
  89. List<MapFileInfo> _list = new List<MapFileInfo>();
  90. foreach (var mapIndexFile in _mapIndexFiles)
  91. {
  92. _list.Add(mapIndexFile.Value);
  93. }
  94. return _list;
  95. }
  96. //获取地图数据
  97. public static MapInfo GetMap(uint serial)
  98. {
  99. //返回缓存数据
  100. if (_cache.ContainsKey(serial)) return _cache[serial];
  101. //加载数据
  102. MapInfo mapInfo = _loadMap(serial);
  103. return mapInfo;
  104. }
  105. // 地面数据合批
  106. public static Dictionary<uint,GraphicDetail> BakeGrounds(uint mapID,List<GraphicInfoData> graphicInfoDatas,int palet = 0,int subPalet = 0,bool linear = false)
  107. {
  108. _mapGroundGraphicBatch.TryGetValue(mapID, out var graphicDataDict);
  109. if (graphicDataDict == null)
  110. {
  111. graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, true, palet, subPalet, linear, 2048, 0);
  112. _mapGroundGraphicBatch[mapID] = graphicDataDict;
  113. }
  114. return graphicDataDict;
  115. }
  116. // 物件数据合批
  117. public static Dictionary<uint,GraphicDetail> BakeObjects(uint mapID,List<GraphicInfoData> graphicInfoDatas,int palet = 0,int subPalet = 0,bool linear = false)
  118. {
  119. _mapObjectGraphicBatch.TryGetValue(mapID, out var graphicDataDict);
  120. if (graphicDataDict == null)
  121. {
  122. graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, true, palet, subPalet, linear, 4096, 0);
  123. _mapObjectGraphicBatch[mapID] = graphicDataDict;
  124. }
  125. return graphicDataDict;
  126. }
  127. public static void ClearMapBatch(uint mapID)
  128. {
  129. Dictionary<uint,GraphicDetail> graphicDataDict;
  130. List<GraphicDetail> graphicDetails;
  131. List<Texture> textures = new List<Texture>();
  132. _mapGroundGraphicBatch.TryGetValue(mapID, out graphicDataDict);
  133. if (graphicDataDict != null)
  134. {
  135. graphicDetails = graphicDataDict.Values.ToList();
  136. foreach (var graphicDetail in graphicDetails)
  137. {
  138. Texture texture = graphicDetail.Sprite.texture;
  139. if (!textures.Contains(texture)) textures.Add(graphicDetail.Sprite.texture);
  140. graphicDetail.SpritePPU100 = null;
  141. graphicDetail.Sprite = null;
  142. }
  143. }
  144. _mapObjectGraphicBatch.TryGetValue(mapID, out graphicDataDict);
  145. if (graphicDataDict != null)
  146. {
  147. graphicDetails = graphicDataDict.Values.ToList();
  148. foreach (var graphicDetail in graphicDetails)
  149. {
  150. Texture texture = graphicDetail.Sprite.texture;
  151. if (!textures.Contains(texture)) textures.Add(graphicDetail.Sprite.texture);
  152. graphicDetail.SpritePPU100 = null;
  153. graphicDetail.Sprite = null;
  154. }
  155. }
  156. foreach (var texture in textures)
  157. {
  158. Resources.UnloadAsset(texture);
  159. }
  160. _mapGroundGraphicBatch.Remove(mapID);
  161. _mapObjectGraphicBatch.Remove(mapID);
  162. }
  163. //加载地图数据
  164. private static MapInfo _loadMap(uint serial)
  165. {
  166. // CGTool.Logger.Write("开始加载时间:" + DateTime.Now);
  167. if (!_mapIndexFiles.ContainsKey(serial)) return null;
  168. // print("找到地图文件: " + mapFileInfo.Name);
  169. FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
  170. BinaryReader mapFileReader = new BinaryReader(mapFileStream);
  171. MapInfo mapInfo = new MapInfo();
  172. mapInfo.Serial = serial;
  173. bool isClientMapFile = false;
  174. //地图文件头
  175. byte[] mapHeader = mapFileReader.ReadBytes( 6);
  176. if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
  177. isClientMapFile = false;
  178. Debug.Log("[CGTool] 地图文件头: 服务端地图");
  179. }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
  180. isClientMapFile = true;
  181. Debug.Log("[CGTool] 地图文件头: 客户端地图");
  182. }
  183. else
  184. {
  185. Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName);
  186. return null;
  187. }
  188. byte[] bytes;
  189. if (isClientMapFile)
  190. {
  191. // 无用信息
  192. mapFileReader.ReadBytes(6);
  193. //读取地图宽度
  194. bytes = mapFileReader.ReadBytes(4);
  195. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  196. //读取地图高度
  197. bytes = mapFileReader.ReadBytes(4);
  198. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  199. if (MapExtra.ClientMapExtraDatas.ContainsKey(serial))
  200. {
  201. mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name;
  202. mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet;
  203. }
  204. else
  205. {
  206. mapInfo.Name = "未知领域";
  207. mapInfo.Palet = -1;
  208. }
  209. }
  210. else
  211. {
  212. // 无用信息
  213. mapFileReader.ReadBytes(2);
  214. //地图名称
  215. byte[] mapNameBytes = mapFileReader.ReadBytes(32);
  216. string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|');
  217. mapInfo.Name = mapHead[0];
  218. // 调色板
  219. if (mapHead.Length>1){
  220. if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]);
  221. }
  222. //读取地图宽度
  223. bytes = mapFileReader.ReadBytes(2);
  224. Array.Reverse(bytes);
  225. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  226. //读取地图高度
  227. bytes = mapFileReader.ReadBytes(2);
  228. Array.Reverse(bytes);
  229. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  230. }
  231. byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  232. byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  233. mapFileReader.Dispose();
  234. mapFileReader.Close();
  235. mapFileStream.Close();
  236. // print(JsonUtility.ToJson(mapInfo));
  237. BinaryReader mapReader = new BinaryReader(new MemoryStream(mapBytes));
  238. BinaryReader mapCoverReader = new BinaryReader(new MemoryStream(mapCoverBytes));
  239. // BinaryReader mapInfoReader = new BinaryReader(new MemoryStream(mapInfoBytes));
  240. List<MapBlockData> tempGroundTiles = new List<MapBlockData>();
  241. List<MapBlockData> tempObjectTiles = new List<MapBlockData>();
  242. // CGTool.Logger.Write("开始解析时间:" + DateTime.Now);
  243. //原始数据为反转数据,即坐标起点为 1,1 排序方向为 y : 1=>0 x: 1=>0
  244. int len = mapInfo.Width * mapInfo.Height;
  245. for (int i = 0; i < len; i++)
  246. {
  247. //地面数据
  248. MapBlockData mapTile = null;
  249. bytes = mapReader.ReadBytes(2);
  250. if(!isClientMapFile) Array.Reverse(bytes);
  251. uint mapGraphicSerial = BitConverter.ToUInt16(bytes,0);
  252. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial);
  253. if (graphicInfoData != null)
  254. {
  255. mapTile = new MapBlockData();
  256. mapTile.GraphicInfo = graphicInfoData;
  257. mapTile.MapSerial = mapGraphicSerial;
  258. }
  259. tempGroundTiles.Add(mapTile);
  260. MapBlockData mapCoverTile = null;
  261. bytes = mapCoverReader.ReadBytes(2);
  262. if(!isClientMapFile) Array.Reverse(bytes);
  263. uint mapCoverGraphicSerial = BitConverter.ToUInt16(bytes,0);
  264. graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial);
  265. if (graphicInfoData != null)
  266. {
  267. mapCoverTile = new MapBlockData();
  268. mapCoverTile.GraphicInfo = graphicInfoData;
  269. mapCoverTile.MapSerial = mapCoverGraphicSerial;
  270. }
  271. tempObjectTiles.Add(mapCoverTile);
  272. }
  273. MapBlockData[] GroundTiles = new MapBlockData[len];
  274. MapBlockData[] ObjectTiles = new MapBlockData[len];
  275. bool[] blockedIndexs = new bool[len];
  276. bool[,] nodes = new bool[mapInfo.Width, mapInfo.Height];
  277. mapInfo.FixPlayerZs = new float[len];
  278. // CGTool.Logger.Write("开始排序时间:" + DateTime.Now);
  279. //重新排序
  280. for (int y = 0; y < mapInfo.Height; y++)
  281. {
  282. for (int x = 0; x < mapInfo.Width; x++)
  283. {
  284. // int index = i * (int) mapInfo.Width + ((int) mapInfo.Width - j - 1);
  285. int _tmpindex = x + (mapInfo.Height - y - 1) * mapInfo.Width;
  286. int index = x + y * mapInfo.Width;
  287. MapBlockData mapTile = tempGroundTiles[_tmpindex];
  288. MapBlockData ObjectTile = tempObjectTiles[_tmpindex];
  289. GroundTiles[index] = mapTile;
  290. ObjectTiles[index] = ObjectTile;
  291. if (mapTile==null || mapTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  292. //角色默认层级
  293. float Z = x * 9 + y * 11;
  294. mapInfo.FixPlayerZs[index] = Z;
  295. if (ObjectTile != null)
  296. {
  297. ObjectTile.MapIndex = index;
  298. if (!ObjectTile.GraphicInfo.AsGround)
  299. {
  300. ObjectTile.ObjectZIndex = Z + Math.Min(ObjectTile.GraphicInfo.East,ObjectTile.GraphicInfo.South) * 10 - 10;
  301. ObjectTile.x = x;
  302. ObjectTile.y = y;
  303. if(ObjectTile.GraphicInfo !=null && ObjectTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  304. }
  305. }
  306. nodes[x, y] = !blockedIndexs[index];
  307. }
  308. }
  309. // Z轴修正
  310. void resetObjectZ(MapBlockData blockData,float Z = 0f)
  311. {
  312. if (!blockData.GraphicInfo.Blocked)
  313. {
  314. blockData.ObjectZIndex = blockData.ObjectZIndex + 0.1f;
  315. return;
  316. }
  317. int x = blockData.x;
  318. int y = blockData.y;
  319. if (Z != 0f)
  320. {
  321. mapInfo.FixPlayerZs[(int)(y * mapInfo.Width + x)] = Z;
  322. blockData.ObjectZIndex = Z;
  323. }
  324. else
  325. {
  326. Z = blockData.ObjectZIndex;
  327. }
  328. int ox = x - 1;
  329. if (ox >= 0 && (blockData.GraphicInfo.South>2 || blockData.GraphicInfo.Serial==17644))
  330. {
  331. int maxHeight = Math.Min(y + blockData.GraphicInfo.South, mapInfo.Height);
  332. float leftZ = Z - 10f;
  333. for(int n = y;n<maxHeight;n++)
  334. {
  335. int _index = (int)(n * mapInfo.Width + ox);
  336. mapInfo.FixPlayerZs[_index] = leftZ + (n-y) * 0.1f;
  337. if (ObjectTiles[_index] != null) if(blockData.GraphicInfo.Serial != 17644 && ObjectTiles[_index].GraphicInfo.Serial== 17644) resetObjectZ(ObjectTiles[_index],leftZ);
  338. }
  339. }
  340. int oy = y - 1;
  341. if (oy >= 0 && (blockData.GraphicInfo.East>2 || blockData.GraphicInfo.Serial==17644))
  342. {
  343. int maxWidth = Math.Min(x + blockData.GraphicInfo.East, mapInfo.Width);
  344. float rightZ = Z - 10f;
  345. for(int n = x;n<maxWidth;n++)
  346. {
  347. int _index = (int)(oy * mapInfo.Width + n);
  348. mapInfo.FixPlayerZs[_index] = rightZ + (n-x) * 0.1f;
  349. if (ObjectTiles[_index] != null) if(blockData.GraphicInfo.Serial != 17644 && ObjectTiles[_index].GraphicInfo.Serial == 17644) resetObjectZ(ObjectTiles[_index],rightZ);
  350. }
  351. }
  352. if (blockData.GraphicInfo.Serial == 17644)
  353. {
  354. x = blockData.x - 1;
  355. y = blockData.y - 1;
  356. mapInfo.FixPlayerZs[(int)(y * mapInfo.Width + x)] = Z;
  357. }
  358. }
  359. //整理Object Z轴层级遮挡及角色遮挡问题
  360. for (int y = 0; y < mapInfo.Height; y++)
  361. {
  362. for (int x = 0; x < mapInfo.Width; x++)
  363. {
  364. int index = x + y * mapInfo.Width;
  365. // int objectTileZIndex = index * FixZIndex;
  366. MapBlockData ObjectTile = ObjectTiles[index];
  367. if(ObjectTile==null || ObjectTile.GraphicInfo==null) continue;
  368. //地图单位Z轴补正
  369. if (!ObjectTile.GraphicInfo.AsGround && ObjectTile.GraphicInfo.Serial != 17644)
  370. {
  371. resetObjectZ(ObjectTile, ObjectTile.ObjectZIndex);
  372. }
  373. //如果物件占地范围大于1x1,则需要处理行走限制
  374. if (ObjectTile.GraphicInfo.Blocked && (ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1))
  375. {
  376. for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++)
  377. {
  378. for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++)
  379. {
  380. if(i>=mapInfo.Width || j>=mapInfo.Height) continue;
  381. int _index = (int) (j * mapInfo.Width + i);
  382. blockedIndexs[_index] = true;
  383. nodes[i, j] = false;
  384. }
  385. }
  386. }
  387. }
  388. }
  389. mapInfo.GroundDatas = GroundTiles.ToList();
  390. mapInfo.ObjectDatas = ObjectTiles.ToList();
  391. mapInfo.BlockedIndexs = blockedIndexs;
  392. mapInfo.MapNodes = nodes;
  393. _cache[serial] = mapInfo;
  394. Debug.Log("[CGTool] 读取地图: " + mapInfo.Name);
  395. Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
  396. // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
  397. return mapInfo;
  398. }
  399. }
  400. }