moved pathing crap out of actor

- despawn actors on moving too far from spawn
- added clampy stuff (<3 devi)
This commit is contained in:
Tahir Akhlaq 2017-06-07 00:46:32 +01:00
parent bd97e72774
commit a62475e81e
12 changed files with 308 additions and 239 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "FFXIVClassic Map Server/navmesh/rcdtcs"]
path = FFXIVClassic Map Server/navmesh/rcdtcs
url = https://github.com/jlalleve/rcdtcs

View File

@ -352,16 +352,31 @@ namespace FFXIVClassic.Common
return (value >> bits) | (value << (16 - bits));
}
public static float Clamp(float val, float min, float max)
public static T Clamp<T>(this T value, T min, T max) where T : IComparable<T>
{
return Math.Max(Math.Min(max, val), min);
if (value.CompareTo(min) < 0)
return min;
else if (value.CompareTo(max) > 0)
return max;
else
return value;
}
public static int Clamp(int val, int min, int max)
public static T Min<T>(this T value, T min) where T : IComparable<T>
{
if (value.CompareTo(min) > 0)
return min;
else
return value;
}
public static T Max<T>(this T value, T max) where T : IComparable<T>
{
return Math.Max(Math.Min(max, val), min);
if (value.CompareTo(max) < 0)
return max;
else
return value;
}
public static float Distance(float x, float y, float z, float x2, float y2, float z2)

View File

@ -69,7 +69,7 @@
</Reference>
<Reference Include="SharpNav, Version=1.0.0.1, Culture=neutral, PublicKeyToken=b467138d8cacd85b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\SharpNav.dll</HintPath>
<HintPath>navmesh\SharpNav.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -137,21 +137,6 @@
<Compile Include="lua\LuaParam.cs" />
<Compile Include="lua\LuaScript.cs" />
<Compile Include="lua\LuaUtils.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourCommon.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourNavMesh.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourNavMeshBuilder.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourNavMeshQuery.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourNode.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Detour\DetourStatus.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\Recast.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastArea.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastContour.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastFilter.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastLayers.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastMesh.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastMeshDetail.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastRasterization.cs" />
<Compile Include="navmesh\rcdtcs\Assets\Rcdtcs\Recast\RecastRegion.cs" />
<Compile Include="PacketProcessor.cs" />
<Compile Include="packets\receive\ChatMessagePacket.cs" />
<Compile Include="packets\receive\events\EventUpdatePacket.cs" />
@ -354,7 +339,9 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="navmesh\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(SolutionDir)data\map_config.ini" "$(SolutionDir)$(ProjectName)\$(OutDir)" /d

View File

