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 CGTool
  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.MapFolder);
  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. }
  83. //获取全部地图列表
  84. public static List<MapFileInfo> GetMapList()
  85. {
  86. List<MapFileInfo> _list = new List<MapFileInfo>();
  87. foreach (var mapIndexFile in _mapIndexFiles)
  88. {
  89. _list.Add(mapIndexFile.Value);
  90. }
  91. return _list;
  92. }
  93. //获取地图数据
  94. public static MapInfo GetMap(uint serial)
  95. {
  96. //返回缓存数据
  97. if (_cache.ContainsKey(serial)) return _cache[serial];
  98. //加载数据
  99. MapInfo mapInfo = _loadMap(serial);
  100. return mapInfo;
  101. }
  102. //加载地图数据
  103. private static MapInfo _loadMap(uint serial)
  104. {
  105. // CGTool.Logger.Write("开始加载时间:" + DateTime.Now);
  106. if (!_mapIndexFiles.ContainsKey(serial)) return null;
  107. // print("找到地图文件: " + mapFileInfo.Name);
  108. FileStream mapFileStream = new FileStream(CGTool.MapFolder + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
  109. BinaryReader mapFileReader = new BinaryReader(mapFileStream);
  110. MapInfo mapInfo = new MapInfo();
  111. mapInfo.Serial = serial;
  112. bool isClientMapFile = false;
  113. //地图文件头
  114. byte[] mapHeader = mapFileReader.ReadBytes( 6);
  115. if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
  116. isClientMapFile = false;
  117. Debug.Log("地图文件头: 服务端地图");
  118. }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
  119. isClientMapFile = true;
  120. Debug.Log("地图文件头: 客户端地图");
  121. }
  122. else
  123. {
  124. Debug.Log("地图文件头错误: " + _mapIndexFiles[serial].FileName);
  125. return null;
  126. }
  127. byte[] bytes;
  128. if (isClientMapFile)
  129. {
  130. // 无用信息
  131. mapFileReader.ReadBytes(6);
  132. //读取地图宽度
  133. bytes = mapFileReader.ReadBytes(4);
  134. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  135. //读取地图高度
  136. bytes = mapFileReader.ReadBytes(4);
  137. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  138. if (MapExtra.ClientMapExtraDatas.ContainsKey(serial))
  139. {
  140. mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name;
  141. mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet;
  142. }
  143. else
  144. {
  145. mapInfo.Name = "未知领域";
  146. mapInfo.Palet = -1;
  147. }
  148. }
  149. else
  150. {
  151. // 无用信息
  152. mapFileReader.ReadBytes(2);
  153. //地图名称
  154. byte[] mapNameBytes = mapFileReader.ReadBytes(32);
  155. string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|');
  156. mapInfo.Name = mapHead[0];
  157. // 调色板
  158. if (mapHead.Length>1){
  159. if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]);
  160. }
  161. //读取地图宽度
  162. bytes = mapFileReader.ReadBytes(2);
  163. Array.Reverse(bytes);
  164. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  165. //读取地图高度
  166. bytes = mapFileReader.ReadBytes(2);
  167. Array.Reverse(bytes);
  168. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  169. }
  170. Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
  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.GetGraphicInfoDataBySerial(Version, 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.GetGraphicInfoDataBySerial(Version, 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-1);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)
  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. // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
  318. return mapInfo;
  319. }
  320. }
  321. }