171 lines
6.7 KiB
C#
171 lines
6.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
// Filename : CMoveMap.cs
|
|
// Creator : ported from C++ (AutoPFImp/AutoMoveImp/MoveMap.*)
|
|
// Date : 2026/01/09
|
|
|
|
namespace AutoMove
|
|
{
|
|
/// <summary>
|
|
/// Pathfinding map container (loads .cfg and its referenced .prmap/.pdhmap/.mlu).
|
|
/// 寻路地图容器(加载 .cfg 及其引用的 .prmap/.pdhmap/.mlu)。
|
|
/// </summary>
|
|
public class CMoveMap
|
|
{
|
|
// C++: PFMAP_CFG_FILE_MAGIC (('c'<<24)|('f'<<16)|('g'<<8)|('f')) => bytes 'f''g''f''c' in LE.
|
|
private const uint PFMAP_CFG_FILE_MAGIC = 0x63666766;
|
|
private const uint PFMAP_CFG_FILE_VERSION = 1;
|
|
|
|
// map origin (world pos of bottom-left corner) // 地图原点(左下角的世界坐标)
|
|
private Vector3 m_vOrigin;
|
|
private readonly List<CLayerMap> m_aLayers = new List<CLayerMap>(2);
|
|
private int m_iMapWidth;
|
|
private int m_iMapLength;
|
|
private float m_fPixelSize = 1.0f;
|
|
|
|
public int GetLayerCount() => m_aLayers.Count;
|
|
public CLayerMap GetLayer(int index) => (index >= 0 && index < m_aLayers.Count) ? m_aLayers[index] : null;
|
|
public int GetMapWidth() => m_iMapWidth;
|
|
public int GetMapLength() => m_iMapLength;
|
|
public float GetPixelSize() => m_fPixelSize;
|
|
|
|
public void SetOrigin(Vector3 vOrigin)
|
|
{
|
|
// C++ only uses x/z.
|
|
// C++ 只使用 x/z。
|
|
m_vOrigin.x = vOrigin.x;
|
|
m_vOrigin.z = vOrigin.z;
|
|
}
|
|
|
|
public void CalcOrigin()
|
|
{
|
|
// C++: use first layer rmap size and pixel size, then set origin to map center.
|
|
// C++:用第一层 rmap 的尺寸与像素大小,然后设置 origin 为地图中心。
|
|
if (m_aLayers.Count == 0) return;
|
|
var rmap = m_aLayers[0].GetRMap();
|
|
if (rmap == null) return;
|
|
rmap.GetImageSize(out m_iMapWidth, out m_iMapLength);
|
|
m_fPixelSize = rmap.GetPixelSize();
|
|
|
|
m_vOrigin = Vector3.zero;
|
|
m_vOrigin.x = -m_iMapWidth * m_fPixelSize * 0.5f;
|
|
m_vOrigin.z = -m_iMapLength * m_fPixelSize * 0.5f;
|
|
}
|
|
|
|
public Vector2 TransMap2Wld(int x, int y)
|
|
{
|
|
float wx = m_vOrigin.x + (x + 0.5f) * m_fPixelSize;
|
|
float wz = m_vOrigin.z + (y + 0.5f) * m_fPixelSize;
|
|
return new Vector2(wx, wz);
|
|
}
|
|
|
|
public Vector2Int TransWld2Map(float wx, float wz)
|
|
{
|
|
int x = Mathf.FloorToInt((wx - m_vOrigin.x) / m_fPixelSize);
|
|
int y = Mathf.FloorToInt((wz - m_vOrigin.z) / m_fPixelSize);
|
|
return new Vector2Int(x, y);
|
|
}
|
|
|
|
public float GetDH(int iLayer, int x, int y)
|
|
{
|
|
var layer = GetLayer(iLayer);
|
|
if (layer == null) return 0.0f;
|
|
return layer.GetDH(x, y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load a movemap from cfg bytes. The resolver must return bytes for referenced files.
|
|
/// 从 cfg 字节加载 movemap。resolver 必须返回引用文件的字节。
|
|
/// </summary>
|
|
public bool Load(byte[] cfgBytes, Func<string, byte[]> resolver, string debugBasePath)
|
|
{
|
|
try
|
|
{
|
|
m_aLayers.Clear();
|
|
|
|
if (cfgBytes == null || cfgBytes.Length < 16) return false;
|
|
int offset = 0;
|
|
|
|
// Some PW client assets have a leading "MOXB" wrapper.
|
|
// 一些完美客户端资源有 "MOXB" 前缀封装。
|
|
if (cfgBytes.Length >= 8 &&
|
|
cfgBytes[0] == (byte)'M' && cfgBytes[1] == (byte)'O' &&
|
|
cfgBytes[2] == (byte)'X' && cfgBytes[3] == (byte)'B')
|
|
{
|
|
offset += 4;
|
|
}
|
|
|
|
uint magic = BitConverter.ToUInt32(cfgBytes, offset); offset += 4;
|
|
if (magic != PFMAP_CFG_FILE_MAGIC)
|
|
{
|
|
Debug.LogWarning($"[CMoveMap] Invalid cfg magic for {debugBasePath} magic=0x{magic:X8}");
|
|
return false;
|
|
}
|
|
|
|
uint ver = BitConverter.ToUInt32(cfgBytes, offset); offset += 4;
|
|
if (ver != PFMAP_CFG_FILE_VERSION)
|
|
{
|
|
Debug.LogWarning($"[CMoveMap] Invalid cfg version for {debugBasePath} ver={ver}");
|
|
return false;
|
|
}
|
|
|
|
int count = BitConverter.ToInt32(cfgBytes, offset); offset += 4;
|
|
if (count <= 0) return false;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
int len = BitConverter.ToInt32(cfgBytes, offset); offset += 4;
|
|
string baseName = System.Text.Encoding.ASCII.GetString(cfgBytes, offset, len);
|
|
offset += len;
|
|
|
|
var layer = new CLayerMap();
|
|
m_aLayers.Add(layer);
|
|
|
|
uint flagR = BitConverter.ToUInt32(cfgBytes, offset); offset += 4;
|
|
if (flagR == 1)
|
|
{
|
|
byte[] prmap = resolver(baseName + ".prmap");
|
|
if (prmap == null || !layer.LoadRMap(prmap)) return false;
|
|
}
|
|
|
|
uint flagDH = BitConverter.ToUInt32(cfgBytes, offset); offset += 4;
|
|
if (flagDH == 1)
|
|
{
|
|
byte[] pdhmap = resolver(baseName + ".pdhmap");
|
|
if (pdhmap == null || !layer.LoadDHMap(pdhmap)) return false;
|
|
}
|
|
|
|
uint flagIsl = BitConverter.ToUInt32(cfgBytes, offset); offset += 4;
|
|
if (flagIsl == 1)
|
|
{
|
|
// island list not ported yet (rarely needed for basic route).
|
|
// island 列表暂未移植(基础寻路通常不依赖)。
|
|
_ = resolver(baseName + ".isl");
|
|
}
|
|
}
|
|
|
|
// mlu name (we load bytes to validate presence, but we don't port MultiCluGraph yet).
|
|
// mlu 名称(我们读取以验证存在,但暂不移植 MultiCluGraph)。
|
|
int mluLen = BitConverter.ToInt32(cfgBytes, offset); offset += 4;
|
|
string mluBase = System.Text.Encoding.ASCII.GetString(cfgBytes, offset, mluLen);
|
|
offset += mluLen;
|
|
_ = resolver(mluBase + ".mlu");
|
|
|
|
// compute dimensions & default origin
|
|
// 计算尺寸与默认 origin
|
|
CalcOrigin();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"[CMoveMap] Load failed for {debugBasePath}: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|