@ -47,6 +47,7 @@ namespace FFXIVClassic_Map_Server.Actors
public bool hasMoved = false;
public bool isAtSpawn = true;
public EventList eventConditions;
public Actor(uint actorId)
@ -82,6 +83,15 @@ namespace FFXIVClassic_Map_Server.Actors
}
}
public void ResetMoveSpeedsToDefault()
{
this.moveSpeeds[0] = SetActorSpeedPacket.DEFAULT_STOP;
this.moveSpeeds[1] = SetActorSpeedPacket.DEFAULT_WALK;
this.moveSpeeds[2] = SetActorSpeedPacket.DEFAULT_RUN;
this.moveSpeeds[3] = SetActorSpeedPacket.DEFAULT_ACTIVE;
hasMoved = true;
}
public SubPacket CreateAddActorPacket(uint playerActorId, byte val)
{
return AddActorPacket.BuildPacket(actorId, playerActorId, val);
@ -151,10 +161,6 @@ namespace FFXIVClassic_Map_Server.Actors
positionX = pos.X;
positionY = pos.Y;
positionZ = pos.Z;
if (target != null)
LookAt(target);
//Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates)
}
lastMoveUpdate = DateTime.Now;
@ -358,108 +364,9 @@ namespace FFXIVClassic_Map_Server.Actors
public void Update(double deltaTime)
{
// todo: this is retarded
if (this is Zone || this is Area || this is Player)
return;
var diffTime = (DateTime.Now - lastAiUpdate);
// todo: this too
if (diffTime.Milliseconds >= deltaTime)
if (this is Character)
{
bool foundActor = false;
bool skipFollow = false;
// leash back to spawn
if (this.oldPositionX != 0.0f && this.oldPositionY != 0.0f && this.oldPositionZ != 0.0f)
{
var spawnDistance = Utils.Distance(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ);
if (spawnDistance >= 45)
{
skipFollow = true;
}
}
foreach (var actor in ((Area)zone).GetActorsAroundActor(this, 50))
{
if (actor is Player && actor != this)
{
var player = actor as Player;
if (skipFollow)
{
// todo: despawn self for player
continue;
}
var distance = Utils.Distance(positionX, positionY, positionZ, player.positionX, player.positionY, player.positionZ);
int maxDistance = player == target ? 25 : 15;
if (distance <= maxDistance)
{
foundActor = true;
if (!hasMoved)
{
if (distance >= 3)
{
FollowTarget(player, 2.0f);
}
// too close, spread out
else if (distance <= 0.64f)
{
var minRadius = 0.65f;
var maxRadius = 0.85f;
var angle = Program.Random.NextDouble() * Math.PI * 2;
var radius = Math.Sqrt(Program.Random.NextDouble() * (maxRadius - minRadius)) + minRadius;
float x = (float)(radius * Math.Cos(angle));
float z = (float)(radius * Math.Sin(angle));
positionUpdates.Add(new utils.Vector3(positionX + x, positionY, positionZ + z));
hasMoved = true;
}
if (target != null)
{
LookAt(target);
}
}
}
break;
}
}
var diffMove = (DateTime.Now - lastMoveUpdate);
// 5 seconds before back to spawn
if (diffMove.Seconds >= 5 && !foundActor)
{
// leash to spawn
this.isAtSpawn = Utils.Distance(positionX, positionY, positionZ, oldPositionX, oldPositionY, oldPositionZ) <= 25.0f;
if (this.target == null && skipFollow)
{
// not in spawn range
if (!this.isAtSpawn)
{
PathTo(oldPositionX, oldPositionY, oldPositionZ, 3.0f);
}
// within spawn range, find a random point
else if (diffMove.Seconds >= 15)
{
//Program.Log.Error("Picking random point to walk to! ");
PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.5f, 25, 8.5f);
}
}
this.target = null;
}
lastAiUpdate = DateTime.Now;
((Character)this).Update(deltaTime);
}
}
@ -673,88 +580,6 @@ namespace FFXIVClassic_Map_Server.Actors
rotation = (float)dRot;
}
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 sw = new System.Diagnostics.Stopwatch();
sw.Start();
var path = utils.NavmeshUtils.GetPath(((Zone)GetZone()), pos, dest, stepSize, maxPath, polyRadius);
if (path != null)
{
if (oldPositionX == 0.0f && oldPositionY == 0.0f && oldPositionZ == 0.0f)
{
oldPositionX = positionX;
oldPositionY = positionY;
oldPositionZ = positionZ;
}
// todo: something went wrong
if (path.Count == 0)
{
positionX = oldPositionX;
positionY = oldPositionY;
positionZ = oldPositionZ;
}
positionUpdates = path;
this.hasMoved = true;
this.isAtSpawn = false;
sw.Stop();
((Zone)zone).pathCalls++;
((Zone)zone).pathCallTime += 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)
{
if (target != null)
{
var player = target as Player;
if (this.target != target)
{
#region super important performance critical code
var chatMode = Program.Random.Next(12);
var emphasis = Program.Random.Next(9);
var drag = Program.Random.Next(7);
string oni = "ONI";
string chan = "CHA";
for(var i = 0; i < emphasis; ++i)
oni += "I";
for (var i = 0; i < drag; ++i)
chan += "A";
oni += "-";
chan += "N";
player.SendMessage((uint)chatMode, "Rowena", oni + chan);
#endregion
this.target = target;
}
this.moveState = player.moveState;
this.moveSpeeds = player.moveSpeeds;
PathTo(player.positionX, player.positionY, player.positionZ, stepSize, maxPath);
}
}
public void OnPath()
{
// todo: lua function onPath in mob script
}
}
}

View File

@ -202,6 +202,7 @@ namespace FFXIVClassic_Map_Server.Actors
mActorBlock[gridOldX, gridOldY].Remove(actor);
mActorBlock[gridX, gridY].Add(actor);
}
this.hasMoved = true;
}
public List<Actor> GetActorsAroundPoint(float x, float y, int checkDistance)

View File

@ -22,7 +22,6 @@ namespace FFXIVClassic_Map_Server.actors.area
Dictionary<string, List<PrivateAreaContent>> contentAreas = new Dictionary<string, List<PrivateAreaContent>>();
Object contentAreasLock = new Object();
public Detour.dtNavMesh navMesh;
public SharpNav.TiledNavMesh tiledNavMesh;
public SharpNav.NavMeshQuery navMeshQuery;
public Int64 pathCalls;

View File

@ -1,9 +1,11 @@

