Map.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. public static Dictionary<uint,GraphicDetail> BakeGrounds(List<GraphicInfoData> graphicInfoDatas,int palet = 0)
  105. {
  106. Dictionary<uint, GraphicDetail>
  107. graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, palet, 2048, 0);
  108. return graphicDataDict;
  109. }
  110. // 物件数据合批
  111. public static Dictionary<uint,GraphicDetail> BakeObjects(List<GraphicInfoData> graphicInfoDatas,int palet = 0)
  112. {
  113. Dictionary<uint, GraphicDetail>
  114. graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, palet, 4096);
  115. return graphicDataDict;
  116. }
  117. //加载地图数据
  118. private static MapInfo _loadMap(uint serial)
  119. {
  120. // CGTool.Logger.Write("开始加载时间:" + DateTime.Now);
  121. if (!_mapIndexFiles.ContainsKey(serial)) return null;
  122. // print("找到地图文件: " + mapFileInfo.Name);
  123. FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
  124. BinaryReader mapFileReader = new BinaryReader(mapFileStream);
  125. MapInfo mapInfo = new MapInfo();
  126. mapInfo.Serial = serial;
  127. bool isClientMapFile = false;
  128. //地图文件头
  129. byte[] mapHeader = mapFileReader.ReadBytes( 6);
  130. if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
  131. isClientMapFile = false;
  132. Debug.Log("[CGTool] 地图文件头: 服务端地图");
  133. }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
  134. isClientMapFile = true;
  135. Debug.Log("[CGTool] 地图文件头: 客户端地图");
  136. }
  137. else
  138. {
  139. Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName);
  140. return null;
  141. }
  142. byte[] bytes;
  143. if (isClientMapFile)
  144. {
  145. // 无用信息
  146. mapFileReader.ReadBytes(6);
  147. //读取地图宽度
  148. bytes = mapFileReader.ReadBytes(4);
  149. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  150. //读取地图高度
  151. bytes = mapFileReader.ReadBytes(4);
  152. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  153. if (MapExtra.ClientMapExtraDatas.ContainsKey(serial))
  154. {
  155. mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name;
  156. mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet;
  157. }
  158. else
  159. {
  160. mapInfo.Name = "未知领域";
  161. mapInfo.Palet = -1;
  162. }
  163. }
  164. else
  165. {
  166. // 无用信息
  167. mapFileReader.ReadBytes(2);
  168. //地图名称
  169. byte[] mapNameBytes = mapFileReader.ReadBytes(32);
  170. string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|');
  171. mapInfo.Name = mapHead[0];
  172. // 调色板
  173. if (mapHead.Length>1){
  174. if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]);
  175. }
  176. //读取地图宽度
  177. bytes = mapFileReader.ReadBytes(2);
  178. Array.Reverse(bytes);
  179. mapInfo.Width = BitConverter.ToUInt16(bytes,0);
  180. //读取地图高度
  181. bytes = mapFileReader.ReadBytes(2);
  182. Array.Reverse(bytes);
  183. mapInfo.Height = BitConverter.ToUInt16(bytes,0);
  184. }
  185. byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  186. byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
  187. mapFileReader.Dispose();
  188. mapFileReader.Close();
  189. mapFileStream.Close();
  190. // print(JsonUtility.ToJson(mapInfo));
  191. BinaryReader mapReader = new BinaryReader(new MemoryStream(mapBytes));
  192. BinaryReader mapCoverReader = new BinaryReader(new MemoryStream(mapCoverBytes));
  193. // BinaryReader mapInfoReader = new BinaryReader(new MemoryStream(mapInfoBytes));
  194. List<MapBlockData> tempGroundTiles = new List<MapBlockData>();
  195. List<MapBlockData> tempObjectTiles = new List<MapBlockData>();
  196. // CGTool.Logger.Write("开始解析时间:" + DateTime.Now);
  197. //原始数据为反转数据,即坐标起点为 1,1 排序方向为 y : 1=>0 x: 1=>0
  198. int len = mapInfo.Width * mapInfo.Height;
  199. for (int i = 0; i < len; i++)
  200. {
  201. //地面数据
  202. MapBlockData mapTile = null;
  203. bytes = mapReader.ReadBytes(2);
  204. if(!isClientMapFile) Array.Reverse(bytes);
  205. uint mapGraphicSerial = BitConverter.ToUInt16(bytes,0);
  206. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial);
  207. if (graphicInfoData != null)
  208. {
  209. mapTile = new MapBlockData();
  210. mapTile.GraphicInfo = graphicInfoData;
  211. mapTile.MapSerial = mapGraphicSerial;
  212. }
  213. tempGroundTiles.Add(mapTile);
  214. MapBlockData mapCoverTile = null;
  215. bytes = mapCoverReader.ReadBytes(2);
  216. if(!isClientMapFile) Array.Reverse(bytes);
  217. uint mapCoverGraphicSerial = BitConverter.ToUInt16(bytes,0);
  218. graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial);
  219. if (graphicInfoData != null)
  220. {
  221. mapCoverTile = new MapBlockData();
  222. mapCoverTile.GraphicInfo = graphicInfoData;
  223. mapCoverTile.MapSerial = mapCoverGraphicSerial;
  224. }
  225. tempObjectTiles.Add(mapCoverTile);
  226. }
  227. MapBlockData[] GroundTiles = new MapBlockData[len];
  228. MapBlockData[] ObjectTiles = new MapBlockData[len];
  229. bool[] blockedIndexs = new bool[len];
  230. float[] fixPlayerZs = new float[len];
  231. bool[,] nodes = new bool[mapInfo.Width, mapInfo.Height];
  232. // CGTool.Logger.Write("开始排序时间:" + DateTime.Now);
  233. //重新排序
  234. for (int y = 0; y < mapInfo.Height; y++)
  235. {
  236. for (int x = 0; x < mapInfo.Width; x++)
  237. {
  238. // int index = i * (int) mapInfo.Width + ((int) mapInfo.Width - j - 1);
  239. int _tmpindex = x + (mapInfo.Height - y - 1) * mapInfo.Width;
  240. int index = x + y * mapInfo.Width;
  241. MapBlockData mapTile = tempGroundTiles[_tmpindex];
  242. MapBlockData ObjectTile = tempObjectTiles[_tmpindex];
  243. GroundTiles[index] = mapTile;
  244. ObjectTiles[index] = ObjectTile;
  245. if (mapTile==null || mapTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  246. if (ObjectTile!=null && ObjectTile.GraphicInfo !=null && ObjectTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
  247. nodes[x, y] = !blockedIndexs[index];
  248. //角色默认层级
  249. // int objectTileZIndex = index * FixZIndex;
  250. fixPlayerZs[index] = 1;
  251. }
  252. }
  253. //整理Object Z轴层级遮挡及角色遮挡问题
  254. for (int y = 0; y < mapInfo.Height; y++)
  255. {
  256. for (int x = 0; x < mapInfo.Width; x++)
  257. {
  258. int index = x + y * mapInfo.Width;
  259. int objectTileZIndex = index * FixZIndex;
  260. MapBlockData ObjectTile = ObjectTiles[index];
  261. if(ObjectTile==null || ObjectTile.GraphicInfo==null) continue;
  262. //Object默认层级
  263. ObjectTile.ObjectZIndex = objectTileZIndex;
  264. //角色Z轴补正
  265. //在自定义排序轴(1,1,-1)情况下,角色Z轴在物件y-1位置,到x+East位置,补正为48*x
  266. //在物件South+1位置,到x+East位置,补正为-48*x
  267. if (!ObjectTile.GraphicInfo.AsGround)
  268. {
  269. for(int i = x;i<(x+ObjectTile.GraphicInfo.East);i++)
  270. {
  271. int fix = 1;
  272. int oy = y - 1;
  273. int _index = (int) (oy * mapInfo.Width + i);
  274. if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - x + 1) * 240f + 0.1f;
  275. // fix = -1;
  276. // oy = y + ObjectTile.GraphicInfo.South;
  277. // _index = (int) (oy * mapInfo.Width + i);
  278. // if (fixPlayerZs[_index] == 0) fixPlayerZs[_index] = fix * (i - x + 1) * 100;
  279. }
  280. for(int i=y+1;i<(y+ObjectTile.GraphicInfo.South);i++)
  281. {
  282. int fix = 1;
  283. int ox = x - 1;
  284. int _index = (int) (i * mapInfo.Width + ox);
  285. if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - y - 1) * 240f + 0.1f;
  286. }
  287. }
  288. else
  289. {
  290. // ObjectTile.ObjectZIndex = 0;
  291. }
  292. //如果物件占地范围大于1x1,则需要处理行走限制
  293. if ((ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1) && ObjectTile.GraphicInfo.Blocked)
  294. {
  295. //取物件占地中间点位置
  296. // objectTileZIndex = (x + ObjectTile.GraphicInfo.East / 2 + (y + ObjectTile.GraphicInfo.South / 2) * mapInfo.Width) * FixZIndex;
  297. // ObjectTile.ObjectZIndex = objectTileZIndex;
  298. //取物件左上角位置Z轴复写默认Z轴
  299. // ObjectTile.ObjectZIndex = (x + (y + ObjectTile.GraphicInfo.South) * mapInfo.Width) * FixZIndex;
  300. for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++)
  301. {
  302. for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++)
  303. {
  304. if(i>=mapInfo.Width || j>=mapInfo.Height) continue;
  305. int _index = (int) (j * mapInfo.Width + i);
  306. blockedIndexs[_index] = true;
  307. nodes[i, j] = false;
  308. }
  309. }
  310. }
  311. }
  312. }
  313. mapInfo.GroundDatas = GroundTiles.ToList();
  314. mapInfo.ObjectDatas = ObjectTiles.ToList();
  315. mapInfo.BlockedIndexs = blockedIndexs;
  316. mapInfo.MapNodes = nodes;
  317. mapInfo.FixPlayerZs = fixPlayerZs;
  318. _cache[serial] = mapInfo;
  319. Debug.Log("[CGTool] 读取地图: " + mapInfo.Name);
  320. Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
  321. // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
  322. return mapInfo;
  323. }
  324. }
  325. }