Map.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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. namespace CrossgateToolkit
  17. {
  18. //地图文件信息
  19. public class MapFileInfo
  20. {
  21. public uint Serial;
  22. public string Name;
  23. public string FileName;
  24. }
  25. //地图块数据
  26. public class MapBlockData
  27. {
  28. public GraphicInfoData GraphicInfo;
  29. // public uint GraphicIndex;
  30. public uint MapSerial;
  31. public int FixPlayerZ;
  32. public int ObjectZIndex = 0;
  33. }
  34. //地图信息
  35. public class MapInfo
  36. {
  37. //地图编号
  38. public uint Serial;
  39. //地图宽度
  40. public int Width;
  41. //地图高度
  42. public int Height;
  43. // 地图名称
  44. public string Name;
  45. // 调色板号 - 默认 -1 表示自动
  46. public int Palet = -1;
  47. //未知数据
  48. public byte[] Unknow;
  49. //地面数据
  50. public List<MapBlockData> GroundDatas = new List<MapBlockData>();
  51. //地表数据
  52. public List<MapBlockData> ObjectDatas = new List<MapBlockData>();
  53. public bool[] BlockedIndexs;
  54. public float[] FixPlayerZs;
  55. //地图坐标二维数组,用以记录可行走区域并作为自动寻路的数据参考
  56. public bool[,] MapNodes;
  57. }
  58. public class Map
  59. {
  60. //Z轴修正值
  61. public static readonly int FixZIndex = 24;
  62. //缓存数据
  63. private static Dictionary<uint, MapInfo> _cache = new Dictionary<uint, MapInfo>();
  64. private static Dictionary<uint, MapFileInfo> _mapIndexFiles = new Dictionary<uint, MapFileInfo>();
  65. //初始化地图文件列表
  66. public static void Init()
  67. {
  68. DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.PATH.MAP);
  69. FileInfo[] mapFiles = mapDirectory.GetFiles();
  70. string match = @"^(\d+)_?(.+)?$";
  71. foreach (var fileInfo in mapFiles)
  72. {
  73. string filename = fileInfo.Name;
  74. Match matchRet = Regex.Match(filename, match);
  75. if(!matchRet.Success) continue;
  76. MapFileInfo _file = new MapFileInfo();
  77. _file.Serial = uint.Parse(matchRet.Groups[1].Value);
  78. if(matchRet.Groups.Count > 1) _file.Name = matchRet.Groups[1].Value;
  79. _file.FileName = filename;
  80. _mapIndexFiles.Add(_file.Serial, _file);
  81. }
  82. Debug.Log("[CGTool] 地图列表初始化完成,共" + _mapIndexFiles.Count + "个地图文件");
  83. }
  84. //获取全部地图列表
  85. public static List<MapFileInfo> GetMapList()
  86. {
  87. List<MapFileInfo> _list = new List<MapFileInfo>();
  88. foreach (var mapIndexFile in _mapIndexFiles)
  89. {
  90. _list.Add(mapIndexFile.Value);
  91. }
  92. return _list;
  93. }
  94. //获取地图数据
  95. public static MapInfo GetMap(uint serial)
  96. {
  97. //返回缓存数据
  98. if (_cache.ContainsKey(serial)) return _cache[serial];
  99. //加载数据
  100. MapInfo mapInfo = _loadMap(serial);
  101. return mapInfo;
  102. }
  103. //加载地图数据
  104. private static MapInfo _loadMap(uint serial)
  105. {
  106. // CGTool.Logger.Write("开始加载时间:" + DateTime.Now);
  107. if (!_mapIndexFiles.ContainsKey(serial)) return null;
  108. // print("找到地图文件: " + mapFileInfo.Name);
  109. FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
  110. BinaryReader mapFileReader = new BinaryReader(mapFileStream);
  111. MapInfo mapInfo = new MapInfo();
  112. mapInfo.Serial = serial;
  113. bool isClientMapFile = false;
  114. //地图文件头
  115. byte[] mapHeader = mapFileReader.ReadBytes( 6);
  116. if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
  117. isClientMapFile = false;
  118. Debug.Log("[CGTool] 地图文件头: 服务端地图");
  119. }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
  120. isClientMapFile = true;
  121. Debug.Log("[CGTool] 地图文件头: 客户端地图");
  122. }
  123. else
  124. {
  125. Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName);
  126. return null;
  127. }
  128. byte[] bytes;
  129. if (isClientMapFile)
  130. {
  131. // 无用信息
  132. mapFileReader.ReadBytes(6);
  133. //读取地图宽度
  134. bytes = mapFileReader.ReadBytes(4);
  135. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  136. //读取地图高度
  137. bytes = mapFileReader.ReadBytes(4);
  138. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  139. if (MapExtra.ClientMapExtraDatas.ContainsKey(serial))
  140. {
  141. mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name;
  142. mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet;
  143. }
  144. else
  145. {
  146. mapInfo.Name = "未知领域";
  147. mapInfo.Palet = -1;
  148. }
  149. }
  150. else
  151. {
  152. // 无用信息
  153. mapFileReader.ReadBytes(2);
  154. //地图名称
  155. byte[] mapNameBytes = mapFileReader.ReadBytes(32);
  156. string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|');
  157. mapInfo.Name = mapHead[0];
  158. // 调色板
  159. if (mapHead.Length>1){
  160. if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]);
  161. }
  162. //读取地图宽度
  163. bytes = mapFileReader.ReadBytes(2);
  164. Array.Reverse(bytes);
  165. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  166. //读取地图高度
  167. bytes = mapFileReader.ReadBytes(2);
  168. Array.Reverse(bytes);
  169. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  170. }
  171. byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  172. byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  173. mapFileReader.Dispose();
  174. mapFileReader.Close();
  175. mapFileStream.Close();
  176. // print(JsonUtility.ToJson(mapInfo));
  177. BinaryReader mapReader = new BinaryReader(new MemoryStream(mapBytes));
  178. BinaryReader mapCoverReader = new BinaryReader(new MemoryStream(mapCoverBytes));
  179. // BinaryReader mapInfoReader = new BinaryReader(new MemoryStream(mapInfoBytes));
  180. List<MapBlockData> tempGroundTiles = new List<MapBlockData>();
  181. List<MapBlockData> tempObjectTiles = new List<MapBlockData>();
  182. // CGTool.Logger.Write("开始解析时间:" + DateTime.Now);
  183. //原始数据为反转数据,即坐标起点为 1,1 排序方向为 y : 1=>0 x: 1=>0
  184. int len = mapInfo.Width * mapInfo.Height;
  185. for (int i = 0; i < len; i++)
  186. {
  187. //地面数据
  188. MapBlockData mapTile = null;
  189. bytes = mapReader.ReadBytes(2);
  190. if(!isClientMapFile) Array.Reverse(bytes);
  191. uint mapGraphicSerial = BitConverter.ToUInt16(bytes,0);
  192. int Version = 0;
  193. if (mapGraphicSerial > 20000)
  194. {
  195. mapGraphicSerial += 200000;
  196. Version = 1;
  197. }
  198. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial);
  199. if (graphicInfoData != null)
  200. {
  201. mapTile = new MapBlockData();
  202. mapTile.GraphicInfo = graphicInfoData;
  203. mapTile.MapSerial = mapGraphicSerial;
  204. }
  205. tempGroundTiles.Add(mapTile);
  206. MapBlockData mapCoverTile = null;
  207. bytes = mapCoverReader.ReadBytes(2);
  208. if(!isClientMapFile) Array.Reverse(bytes);
  209. uint mapCoverGraphicSerial = BitConverter.ToUInt16(bytes,0);
  210. Version = 0;
  211. if (mapCoverGraphicSerial > 30000 || mapCoverGraphicSerial==25290)
  212. {
  213. mapCoverGraphicSerial += 200000;
  214. Version = 1;
  215. }
  216. graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial);
  217. if (graphicInfoData != null)
  218. {
  219. mapCoverTile = new MapBlockData();
  220. mapCoverTile.GraphicInfo = graphicInfoData;
  221. mapCoverTile.MapSerial = mapCoverGraphicSerial;
  222. }
  223. tempObjectTiles.Add(mapCoverTile);
  224. }
  225. MapBlockData[] GroundTiles = new MapBlockData[len];
  226. MapBlockData[] ObjectTiles = new MapBlockData[len];
  227. bool[] blockedIndexs = new bool[len];
  228. float[] fixPlayerZs = new float[len];
  229. bool[,] nodes = new bool[mapInfo.Width, mapInfo.Height];
  230. // CGTool.Logger.Write("开始排序时间:" + DateTime.Now);
  231. //重新排序
  232. for (int y = 0; y < mapInfo.Height; y++)
  233. {
  234. for (int x = 0; x < mapInfo.Width; x++)
  235. {
  236. // int index = i * (int) mapInfo.Width + ((int) mapInfo.Width - j - 1);
  237. int _tmpindex = x + (mapInfo.Height - y - 1) * mapInfo.Width;
  238. int index = x + y * mapInfo.Width;
  239. MapBlockData mapTile = tempGroundTiles[_tmpindex];
  240. MapBlockData ObjectTile = tempObjectTiles[_tmpindex];
  241. GroundTiles[index] = mapTile;
  242. ObjectTiles[index] = ObjectTile;
  243. if (mapTile==null || mapTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  244. if (ObjectTile!=null && ObjectTile.GraphicInfo !=null && ObjectTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  245. nodes[x, y] = !blockedIndexs[index];
  246. //角色默认层级
  247. // int objectTileZIndex = index * FixZIndex;
  248. fixPlayerZs[index] = 1;
  249. }
  250. }
  251. //整理Object Z轴层级遮挡及角色遮挡问题
  252. for (int y = 0; y < mapInfo.Height; y++)
  253. {
  254. for (int x = 0; x < mapInfo.Width; x++)
  255. {
  256. int index = x + y * mapInfo.Width;
  257. int objectTileZIndex = index * FixZIndex;
  258. MapBlockData ObjectTile = ObjectTiles[index];
  259. if(ObjectTile==null || ObjectTile.GraphicInfo==null) continue;
  260. //Object默认层级
  261. ObjectTile.ObjectZIndex = objectTileZIndex;
  262. //角色Z轴补正
  263. //在自定义排序轴(1,1,-1)情况下,角色Z轴在物件y-1位置,到x+East位置,补正为48*x
  264. //在物件South+1位置,到x+East位置,补正为-48*x
  265. if (!ObjectTile.GraphicInfo.AsGround)
  266. {
  267. for(int i = x;i<(x+ObjectTile.GraphicInfo.East);i++)
  268. {
  269. int fix = 1;
  270. int oy = y - 1;
  271. int _index = (int) (oy * mapInfo.Width + i);
  272. if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - x + 1) * 240f + 0.1f;
  273. // fix = -1;
  274. // oy = y + ObjectTile.GraphicInfo.South;
  275. // _index = (int) (oy * mapInfo.Width + i);
  276. // if (fixPlayerZs[_index] == 0) fixPlayerZs[_index] = fix * (i - x + 1) * 100;
  277. }
  278. for(int i=y+1;i<(y+ObjectTile.GraphicInfo.South);i++)
  279. {
  280. int fix = 1;
  281. int ox = x - 1;
  282. int _index = (int) (i * mapInfo.Width + ox);
  283. if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - y - 1) * 240f + 0.1f;
  284. }
  285. }
  286. else
  287. {
  288. // ObjectTile.ObjectZIndex = 0;
  289. }
  290. //如果物件占地范围大于1x1,则需要处理行走限制
  291. if ((ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1) && ObjectTile.GraphicInfo.Blocked)
  292. {
  293. //取物件占地中间点位置
  294. // objectTileZIndex = (x + ObjectTile.GraphicInfo.East / 2 + (y + ObjectTile.GraphicInfo.South / 2) * mapInfo.Width) * FixZIndex;
  295. // ObjectTile.ObjectZIndex = objectTileZIndex;
  296. //取物件左上角位置Z轴复写默认Z轴
  297. // ObjectTile.ObjectZIndex = (x + (y + ObjectTile.GraphicInfo.South) * mapInfo.Width) * FixZIndex;
  298. for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++)
  299. {
  300. for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++)
  301. {
  302. if(i>=mapInfo.Width || j>=mapInfo.Height) continue;
  303. int _index = (int) (j * mapInfo.Width + i);
  304. blockedIndexs[_index] = true;
  305. nodes[i, j] = false;
  306. }
  307. }
  308. }
  309. }
  310. }
  311. mapInfo.GroundDatas = GroundTiles.ToList();
  312. mapInfo.ObjectDatas = ObjectTiles.ToList();
  313. mapInfo.BlockedIndexs = blockedIndexs;
  314. mapInfo.MapNodes = nodes;
  315. mapInfo.FixPlayerZs = fixPlayerZs;
  316. _cache[serial] = mapInfo;
  317. Debug.Log("[CGTool] 读取地图: " + mapInfo.Name);
  318. Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
  319. // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
  320. return mapInfo;
  321. }
  322. }
  323. }