using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.Actors.Chara;
using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.utils;
using System;
namespace FFXIVClassic_Map_Server.Actors
{
@ -40,6 +42,8 @@ namespace FFXIVClassic_Map_Server.Actors
public bool isStatic = false;
public bool isMovingToSpawn = false;
public uint modelId;
public uint[] appearanceIds = new uint[28];
@ -111,6 +115,258 @@ namespace FFXIVClassic_Map_Server.Actors
zone.BroadcastPacketAroundActor(this, PlayAnimationOnActorPacket.BuildPacket(actorId, actorId, animId));
}
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 sw = new System.Diagnostics.Stopwatch();
sw.Start();
var path = utils.NavmeshUtils.GetPath(((Zone)GetZone()), pos, dest, stepSize, maxPath, polyRadius);
if (path != null)
{
if (oldPositionX == 0.0f && oldPositionY == 0.0f && oldPositionZ == 0.0f)
{
oldPositionX = positionX;
oldPositionY = positionY;
oldPositionZ = positionZ;
}
// todo: something went wrong
if (path.Count == 0)
{
positionX = oldPositionX;
positionY = oldPositionY;
positionZ = oldPositionZ;
}
positionUpdates = path;
this.hasMoved = true;
this.isAtSpawn = false;
sw.Stop();
((Zone)zone).pathCalls++;
((Zone)zone).pathCallTime += 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)
{
var player = target as Player;
if (player != null)
{
if (this.target != player)
{
#region super important performance critical code
var chatMode = Program.Random.Next(13);
var emphasis = Program.Random.Next(9);
var drag = Program.Random.Next(7);
chatMode = chatMode.Clamp(1, 12);
string oni = "ONI";
string chan = "CHA";
for (var i = 0; i < emphasis; ++i)
oni += "I";
for (var i = 0; i < drag; ++i)
chan += "A";
oni += "-";
chan += "N";
// imouto aggro
player.SendMessage((uint)chatMode, "Rowena", oni + chan);
// sing for onii
this.PlayAnimation(Program.Random.Next(0,2) == 1 ? (uint)67111904 : (uint)67108902);
#endregion
this.target = target;
}
this.moveState = player.moveState;
this.moveSpeeds = player.moveSpeeds;
PathTo(player.positionX, player.positionY, player.positionZ, stepSize, maxPath);
}
}
public void OnPath()
{
// todo: lua function onPath in mob script
}
public void Update(double deltaTime)
{
var diffTime = (DateTime.Now - lastAiUpdate);
if (this is Player)
{
// todo: handle player stuff here
}
else
{
// todo: handle mobs only?
//if (this.isStatic)
// return;
// todo: this too
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);
// despawn if too far from spawn so client can reload me
if (spawnDistance >= 63)
{
despawnOutOfRange = true;
if (target != null)
{
var player = target as Player;
// target zoned, deaggro
target = null;
// tell player to despawn us and we can move back to spawn
if (player != null)
{
// make sure we dont tell player to despawn us twice
targId = player.actorId;
player.QueuePacket(RemoveActorPacket.BuildPacket(player.actorId, actorId));
}
}
this.isMovingToSpawn = true;
this.positionUpdates.Clear();
this.lastMoveUpdate = this.lastMoveUpdate.AddSeconds(-5);
}
// set a leash to path back to spawn even if have target
else if (spawnDistance >= 55)
{
this.isMovingToSpawn = true;
this.target = null;
this.positionUpdates.Clear();
this.lastMoveUpdate = this.lastMoveUpdate.AddSeconds(-5);
}
}
foreach (var actor in zone.GetActorsAroundActor(this, 65))
{
if (actor is Player && actor != this)
{
var player = actor as Player;
// dont despawn again if we already told target to despawn us
if (despawnOutOfRange && player.actorId != targId)
{
player.QueuePacket(RemoveActorPacket.BuildPacket(player.actorId, this.actorId));
continue;
}
// find distance between self and target
var distance = Utils.Distance(positionX, positionY, positionZ, player.positionX, player.positionY, player.positionZ);
int maxDistance = player == target ? 27 : 15;
// check target isnt too far
if (distance <= maxDistance)
{
foundActor = true;
if (!hasMoved)
{
if (distance >= 3)
{
FollowTarget(player, 2.0f);
}
// too close, spread out
else if (distance <= 0.64f)
{
var minRadius = 0.65f;
var maxRadius = 0.85f;
var angle = Program.Random.NextDouble() * Math.PI * 2;
var radius = Math.Sqrt(Program.Random.NextDouble() * (maxRadius - minRadius)) + minRadius;
float x = (float)(radius * Math.Cos(angle));
float z = (float)(radius * Math.Sin(angle));
positionUpdates.Add(new utils.Vector3(positionX + x, positionY, positionZ + z));
hasMoved = true;
}
if (target != null)
{
LookAt(target);
}
}
}
break;
}
}
var diffMove = (DateTime.Now - lastMoveUpdate);
// player disappeared
if (diffMove.Seconds >= 5 && !foundActor)
{
// dont path if havent moved before
if (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;
// make sure we have no target
if (this.target == null)
{
// path back to spawn
if (!this.isAtSpawn)
{
PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.8f);
}
// within spawn range, find a random point
else if (diffMove.Seconds >= 15 && !hasMoved)
{
// this shit gets hit every time, but it wont path to it?
Program.Log.Error("{0} Picking random point to walk to!", actorId);
PathTo(oldPositionX, oldPositionY, oldPositionZ, 2.5f, 15, 20.5f);
// face destination
if (positionUpdates.Count > 0)
{
var destinationPos = positionUpdates[positionUpdates.Count - 1];
LookAt(destinationPos.X, destinationPos.Y);
}
this.isMovingToSpawn = false;
}
// already at spawn, dont recalculate distance on next ai update
else
{
this.isMovingToSpawn = false;
}
}
}
// todo: this is retarded. actually no it isnt, i didnt deaggro if out of range..
target = null;
}
lastAiUpdate = DateTime.Now;
}
}
}
}
}

