Map.cs 18 KB

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