diff --git a/FFXIVClassic Common Class Lib/FFXIVClassic Common Class Lib.csproj b/FFXIVClassic Common Class Lib/FFXIVClassic Common Class Lib.csproj
index b5c7bcb2..6a3befdb 100644
--- a/FFXIVClassic Common Class Lib/FFXIVClassic Common Class Lib.csproj
+++ b/FFXIVClassic Common Class Lib/FFXIVClassic Common Class Lib.csproj
@@ -70,6 +70,7 @@
+
diff --git a/FFXIVClassic Common Class Lib/Vector3.cs b/FFXIVClassic Common Class Lib/Vector3.cs
new file mode 100644
index 00000000..04bf296c
--- /dev/null
+++ b/FFXIVClassic Common Class Lib/Vector3.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic.Common
+{
+ public class Vector3
+ {
+ public float X;
+ public float Y;
+ public float Z;
+ public static Vector3 Zero = new Vector3();
+
+ public Vector3(float x, float y, float z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ public Vector3()
+ {
+ X = 0.0f;
+ Y = 0.0f;
+ Z = 0.0f;
+ }
+
+ public static Vector3 operator +(Vector3 lhs, Vector3 rhs)
+ {
+ Vector3 newVec = new Vector3(lhs.X, lhs.Y, lhs.Z);
+ newVec.X += rhs.X;
+ newVec.Y += rhs.Y;
+ newVec.Z += rhs.Z;
+ return newVec;
+ }
+
+ public static Vector3 operator -(Vector3 lhs, Vector3 rhs)
+ {
+ return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
+ }
+
+ public static Vector3 operator *(Vector3 lhs, Vector3 rhs)
+ {
+ return new Vector3(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z);
+ }
+
+ public static Vector3 operator *(float scalar, Vector3 rhs)
+ {
+ return new Vector3(scalar * rhs.X, scalar * rhs.Y, scalar * rhs.Z);
+ }
+
+ public static Vector3 operator /(Vector3 lhs, Vector3 rhs)
+ {
+ return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
+ }
+
+ public float Length()
+ {
+ return (float)Math.Sqrt(this.LengthSquared());
+ }
+
+ public float LengthSquared()
+ {
+ return (this.X * this.X) + (this.Y * this.Y) + (this.Z * this.Z);
+ }
+
+ public static float Dot(Vector3 lhs, Vector3 rhs)
+ {
+ return (lhs.X * rhs.X) + (lhs.Y * rhs.Y) + (lhs.Z * rhs.Z);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index 8e3fc9ae..f0b4d371 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -340,6 +340,7 @@
+
diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs
index 4afe2ca2..8e642e82 100644
--- a/FFXIVClassic Map Server/actors/Actor.cs
+++ b/FFXIVClassic Map Server/actors/Actor.cs
@@ -40,7 +40,7 @@ namespace FFXIVClassic_Map_Server.Actors
public string className;
public List classParams;
- public List positionUpdates = new List();
+ public List positionUpdates = new List();
public DateTime lastMoveUpdate;
public Actor target;
@@ -158,12 +158,16 @@ namespace FFXIVClassic_Map_Server.Actors
if (hasMoved)
{
var pos = positionUpdates[0];
- positionUpdates.Remove(pos);
+ if (this is Character)
+ ((Character)this).OnPath(ref pos);
+
positionX = pos.X;
positionY = pos.Y;
positionZ = pos.Z;
//Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates)
+
+ positionUpdates.RemoveAt(0);
}
lastMoveUpdate = DateTime.Now;
return MoveActorToPositionPacket.BuildPacket(actorId, playerActorId, positionX, positionY, positionZ, rotation, moveState);
@@ -609,10 +613,10 @@ namespace FFXIVClassic_Map_Server.Actors
rotation = (float)dRot;
}
- public void QueuePositionUpdate(utils.Vector3 pos)
+ public void QueuePositionUpdate(Vector3 pos)
{
if (positionUpdates == null)
- positionUpdates = new List();
+ positionUpdates = new List();
positionUpdates.Add(pos);
this.hasMoved = true;
@@ -620,7 +624,7 @@ namespace FFXIVClassic_Map_Server.Actors
public void QueuePositionUpdate(float x, float y, float z)
{
- QueuePositionUpdate(new utils.Vector3(x, y, z));
+ QueuePositionUpdate(new Vector3(x, y, z));
}
public void ClearPositionUpdates()
@@ -628,7 +632,7 @@ namespace FFXIVClassic_Map_Server.Actors
positionUpdates.Clear();
}
- public utils.Vector3 FindRandomPointAroundActor(float minRadius, float maxRadius)
+ public Vector3 FindRandomPointAroundActor(float minRadius, float maxRadius)
{
var angle = Program.Random.NextDouble() * Math.PI * 2;
var radius = Math.Sqrt(Program.Random.NextDouble() * (maxRadius - minRadius)) + minRadius;
@@ -636,7 +640,7 @@ namespace FFXIVClassic_Map_Server.Actors
float x = (float)(radius * Math.Cos(angle));
float z = (float)(radius * Math.Sin(angle));
- return new utils.Vector3(positionX + x, positionY, positionZ + z);
+ return new Vector3(positionX + x, positionY, positionZ + z);
}
}
}
diff --git a/FFXIVClassic Map Server/actors/area/Zone.cs b/FFXIVClassic Map Server/actors/area/Zone.cs
index e4aaea3e..cb75cbd2 100644
--- a/FFXIVClassic Map Server/actors/area/Zone.cs
+++ b/FFXIVClassic Map Server/actors/area/Zone.cs
@@ -33,23 +33,20 @@ namespace FFXIVClassic_Map_Server.actors.area
public Zone(uint id, string zoneName, ushort regionId, string classPath, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid, bool loadNavMesh = false)
: base(id, zoneName, regionId, classPath, bgmDay, bgmNight, bgmBattle, isIsolated, isInn, canRideChocobo, canStealth, isInstanceRaid)
{
- var navMeshName = loadNavMesh ? zoneName + ".snb" : "";
-
- if (navMeshName != "")
+ if (loadNavMesh)
{
try
{
- tiledNavMesh = utils.NavmeshUtils.LoadNavmesh(tiledNavMesh, navMeshName);
+ tiledNavMesh = utils.NavmeshUtils.LoadNavmesh(tiledNavMesh, zoneName + ".snb");
navMeshQuery = new SharpNav.NavMeshQuery(tiledNavMesh, 100);
- if (tiledNavMesh != null)
+ if (tiledNavMesh != null && tiledNavMesh.Tiles[0].PolyCount > 0)
Program.Log.Info($"Loaded navmesh for {zoneName}");
}
catch (Exception e)
{
Program.Log.Error(e.Message);
}
-
}
}
diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs
index 0c2c5e1d..0cdf17d6 100644
--- a/FFXIVClassic Map Server/actors/chara/Character.cs
+++ b/FFXIVClassic Map Server/actors/chara/Character.cs
@@ -119,8 +119,8 @@ namespace FFXIVClassic_Map_Server.Actors
public void PathTo(float x, float y, float z, float stepSize = 0.70f, int maxPath = 40, float polyRadius = 0.0f)
{
- var pos = new utils.Vector3(positionX, positionY, positionZ);
- var dest = new utils.Vector3(x, y, z);
+ var pos = new Vector3(positionX, positionY, positionZ);
+ var dest = new Vector3(x, y, z);
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
@@ -156,11 +156,11 @@ namespace FFXIVClassic_Map_Server.Actors
if (path.Count == 1)
Program.Log.Info($"mypos: {positionX} {positionY} {positionZ} | targetPos: {x} {y} {z} | step {stepSize} | maxPath {maxPath} | polyRadius {polyRadius}");
- //Program.Log.Error("[{0}][{1}] Created {2} points in {3} milliseconds", actorId, actorName, path.Count, sw.ElapsedMilliseconds);
+ Program.Log.Error("[{0}][{1}] Created {2} points in {3} milliseconds", actorId, actorName, path.Count, sw.ElapsedMilliseconds);
}
}
- public void FollowTarget(Actor target, float stepSize = 1.2f, int maxPath = 25)
+ public void FollowTarget(Actor target, float stepSize = 1.2f, int maxPath = 25, float radius = 0.0f)
{
var player = target as Player;
@@ -202,13 +202,20 @@ namespace FFXIVClassic_Map_Server.Actors
this.moveState = player.moveState;
this.moveSpeeds = player.moveSpeeds;
- PathTo(player.positionX, player.positionY, player.positionZ, stepSize, maxPath);
+ PathTo(player.positionX, player.positionY, player.positionZ, stepSize, maxPath, radius);
}
}
- public void OnPath()
+ public void OnPath(ref Vector3 point)
{
- // todo: lua function onPath in mob script
+ if (positionUpdates != null && positionUpdates.Count > 0)
+ {
+ if (point == positionUpdates[positionUpdates.Count - 1])
+ {
+ var myPos = new Vector3(positionX, positionY, positionZ);
+ //point = NavmeshUtils.GetPath((Zone)zone, myPos, point, 0.35f, 1, 0.000001f, true)?[0];
+ }
+ }
}
public void Update(double deltaTime)
@@ -234,22 +241,21 @@ namespace FFXIVClassic_Map_Server.Actors
if (diffTime.Milliseconds >= deltaTime)
{
bool foundActor = false;
- bool despawnOutOfRange = false;
-
- var targId = target != null ? actorId : 0;
// leash back to spawn
if (!isMovingToSpawn && this.oldPositionX != 0.0f && this.oldPositionY != 0.0f && this.oldPositionZ != 0.0f)
{
- var spawnDistance = Utils.Distance(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ);
+ //var spawnDistanceSq = Utils.DistanceSquared(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ);
// todo: actual spawn leash and modifiers read from table
// set a leash to path back to spawn even if have target
- if (spawnDistance >= 55)
+ // (50 yalms)
+ if (Utils.DistanceSquared(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ) >= 3025)
{
this.isMovingToSpawn = true;
this.target = null;
this.lastMoveUpdate = this.lastMoveUpdate.AddSeconds(-5);
+ this.hasMoved = false;
ClearPositionUpdates();
}
}
@@ -260,7 +266,8 @@ namespace FFXIVClassic_Map_Server.Actors
var player = target as Player;
// deaggro if zoning/logging
- if (player.playerSession.isUpdatesLocked || player.isZoneChanging || player.isZoning)
+ // todo: player.isZoning seems to be busted
+ if (player.playerSession.isUpdatesLocked)
{
target = null;
ClearPositionUpdates();
@@ -268,7 +275,7 @@ namespace FFXIVClassic_Map_Server.Actors
}
Player closestPlayer = null;
- float closestPlayerDistance = 1000.0f;
+ float closestPlayerDistanceSq = 1000.0f;
// dont bother checking for any in-range players if going back to spawn
if (!this.isMovingToSpawn)
@@ -280,19 +287,20 @@ namespace FFXIVClassic_Map_Server.Actors
var player = actor as Player;
// skip if zoning/logging
- if (player != null && player.isZoning || player.isZoning || player.playerSession.isUpdatesLocked)
+ // todo: player.isZoning seems to be busted
+ if (player != null && player.playerSession.isUpdatesLocked)
continue;
// find distance between self and target
- var distance = Utils.Distance(positionX, positionY, positionZ, player.positionX, player.positionY, player.positionZ);
+ var distanceSq = Utils.DistanceSquared(positionX, positionY, positionZ, player.positionX, player.positionY, player.positionZ);
- int maxDistance = player == target ? 27 : 10;
+ int maxDistanceSq = player == target ? 900 : 100;
// check target isnt too far
// todo: create cone thing for IsFacing
- if (distance <= maxDistance && distance <= closestPlayerDistance && (IsFacing(player) || true))
+ if (distanceSq <= maxDistanceSq && distanceSq <= closestPlayerDistanceSq && (IsFacing(player) || true))
{
- closestPlayerDistance = distance;
+ closestPlayerDistanceSq = distanceSq;
closestPlayer = player;
foundActor = true;
}
@@ -306,12 +314,12 @@ namespace FFXIVClassic_Map_Server.Actors
if (!hasMoved)
{
// todo: include model size and mob specific distance checks
- if (closestPlayerDistance >= 3)
+ if (closestPlayerDistanceSq >= 9)
{
- FollowTarget(closestPlayer, 2.4f, 5);
+ FollowTarget(closestPlayer, 2.5f, 4);
}
// too close, spread out
- else if (closestPlayerDistance <= 0.64f)
+ else if (closestPlayerDistanceSq <= 0.85f)
{
QueuePositionUpdate(target.FindRandomPointAroundActor(0.65f, 0.85f));
}
@@ -328,14 +336,15 @@ namespace FFXIVClassic_Map_Server.Actors
// time elapsed since last move update
var diffMove = (DateTime.Now - lastMoveUpdate);
+ // todo: modifier for DelayBeforeRoamToSpawn
// player disappeared
- if (diffMove.Seconds >= 5 && !foundActor)
+ if (!foundActor && diffMove.Seconds >= 5)
{
// dont path if havent moved before
- if (oldPositionX != 0.0f && oldPositionY != 0.0f && oldPositionZ != 0.0f)
+ if (!hasMoved && oldPositionX != 0.0f && oldPositionY != 0.0f && oldPositionZ != 0.0f)
{
// check within spawn radius
- this.isAtSpawn = Utils.Distance(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ) <= 25.0f;
+ this.isAtSpawn = Utils.DistanceSquared(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ) <= 625.0f;
// make sure we have no target
if (this.target == null)
@@ -346,10 +355,11 @@ namespace FFXIVClassic_Map_Server.Actors
PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.8f);
}
// within spawn range, find a random point
- else if (diffMove.Seconds >= 15 && !hasMoved)
+ else if (diffMove.Seconds >= 15)
{
- // pick a random point within 10 yalms or spawn
- PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.5f, 7, 10.5f);
+ // todo: polyRadius isnt euclidean distance..
+ // pick a random point within 10 yalms of spawn
+ PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.5f, 7, 2.5f);
// face destination
if (positionUpdates.Count > 0)
diff --git a/FFXIVClassic Map Server/navmesh/SharpNav.dll b/FFXIVClassic Map Server/navmesh/SharpNav.dll
index e53d6c97..be560e8f 100644
Binary files a/FFXIVClassic Map Server/navmesh/SharpNav.dll and b/FFXIVClassic Map Server/navmesh/SharpNav.dll differ
diff --git a/FFXIVClassic Map Server/navmesh/wil0Field01.snb b/FFXIVClassic Map Server/navmesh/wil0Field01.snb
index 2b42f353..e8a49ee9 100644
Binary files a/FFXIVClassic Map Server/navmesh/wil0Field01.snb and b/FFXIVClassic Map Server/navmesh/wil0Field01.snb differ
diff --git a/FFXIVClassic Map Server/utils/NavmeshUtils.cs b/FFXIVClassic Map Server/utils/NavmeshUtils.cs
index ae1f9907..54c6e433 100644
--- a/FFXIVClassic Map Server/utils/NavmeshUtils.cs
+++ b/FFXIVClassic Map Server/utils/NavmeshUtils.cs
@@ -8,82 +8,10 @@ using SharpNav;
using SharpNav.Pathfinding;
using SharpNav.Crowds;
using SharpNav.IO;
+using FFXIVClassic.Common;
namespace FFXIVClassic_Map_Server.utils
{
- public class Vector3
- {
- public float X;
- public float Y;
- public float Z;
- public static Vector3 Zero = new Vector3();
-
- public Vector3(float x, float y, float z)
- {
- X = x;
- Y = y;
- Z = z;
- }
-
- public Vector3()
- {
- X = 0.0f;
- Y = 0.0f;
- Z = 0.0f;
- }
-
- public Vector3(SharpNav.Geometry.Vector3 vec)
- {
- X = vec.X;
- Y = vec.Y;
- Z = vec.Z;
- }
-
- public static Vector3 operator +(Vector3 lhs, Vector3 rhs)
- {
- Vector3 newVec = new Vector3(lhs.X, lhs.Y, lhs.Z);
- newVec.X += rhs.X;
- newVec.Y += rhs.Y;
- newVec.Z += rhs.Z;
- return newVec;
- }
-
- public static Vector3 operator -(Vector3 lhs, Vector3 rhs)
- {
- return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
- }
-
- public static Vector3 operator *(Vector3 lhs, Vector3 rhs)
- {
- return new Vector3(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z);
- }
-
- public static Vector3 operator *(float scalar, Vector3 rhs)
- {
- return new Vector3(scalar * rhs.X, scalar * rhs.Y, scalar * rhs.Z);
- }
-
- public static Vector3 operator /(Vector3 lhs, Vector3 rhs)
- {
- return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
- }
-
- public float Length()
- {
- return (float)Math.Sqrt(this.LengthSquared());
- }
-
- public float LengthSquared()
- {
- return (this.X * this.X) + (this.Y * this.Y) + (this.Z * this.Z);
- }
-
- public static float Dot(Vector3 lhs, Vector3 rhs)
- {
- return (lhs.X * rhs.X) + (lhs.Y * rhs.Y) + (lhs.Z * rhs.Z);
- }
- }
-
class NavmeshUtils
{
@@ -96,8 +24,13 @@ namespace FFXIVClassic_Map_Server.utils
public static SharpNav.TiledNavMesh LoadNavmesh(TiledNavMesh navmesh, string filePath)
{
- var serialiser = new SharpNav.IO.Json.NavMeshJsonSerializer();
- return serialiser.Deserialize(System.IO.Path.Combine("../../navmesh/", filePath));
+ SharpNav.IO.NavMeshSerializer serializer;
+ if (System.IO.Path.GetExtension(filePath) == ".snb")
+ serializer = new SharpNav.IO.Binary.NavMeshBinarySerializer();
+ else
+ serializer = new SharpNav.IO.Json.NavMeshJsonSerializer();
+
+ return serializer.Deserialize(System.IO.Path.Combine("../../navmesh/", filePath));
//return navmesh = new SharpNav.IO.Json.NavMeshJsonSerializer().Deserialize(filePath);
}
@@ -105,11 +38,11 @@ namespace FFXIVClassic_Map_Server.utils
// Copyright (c) 2013-2016 Robert Rouhani and other contributors (see CONTRIBUTORS file).
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
- public static List GetPath(FFXIVClassic_Map_Server.actors.area.Zone zone, Vector3 startVec, Vector3 endVec, float stepSize = 0.70f, int pathSize = 45, float polyRadius = 0.0f)
+ public static List GetPath(FFXIVClassic_Map_Server.actors.area.Zone zone, Vector3 startVec, Vector3 endVec, float stepSize = 0.70f, int pathSize = 45, float polyRadius = 0.0f, bool skipToTarget = false)
{
var navMesh = zone.tiledNavMesh;
var navMeshQuery = zone.navMeshQuery;
-
+
// no navmesh loaded, run straight to player
if (navMesh == null)
{
@@ -166,7 +99,11 @@ namespace FFXIVClassic_Map_Server.utils
targetPos = randPoly.Position;
}
- smoothPath.Add(new Vector3(iterPos));
+ if (skipToTarget)
+ {
+ return new List() { new Vector3(targetPos.X, targetPos.Y, targetPos.Z) };
+ }
+ smoothPath.Add(new Vector3(iterPos.X, iterPos.Y, iterPos.Z));
//float STEP_SIZE = 0.70f;
float SLOP = 0.15f;
@@ -216,7 +153,7 @@ namespace FFXIVClassic_Map_Server.utils
iterPos = targetPos;
if (smoothPath.Count < smoothPath.Capacity)
{
- smoothPath.Add(new Vector3(iterPos));
+ smoothPath.Add(new Vector3(iterPos.X, iterPos.Y, iterPos.Z));
}
break;
}
@@ -224,7 +161,7 @@ namespace FFXIVClassic_Map_Server.utils
//store results
if (smoothPath.Count < smoothPath.Capacity)
{
- smoothPath.Add(new Vector3(iterPos));
+ smoothPath.Add(new Vector3(iterPos.X, iterPos.Y, iterPos.Z));
}
}
}