View File

@ -134,7 +134,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
{
//Don't send for static characters (npcs)
// todo: this is retarded, need actual mob class
if (actor is Character && !actor.hasMoved && ((Character)actor).isStatic)
if (actor is Character && !actor.hasMoved)
continue;
// todo: again, this is retarded but debug stuff

Binary file not shown.

@ -1 +0,0 @@
Subproject commit 8eea27727df5132c5f0e6732d1bd36238ce300ea

View File

@ -94,15 +94,6 @@ namespace FFXIVClassic_Map_Server.utils
return false;
}
public static Detour.dtNavMesh LoadNavmesh(string path)
{
var bytes = File.ReadAllBytes(path);
var start = 0;
var navmesh = Detour.NavMeshSetBuild.FromBytes(bytes, ref start);
return navmesh;
}
public static SharpNav.TiledNavMesh LoadNavmesh(TiledNavMesh navmesh, string filePath)
{
var serialiser = new SharpNav.IO.Json.NavMeshJsonSerializer();
@ -110,14 +101,6 @@ namespace FFXIVClassic_Map_Server.utils
//return navmesh = new SharpNav.IO.Json.NavMeshJsonSerializer().Deserialize(filePath);
}
public static List<Vector3> GetPath(Detour.dtNavMesh navmesh, Vector3 start, Vector3 end)
{
var path = new Vector3[] { };
return path.ToList();
}
#region sharpnav stuff
// Copyright (c) 2013-2016 Robert Rouhani <robert.rouhani@gmail.com> and other contributors (see CONTRIBUTORS file).
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
@ -127,16 +110,19 @@ namespace FFXIVClassic_Map_Server.utils
var navMesh = zone.tiledNavMesh;
var navMeshQuery = zone.navMeshQuery;
if (navMesh == null || (startVec.X == endVec.X && startVec.Y == endVec.Y && startVec.Z == endVec.Z))
if (navMesh == null || (startVec.X == endVec.X && startVec.Y == endVec.Y && startVec.Z == endVec.Z && polyRadius == 0.0f))
{
Program.Log.Error("ass");
return null;
}
float distanceSquared = FFXIVClassic.Common.Utils.DistanceSquared(startVec.X, startVec.Y, startVec.Z, endVec.X, endVec.Y, endVec.Z);
// we dont care about distance if picking random point
float distanceSquared = polyRadius == 0.0f ? FFXIVClassic.Common.Utils.DistanceSquared(startVec.X, startVec.Y, startVec.Z, endVec.X, endVec.Y, endVec.Z) : 100;
// no point pathing if in range
if (distanceSquared < 4 && Math.Abs(startVec.Y - endVec.Y) < 1.1f)
{
Program.Log.Error("shit");
return null;
}
@ -145,8 +131,6 @@ namespace FFXIVClassic_Map_Server.utils
NavQueryFilter filter = new NavQueryFilter();
NavPoint startPt, endPt;
RaycastHit hit;
PathCorridor corridor = new PathCorridor();
try
{
@ -172,6 +156,9 @@ namespace FFXIVClassic_Map_Server.utils
smoothPath.Add(new Vector3(iterPos));
if (npolys <= 1)
System.Diagnostics.Debugger.Break();
//float STEP_SIZE = 0.70f;
float SLOP = 0.15f;
while (npolys > 0 && smoothPath.Count < smoothPath.Capacity)
@ -214,7 +201,7 @@ namespace FFXIVClassic_Map_Server.utils
iterPos = result;
//handle end of path when close enough
if (endOfPath && InRange(iterPos, steerPos, SLOP, 1000.0f))
if (endOfPath && InRange(iterPos, steerPos, SLOP, 10.0f))
{
//reached end of path
iterPos = targetPos;

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFXIVClassic Map Server", "FFXIVClassic Map Server\FFXIVClassic Map Server.csproj", "{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}"
ProjectSection(ProjectDependencies) = postProject
@ -52,4 +52,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal