From 4603f3c573304d3c69d09df8b8347739d2375304 Mon Sep 17 00:00:00 2001 From: wuyanchen <307378529@qq.com> Date: Fri, 19 Dec 2025 16:31:28 +0800 Subject: [PATCH] ` --- XNet.Business/MapAgent.cs | 126 +++++++++++++++++++---------- XNet.Business/XNet.Business.csproj | 1 + XNet/Controllers/MapController.cs | 3 +- 3 files changed, 86 insertions(+), 44 deletions(-) diff --git a/XNet.Business/MapAgent.cs b/XNet.Business/MapAgent.cs index 05ae889..ec62551 100644 --- a/XNet.Business/MapAgent.cs +++ b/XNet.Business/MapAgent.cs @@ -1,4 +1,6 @@ -using DotRecast.Detour; +using DotRecast.Core; +using DotRecast.Detour; +using DotRecast.Detour.Io; using System; using System.Collections.Generic; using System.Text; @@ -9,55 +11,93 @@ namespace XNet.Business { public MapAgent() { } - public void Init() + public DtNavMesh LoadFromBabylon(string filePath) { - DtMeshData navData = new DtMeshData(); + byte[] data = File.ReadAllBytes(filePath); + data[3] = 77; // 修正 Magic (TSET -> MSET) + + RcByteBuffer bb = new RcByteBuffer(data); + bb.Order(RcByteOrder.LITTLE_ENDIAN); + + int magic = bb.GetInt(); + int version = bb.GetInt(); + int numTiles = bb.GetInt(); + + DtNavMeshParams option = new DtNavMeshParams(); + option.orig.X = bb.GetFloat(); + option.orig.Y = bb.GetFloat(); + option.orig.Z = bb.GetFloat(); + option.tileWidth = bb.GetFloat(); + option.tileHeight = bb.GetFloat(); + option.maxTiles = bb.GetInt(); + option.maxPolys = bb.GetInt(); + + // --- 关键修正点 1:探测偏移量 --- + // 有些版本的 Babylon 导出的 Params 后面多了一个 int (可能是 maxVertsPerPoly) + // 如果我们发现读出来的 dataSize 大得离谱,就尝试往后挪 4 个字节 + + int savedPos = bb.Position(); + long testTileRef = bb.GetInt(); + int testDataSize = bb.GetInt(); + + // 逻辑判断:如果 dataSize 超过了剩余文件大小,或者是个负数,说明对准错了 + if (testDataSize <= 0 || testDataSize > (data.Length - bb.Position())) + { + Console.WriteLine("检测到字节对齐偏离,尝试跳过 4 字节..."); + bb.Position(savedPos + 4); // 往后挪 4 位再试 + } + else + { + bb.Position(savedPos); // 看起来是对的,退回去正常读 + } + // -------------------------------- + DtNavMesh navMesh = new DtNavMesh(); + navMesh.Init(option, 6); + + DtMeshDataReader tileReader = new DtMeshDataReader(); + + for (int i = 0; i < numTiles; i++) + { + if (bb.Position() + 8 > data.Length) break; + + long tileRef = bb.GetInt(); + int dataSize = bb.GetInt(); + + Console.WriteLine($"Tile[{i}] Ref: {tileRef}, Size: {dataSize}"); + + if (dataSize <= 0 || dataSize > data.Length) + { + Console.WriteLine("警告:dataSize 依然非法,解析中断。"); + break; + } + + byte[] tileData = new byte[dataSize]; + Array.Copy(data, bb.Position(), tileData, 0, dataSize); + bb.Position(bb.Position() + dataSize); + + RcByteBuffer tileBuffer = new RcByteBuffer(tileData); + tileBuffer.Order(RcByteOrder.LITTLE_ENDIAN); + + DtMeshData meshData = tileReader.Read(tileBuffer, 6); + if (meshData != null) + { + navMesh.AddTile(meshData, 0, tileRef, out long result); + } + } + + return navMesh; } - /// - /// 加载Babylon.js RecastJSPlugin生成的NavMesh数据 - /// - /// JS端导出的二进制字节数组 - /// 构建好的DtNavMesh - private static DtNavMesh LoadBabylonNavmesh(byte[] navmeshBytes) + public void SampleUsage(string path) { - try - { - // 初始化NavMesh参数(使用Detour默认参数) - DtNavMeshParams navMeshParams = new DtNavMeshParams - { - orig = new DotRecast.Core.Numerics.RcVec3f(0, 0, 0), // 场景原点(需与JS端烘焙时一致) - tileWidth = 16, // Tile宽度(RecastJSPlugin默认16) - tileHeight = 16, // Tile高度(RecastJSPlugin默认16) - maxTiles = 1024, // 最大Tile数量(根据场景调整) - maxPolys = 65536 // 最大多边形数量(根据场景调整) - }; + DtNavMesh navMesh = LoadFromBabylon(path); - // 创建空的DtNavMesh - DtNavMesh navMesh = new DtNavMesh(); - navMesh.Init(navMeshParams, 6); + // 3. 创建查询对象 + DtNavMeshQuery query = new DtNavMeshQuery(navMesh); - // RecastJSPlugin的getNavmeshData返回的是单个Tile数据(大部分场景) - // 读取Tile数据(Detour Tile格式) - int tileRef = 0; // Tile索引(默认0,多Tile场景需循环解析) - // 添加Tile到NavMesh - - DtMeshData dtMeshData = new DtMeshData(); - - //if (!status.Succeeded()) - //{ - // Console.WriteLine($"添加Tile失败,状态码:{status}"); - // return null; - //} - - return navMesh; - } - catch (Exception ex) - { - Console.WriteLine($"解析NavMesh失败:{ex.Message}"); - return null; - } + // 之后就可以进行寻路了,例如 query.FindPath(...) + Console.WriteLine($"NavMesh loaded. Max Tiles: {navMesh.GetMaxTiles()}"); } } } diff --git a/XNet.Business/XNet.Business.csproj b/XNet.Business/XNet.Business.csproj index d376023..720dfe7 100644 --- a/XNet.Business/XNet.Business.csproj +++ b/XNet.Business/XNet.Business.csproj @@ -9,6 +9,7 @@ + diff --git a/XNet/Controllers/MapController.cs b/XNet/Controllers/MapController.cs index c1adad9..bd00d7a 100644 --- a/XNet/Controllers/MapController.cs +++ b/XNet/Controllers/MapController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using XNet.Business; namespace XNet.Api.Controllers { @@ -10,7 +11,7 @@ namespace XNet.Api.Controllers [HttpGet] public void MapInit() { - + new MapAgent().SampleUsage(@"D:\Rock.nav"); } } }