diff --git a/XNet.Business/Dto/SyncMsg.cs b/XNet.Business/Dto/SyncMsg.cs index 8c74c10..9a02e1f 100644 --- a/XNet.Business/Dto/SyncMsg.cs +++ b/XNet.Business/Dto/SyncMsg.cs @@ -140,6 +140,19 @@ namespace XNet.Business public string PlayerId { get; set; } = string.Empty; } + + [MessagePackObject] + public class PlayerPosReq + { + [Key("roomId")] + public string RoomId { get; set; } = string.Empty; + [Key("isAI")] + public bool IsAI { get; set; } = false; + [Key("endPos")] + public Vec3? EndPos { get; set; } + } + + [MessagePackObject] public class PlayerInitReq { diff --git a/XNet.Business/Entity/ControlPlayer.cs b/XNet.Business/Entity/ControlPlayer.cs index 70852e8..e7cdd0e 100644 --- a/XNet.Business/Entity/ControlPlayer.cs +++ b/XNet.Business/Entity/ControlPlayer.cs @@ -50,10 +50,5 @@ namespace XNet.Business.Entity /// 当前线性插值欧拉角,角色朝向 /// public Vec3 CurrentEuler { get; set; } = new Vec3(); - - /// - /// 路径导航索引下标 - /// - public int AgentIndex { get; set; } = 0; } } diff --git a/XNet.Business/Entity/PlayerStateInfo.cs b/XNet.Business/Entity/PlayerStateInfo.cs index cbbd00a..adf12dc 100644 --- a/XNet.Business/Entity/PlayerStateInfo.cs +++ b/XNet.Business/Entity/PlayerStateInfo.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using DotRecast.Detour.Crowd; +using System.Collections.Concurrent; using System.Net.WebSockets; namespace XNet.Business.Entity @@ -14,5 +15,12 @@ namespace XNet.Business.Entity public bool IsAI { get; set; } = false; public byte SetIdx { get; set; } + + public bool IsCanControl { get; set; } = false; + + /// + /// 路径导航索引 + /// + public DtCrowdAgent Agent { get; set; } = null!; } } diff --git a/XNet.Business/Global.cs b/XNet.Business/Global.cs new file mode 100644 index 0000000..cf0d3a1 --- /dev/null +++ b/XNet.Business/Global.cs @@ -0,0 +1,10 @@ +namespace XNet.Business +{ + public class Global + { + /// + /// 客户端传上来的位置,角度等为了省流量,存成整形,这里处理成单精度浮点型要除以 LocationMultiply + /// + public const float LocationMultiply = 1000f; + } +} diff --git a/XNet.Business/Net/WsServer.cs b/XNet.Business/Net/WsServer.cs index 68a6f6a..a34915e 100644 --- a/XNet.Business/Net/WsServer.cs +++ b/XNet.Business/Net/WsServer.cs @@ -1,5 +1,6 @@ using MessagePack; using System.Net.WebSockets; +using XNet.Business.PathNavigation; using XNet.Business.Tank.Manager; namespace XNet.Business.Net @@ -8,11 +9,11 @@ namespace XNet.Business.Net { private static ActionManager? ActionManager = null; // 启动WebSocket监听 - public static void MapWebSocketServer(this WebApplication app, WsConnectionManager wsManager) + public static void MapWebSocketServer(this WebApplication app, WsConnectionManager wsManager, NavMeshManager navMeshManager) { if (ActionManager == null) { - ActionManager = new ActionManager(wsManager); + ActionManager = new ActionManager(wsManager, navMeshManager); } app.Map("/ws", async context => { diff --git a/XNet.Business/PathNavigation/NavMeshManager.cs b/XNet.Business/PathNavigation/NavMeshManager.cs index 6e484b0..d30fa73 100644 --- a/XNet.Business/PathNavigation/NavMeshManager.cs +++ b/XNet.Business/PathNavigation/NavMeshManager.cs @@ -149,12 +149,12 @@ namespace XNet.Business.PathNavigation /// 获取指定副本实例底层的 NavMesh 和 Query 对象 /// 注意:返回的对象是共享资源,请勿 Dispose,也请勿修改其拓扑结构 /// - public bool GetNavMeshAndQuery(string instanceId, out DtNavMesh navMesh, out DtNavMeshQuery query) + public bool GetNavMeshAndQuery(string roomId, out DtNavMesh navMesh, out DtNavMeshQuery query) { navMesh = null!; query = null!; - if (!_instanceMap.TryGetValue(instanceId, out var templateId)) return false; + if (!_instanceMap.TryGetValue(roomId, out var templateId)) return false; if (!_templates.TryGetValue(templateId, out var template)) return false; navMesh = template.NavMesh; @@ -162,13 +162,24 @@ namespace XNet.Business.PathNavigation return true; } + public RcVec3f? GetClosetPoint(string roomId, Vector3 originPt) + { + if (!_instanceMap.TryGetValue(roomId, out var templateId)) return null; + if (!_templates.TryGetValue(templateId, out var template)) return null; + var query = template.Query; + var startPos = new RcVec3f(originPt.X, originPt.Y, originPt.Z); + query.FindNearestPoly(startPos, _extents, _filter, out long startRef, out var startPt, out var _); + + return startPt; + } + // ========================================== // 4. 高性能寻路 // ========================================== - public List? FindPath(string instanceId, Vector3 start, Vector3 end) + public List? FindPath(string roomId, Vector3 start, Vector3 end) { - if (!_instanceMap.TryGetValue(instanceId, out var templateId)) return null; + if (!_instanceMap.TryGetValue(roomId, out var templateId)) return null; if (!_templates.TryGetValue(templateId, out var template)) return null; const int MAX_POLYS = 256; diff --git a/XNet.Business/Tank/Manager/ActionManager.cs b/XNet.Business/Tank/Manager/ActionManager.cs index 0eeca8e..669583f 100644 --- a/XNet.Business/Tank/Manager/ActionManager.cs +++ b/XNet.Business/Tank/Manager/ActionManager.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using XNet.Business.Net; +using XNet.Business.PathNavigation; namespace XNet.Business.Tank.Manager { @@ -11,10 +12,12 @@ namespace XNet.Business.Tank.Manager private readonly PlayerManager _playerManager; private readonly WsConnectionManager _wsManager; - public ActionManager(WsConnectionManager wsManager) + private readonly NavMeshManager _navMeshManager; + public ActionManager(WsConnectionManager wsManager, NavMeshManager navMeshManager) { - _playerManager = new PlayerManager(wsManager); + _navMeshManager = navMeshManager; _wsManager = wsManager; + _playerManager = new PlayerManager(wsManager, navMeshManager); Init(); } diff --git a/XNet.Business/Tank/Manager/PlayerManager.cs b/XNet.Business/Tank/Manager/PlayerManager.cs index fafbdf0..eaf8516 100644 --- a/XNet.Business/Tank/Manager/PlayerManager.cs +++ b/XNet.Business/Tank/Manager/PlayerManager.cs @@ -4,15 +4,18 @@ using NanoidDotNet; using System.Numerics; using XNet.Business.Entity; using XNet.Business.Net; +using XNet.Business.PathNavigation; namespace XNet.Business.Tank.Manager { public class PlayerManager { private readonly WsConnectionManager _wsManager; - public PlayerManager(WsConnectionManager wsManager) + private readonly NavMeshManager _navMeshManager; + public PlayerManager(WsConnectionManager wsManager, NavMeshManager navMeshManager) { _wsManager = wsManager; + _navMeshManager = navMeshManager; } public async Task SubcribeRoom(string connId, byte[] data) @@ -239,11 +242,26 @@ namespace XNet.Business.Tank.Manager public async Task RequestPath(string connId, byte[] data) { - //var playerState = _wsManager.GetConnectionInfo(connId); - //if (playerState != null) - //{ - // await _wsManager.SendMessageToRoomBatchAsync(playerState.FirstRoomId, data, [connId]); - //} + var posReq = MessagePackSerializer.Deserialize(data); + if (posReq != null) + { + var playerState = _wsManager.GetConnectionInfo(connId); + //if (playerState != null) + //{ + // await _wsManager.SendMessageToRoomBatchAsync(playerState.FirstRoomId, data, [connId]); + //} + if (playerState != null && playerState.IsCanControl && posReq.EndPos != null) + { + var room = _wsManager.GetPlayerRoomInfo(playerState.FirstRoomId, connId); + + var toPt = new Vector3(posReq.EndPos.X, posReq.EndPos.Y, posReq.EndPos.Z) / Global.LocationMultiply; + var closetPt = _navMeshManager.GetClosetPoint(room?.RoomId!, toPt); + if (closetPt != null) + { + room?.Crowd?.RequestMoveTarget(playerState.Agent, 1, closetPt.Value); + } + } + } await Task.CompletedTask; } } diff --git a/XNet/Program.cs b/XNet/Program.cs index ea12edf..88dd6c7 100644 --- a/XNet/Program.cs +++ b/XNet/Program.cs @@ -46,7 +46,7 @@ app.UseStaticFiles(); app.UseWebSockets(); // WebSocket -app.MapWebSocketServer(app.Services.GetRequiredService()); +app.MapWebSocketServer(app.Services.GetRequiredService(), app.Services.GetRequiredService()); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment())