123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- /**
- * 魔力宝贝图档解析脚本 - CGTool
- *
- * @Author HonorLee (dev@honorlee.me)
- * @Version 1.0 (2023-04-15)
- * @License GPL-3.0
- *
- * Map.cs 服务端地图解析类
- */
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text.RegularExpressions;
- using UnityEngine;
- namespace CrossgateToolkit
- {
- //地图文件信息
- public class MapFileInfo
- {
- public uint Serial;
- public string Name;
- public string FileName;
- }
- //地图块数据
- public class MapBlockData
- {
- public GraphicInfoData GraphicInfo;
- // public uint GraphicIndex;
- public uint MapSerial;
- public int FixPlayerZ;
- public int ObjectZIndex = 0;
- }
- //地图信息
- public class MapInfo
- {
- //地图编号
- public uint Serial;
- //地图宽度
- public int Width;
- //地图高度
- public int Height;
- // 地图名称
- public string Name;
- // 调色板号 - 默认 -1 表示自动
- public int Palet = -1;
- //未知数据
- public byte[] Unknow;
- //地面数据
- public List<MapBlockData> GroundDatas = new List<MapBlockData>();
- //地表数据
- public List<MapBlockData> ObjectDatas = new List<MapBlockData>();
- public bool[] BlockedIndexs;
- public float[] FixPlayerZs;
- //地图坐标二维数组,用以记录可行走区域并作为自动寻路的数据参考
- public bool[,] MapNodes;
- }
-
-
- public class Map
- {
- //Z轴修正值
- public static readonly int FixZIndex = 24;
-
- //缓存数据
- private static Dictionary<uint, MapInfo> _cache = new Dictionary<uint, MapInfo>();
- private static Dictionary<uint, MapFileInfo> _mapIndexFiles = new Dictionary<uint, MapFileInfo>();
- //初始化地图文件列表
- public static void Init()
- {
- DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.PATH.MAP);
- FileInfo[] mapFiles = mapDirectory.GetFiles();
- string match = @"^(\d+)_?(.+)?$";
- foreach (var fileInfo in mapFiles)
- {
- string filename = fileInfo.Name;
- Match matchRet = Regex.Match(filename, match);
- if(!matchRet.Success) continue;
-
- MapFileInfo _file = new MapFileInfo();
- _file.Serial = uint.Parse(matchRet.Groups[1].Value);
- if(matchRet.Groups.Count > 1) _file.Name = matchRet.Groups[1].Value;
- _file.FileName = filename;
- _mapIndexFiles.Add(_file.Serial, _file);
- }
- Debug.Log("[CGTool] 地图列表初始化完成,共" + _mapIndexFiles.Count + "个地图文件");
- }
- //获取全部地图列表
- public static List<MapFileInfo> GetMapList()
- {
- List<MapFileInfo> _list = new List<MapFileInfo>();
- foreach (var mapIndexFile in _mapIndexFiles)
- {
- _list.Add(mapIndexFile.Value);
- }
- return _list;
- }
- //获取地图数据
- public static MapInfo GetMap(uint serial)
- {
-
- //返回缓存数据
- if (_cache.ContainsKey(serial)) return _cache[serial];
- //加载数据
- MapInfo mapInfo = _loadMap(serial);
- return mapInfo;
- }
-
- // 地面数据合批
- public static Dictionary<uint,GraphicDetail> BakeGrounds(List<GraphicInfoData> graphicInfoDatas,int palet = 0)
- {
- Dictionary<uint, GraphicDetail>
- graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, palet, 2048, 0);
- return graphicDataDict;
- }
-
- // 物件数据合批
- public static Dictionary<uint,GraphicDetail> BakeObjects(List<GraphicInfoData> graphicInfoDatas,int palet = 0)
- {
- Dictionary<uint, GraphicDetail>
- graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, palet, 4096);
- return graphicDataDict;
- }
- //加载地图数据
- private static MapInfo _loadMap(uint serial)
- {
- // CGTool.Logger.Write("开始加载时间:" + DateTime.Now);
- if (!_mapIndexFiles.ContainsKey(serial)) return null;
-
- // print("找到地图文件: " + mapFileInfo.Name);
- FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open);
- BinaryReader mapFileReader = new BinaryReader(mapFileStream);
-
- MapInfo mapInfo = new MapInfo();
- mapInfo.Serial = serial;
- bool isClientMapFile = false;
- //地图文件头
- byte[] mapHeader = mapFileReader.ReadBytes( 6);
- if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){
- isClientMapFile = false;
- Debug.Log("[CGTool] 地图文件头: 服务端地图");
- }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){
- isClientMapFile = true;
- Debug.Log("[CGTool] 地图文件头: 客户端地图");
- }
- else
- {
- Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName);
- return null;
- }
- byte[] bytes;
- if (isClientMapFile)
- {
- // 无用信息
- mapFileReader.ReadBytes(6);
- //读取地图宽度
- bytes = mapFileReader.ReadBytes(4);
- mapInfo.Width = BitConverter.ToUInt16(bytes,0);
- //读取地图高度
- bytes = mapFileReader.ReadBytes(4);
- mapInfo.Height = BitConverter.ToUInt16(bytes,0);
- if (MapExtra.ClientMapExtraDatas.ContainsKey(serial))
- {
- mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name;
- mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet;
- }
- else
- {
- mapInfo.Name = "未知领域";
- mapInfo.Palet = -1;
- }
- }
- else
- {
- // 无用信息
- mapFileReader.ReadBytes(2);
- //地图名称
- byte[] mapNameBytes = mapFileReader.ReadBytes(32);
- string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|');
- mapInfo.Name = mapHead[0];
-
- // 调色板
- if (mapHead.Length>1){
- if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]);
- }
-
- //读取地图宽度
- bytes = mapFileReader.ReadBytes(2);
- Array.Reverse(bytes);
- mapInfo.Width = BitConverter.ToUInt16(bytes,0);
- //读取地图高度
- bytes = mapFileReader.ReadBytes(2);
- Array.Reverse(bytes);
- mapInfo.Height = BitConverter.ToUInt16(bytes,0);
- }
-
-
- byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
- byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2));
- mapFileReader.Dispose();
- mapFileReader.Close();
- mapFileStream.Close();
- // print(JsonUtility.ToJson(mapInfo));
-
- BinaryReader mapReader = new BinaryReader(new MemoryStream(mapBytes));
- BinaryReader mapCoverReader = new BinaryReader(new MemoryStream(mapCoverBytes));
- // BinaryReader mapInfoReader = new BinaryReader(new MemoryStream(mapInfoBytes));
- List<MapBlockData> tempGroundTiles = new List<MapBlockData>();
- List<MapBlockData> tempObjectTiles = new List<MapBlockData>();
-
- // CGTool.Logger.Write("开始解析时间:" + DateTime.Now);
- //原始数据为反转数据,即坐标起点为 1,1 排序方向为 y : 1=>0 x: 1=>0
- int len = mapInfo.Width * mapInfo.Height;
- for (int i = 0; i < len; i++)
- {
- //地面数据
- MapBlockData mapTile = null;
- bytes = mapReader.ReadBytes(2);
- if(!isClientMapFile) Array.Reverse(bytes);
- uint mapGraphicSerial = BitConverter.ToUInt16(bytes,0);
- GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial);
- if (graphicInfoData != null)
- {
- mapTile = new MapBlockData();
- mapTile.GraphicInfo = graphicInfoData;
- mapTile.MapSerial = mapGraphicSerial;
- }
- tempGroundTiles.Add(mapTile);
-
- MapBlockData mapCoverTile = null;
- bytes = mapCoverReader.ReadBytes(2);
- if(!isClientMapFile) Array.Reverse(bytes);
-
- uint mapCoverGraphicSerial = BitConverter.ToUInt16(bytes,0);
- graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial);
- if (graphicInfoData != null)
- {
- mapCoverTile = new MapBlockData();
- mapCoverTile.GraphicInfo = graphicInfoData;
- mapCoverTile.MapSerial = mapCoverGraphicSerial;
- }
- tempObjectTiles.Add(mapCoverTile);
- }
- MapBlockData[] GroundTiles = new MapBlockData[len];
- MapBlockData[] ObjectTiles = new MapBlockData[len];
- bool[] blockedIndexs = new bool[len];
- float[] fixPlayerZs = new float[len];
- bool[,] nodes = new bool[mapInfo.Width, mapInfo.Height];
- // CGTool.Logger.Write("开始排序时间:" + DateTime.Now);
- //重新排序
- for (int y = 0; y < mapInfo.Height; y++)
- {
- for (int x = 0; x < mapInfo.Width; x++)
- {
- // int index = i * (int) mapInfo.Width + ((int) mapInfo.Width - j - 1);
- int _tmpindex = x + (mapInfo.Height - y - 1) * mapInfo.Width;
- int index = x + y * mapInfo.Width;
-
- MapBlockData mapTile = tempGroundTiles[_tmpindex];
- MapBlockData ObjectTile = tempObjectTiles[_tmpindex];
- GroundTiles[index] = mapTile;
- ObjectTiles[index] = ObjectTile;
- if (mapTile==null || mapTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
- if (ObjectTile!=null && ObjectTile.GraphicInfo !=null && ObjectTile.GraphicInfo.Blocked) blockedIndexs[index] = true;
-
- nodes[x, y] = !blockedIndexs[index];
-
- //角色默认层级
- // int objectTileZIndex = index * FixZIndex;
- fixPlayerZs[index] = 1;
- }
- }
- //整理Object Z轴层级遮挡及角色遮挡问题
- for (int y = 0; y < mapInfo.Height; y++)
- {
- for (int x = 0; x < mapInfo.Width; x++)
- {
- int index = x + y * mapInfo.Width;
- int objectTileZIndex = index * FixZIndex;
- MapBlockData ObjectTile = ObjectTiles[index];
- if(ObjectTile==null || ObjectTile.GraphicInfo==null) continue;
-
- //Object默认层级
- ObjectTile.ObjectZIndex = objectTileZIndex;
- //角色Z轴补正
- //在自定义排序轴(1,1,-1)情况下,角色Z轴在物件y-1位置,到x+East位置,补正为48*x
- //在物件South+1位置,到x+East位置,补正为-48*x
- if (!ObjectTile.GraphicInfo.AsGround)
- {
- for(int i = x;i<(x+ObjectTile.GraphicInfo.East);i++)
- {
- int fix = 1;
- int oy = y - 1;
- int _index = (int) (oy * mapInfo.Width + i);
- if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - x + 1) * 240f + 0.1f;
- // fix = -1;
- // oy = y + ObjectTile.GraphicInfo.South;
- // _index = (int) (oy * mapInfo.Width + i);
- // if (fixPlayerZs[_index] == 0) fixPlayerZs[_index] = fix * (i - x + 1) * 100;
- }
- for(int i=y+1;i<(y+ObjectTile.GraphicInfo.South);i++)
- {
- int fix = 1;
- int ox = x - 1;
- int _index = (int) (i * mapInfo.Width + ox);
- if (fixPlayerZs[_index] == 1) fixPlayerZs[_index] = fix * (i - y - 1) * 240f + 0.1f;
- }
- }
- else
- {
- // ObjectTile.ObjectZIndex = 0;
- }
- //如果物件占地范围大于1x1,则需要处理行走限制
- if ((ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1) && ObjectTile.GraphicInfo.Blocked)
- {
- //取物件占地中间点位置
- // objectTileZIndex = (x + ObjectTile.GraphicInfo.East / 2 + (y + ObjectTile.GraphicInfo.South / 2) * mapInfo.Width) * FixZIndex;
- // ObjectTile.ObjectZIndex = objectTileZIndex;
- //取物件左上角位置Z轴复写默认Z轴
- // ObjectTile.ObjectZIndex = (x + (y + ObjectTile.GraphicInfo.South) * mapInfo.Width) * FixZIndex;
- for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++)
- {
- for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++)
- {
- if(i>=mapInfo.Width || j>=mapInfo.Height) continue;
- int _index = (int) (j * mapInfo.Width + i);
- blockedIndexs[_index] = true;
- nodes[i, j] = false;
- }
- }
- }
- }
- }
- mapInfo.GroundDatas = GroundTiles.ToList();
- mapInfo.ObjectDatas = ObjectTiles.ToList();
- mapInfo.BlockedIndexs = blockedIndexs;
- mapInfo.MapNodes = nodes;
- mapInfo.FixPlayerZs = fixPlayerZs;
- _cache[serial] = mapInfo;
-
- Debug.Log("[CGTool] 读取地图: " + mapInfo.Name);
- Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height);
- // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
- return mapInfo;
- }
- }
- }
|