From 1856cc0634423df338245a681e185e78ae0e87f4 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Wed, 16 Aug 2017 17:25:32 +0100 Subject: [PATCH] (badly) ported dsp's pathfind code - added distance for vectors - todo: why does it go retard --- FFXIVClassic Common Class Lib/Utils.cs | 10 +++ FFXIVClassic Map Server/actors/Actor.cs | 5 ++ .../actors/chara/ai/PathFind.cs | 62 ++++++++++++++++--- .../ai/controllers/BattleNpcController.cs | 17 +++-- .../chara/ai/controllers/PlayerController.cs | 4 +- .../actors/chara/ai/state/AttackState.cs | 7 ++- .../dataobjects/Session.cs | 4 +- .../Actor/battle/BattleActionX01Packet.cs | 2 +- FFXIVClassic Map Server/utils/NavmeshUtils.cs | 16 ++--- 9 files changed, 98 insertions(+), 29 deletions(-) diff --git a/FFXIVClassic Common Class Lib/Utils.cs b/FFXIVClassic Common Class Lib/Utils.cs index 18e46adb..a4b06fa9 100644 --- a/FFXIVClassic Common Class Lib/Utils.cs +++ b/FFXIVClassic Common Class Lib/Utils.cs @@ -379,6 +379,16 @@ namespace FFXIVClassic.Common return value; } + public static float DistanceSquared(Vector3 lhs, Vector3 rhs) + { + return DistanceSquared(lhs.X, lhs.Y, lhs.Z, rhs.X, rhs.Y, rhs.Z); + } + + public static float Distance(Vector3 lhs, Vector3 rhs) + { + return Distance(lhs.X, lhs.Y, lhs.Z, rhs.X, rhs.Y, rhs.Z); + } + public static float Distance(float x, float y, float z, float x2, float y2, float z2) { if (x == x2 && y == y2 && z == z2) diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 53b5be94..6236618c 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -404,9 +404,14 @@ namespace FFXIVClassic_Map_Server.Actors // push latest for player var pos = positionUpdates?[currentSubState == SetActorStatePacket.SUB_STATE_PLAYER ? positionUpdates.Count - 1 : 0]; + oldPositionX = positionX; + oldPositionY = positionY; + oldPositionZ = positionZ; + positionX = pos.X; positionY = pos.Y; positionZ = pos.Z; + //Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates) positionUpdates.RemoveAt(0); diff --git a/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs b/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs index baa6616a..f871ded8 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs @@ -10,6 +10,8 @@ using FFXIVClassic.Common; using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.packets.send.actor; +// port of https://github.com/DarkstarProject/darkstar/blob/master/src/map/ai/helpers/pathfind.h + namespace FFXIVClassic_Map_Server.actors.chara.ai { // todo: path flags, check for obstacles etc @@ -24,6 +26,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai private Character owner; private List path; private bool canFollowPath; + float distanceFromPoint; private PathFindFlags pathFlags; @@ -87,6 +90,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai public void PathInRange(float x, float y, float z, float minRange, float maxRange = 5.0f) { var dest = owner.FindRandomPoint(x, y, z, minRange, maxRange); + // todo: this is dumb.. + distanceFromPoint = owner.meleeRange; PreparePath(dest.X, dest.Y, dest.Z); } @@ -98,7 +103,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai public bool IsFollowingPath() { - return path.Count > 0; + return path?.Count > 0; } public bool IsFollowingScriptedPath() @@ -112,12 +117,53 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { var point = path[0]; - owner.OnPath(point); - owner.QueuePositionUpdate(point); - path.Remove(point); + StepTo(point); - if (path.Count == 0) - owner.LookAt(point.X, point.Y); + if (AtPoint(point)) + { + path.Remove(point); + owner.OnPath(point); + } + } + } + + public bool AtPoint(Vector3 point) + { + if (distanceFromPoint == 0) + return owner.positionX == point.X && owner.positionZ == point.Z; + else + return Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, point.X, point.Y, point.Z) <= (distanceFromPoint + 1.5f); + } + + public void StepTo(Vector3 point, bool run = false) + { + float speed = GetSpeed(); + + float stepDistance = (speed / 10) / 2; + float distanceTo = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, point.X, point.Y, point.Z); + + owner.LookAt(point.X, point.Y); + + if (distanceTo <= distanceFromPoint + stepDistance + 1.5f) + { + if (distanceFromPoint == 0) + { + owner.QueuePositionUpdate(point); + } + else + { + float x = owner.positionX - (float)Math.Cos(owner.rotation + (float)(Math.PI / 2)) * (distanceTo - distanceFromPoint); + float z = owner.positionZ + (float)Math.Sin(owner.rotation + (float)(Math.PI / 2)) * (distanceTo - distanceFromPoint); + + owner.QueuePositionUpdate(x, owner.positionY, z); + } + } + else + { + float x = owner.positionX - (float)Math.Cos(owner.rotation + (float)(Math.PI / 2)) * (distanceTo - distanceFromPoint); + float z = owner.positionZ + (float)Math.Sin(owner.rotation + (float)(Math.PI / 2)) * (distanceTo - distanceFromPoint); + + owner.QueuePositionUpdate(x, owner.positionY, z); } } @@ -126,6 +172,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai // todo: path?.Clear(); pathFlags = PathFindFlags.None; + distanceFromPoint = 0.0f; + } private float GetSpeed() @@ -137,7 +185,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER) { - owner.ChangeSpeed(0.0f, SetActorSpeedPacket.DEFAULT_WALK - 2.0f, SetActorSpeedPacket.DEFAULT_RUN - 2.0f, SetActorSpeedPacket.DEFAULT_ACTIVE - 2.0f); + //owner.ChangeSpeed(0.0f, SetActorSpeedPacket.DEFAULT_WALK - 2.0f, SetActorSpeedPacket.DEFAULT_RUN - 2.0f, SetActorSpeedPacket.DEFAULT_ACTIVE - 2.0f); } // baseSpeed += ConfigConstants.SPEED_MOD; } diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs index 759ab393..79a2e8cf 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs @@ -82,7 +82,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > 10) { owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None); - owner.aiContainer.pathFind.PreparePath(target.positionX, target.positionY, target.positionZ); + owner.aiContainer.pathFind.PathInRange(target.positionX, target.positionY, target.positionZ, 1.5f, owner.meleeRange); ChangeTarget(target); return false; } @@ -193,18 +193,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers return; } - var targetPos = owner.target.GetPosAsVector3(); + var targetPos = new Vector3(owner.target.positionX, owner.target.positionY, owner.target.positionZ); var distance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, targetPos.X, targetPos.Y, targetPos.Z); if (distance > owner.meleeRange - 0.2f || owner.aiContainer.CanFollowPath()) { if (CanMoveForward(distance)) { + owner.LookAt(targetPos.X, targetPos.Y); if (!owner.aiContainer.pathFind.IsFollowingPath() && distance > 3) { // pathfind if too far otherwise jump to target - owner.aiContainer.pathFind.SetPathFlags(distance > 3 ? PathFindFlags.None : PathFindFlags.IgnoreNav ); - owner.aiContainer.pathFind.PreparePath(targetPos, 0.7f, 5); + owner.aiContainer.pathFind.SetPathFlags(distance > 5 ? PathFindFlags.None : PathFindFlags.IgnoreNav ); + owner.aiContainer.pathFind.PreparePath(targetPos, 0.5f, 5); } owner.aiContainer.pathFind.FollowPath(); if (!owner.aiContainer.pathFind.IsFollowingPath()) @@ -213,7 +214,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers { foreach (var battlenpc in owner.zone.GetActorsAroundActor(owner, 1)) { - battlenpc.aiContainer.pathFind.PathInRange(targetPos, 1.5f, 1.5f); + if (battlenpc == owner) + continue; + float mobDistance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, battlenpc.positionX, battlenpc.positionY, battlenpc.positionZ); + if (mobDistance < 0.3f && (battlenpc.updateFlags & ActorUpdateFlags.Position) == 0) + battlenpc.aiContainer.pathFind.PathInRange(targetPos, 1.5f, 1.5f); } } } @@ -277,7 +282,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers if (verticalDistance > 8) return false; - var distance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ); + var distance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.oldPositionX, target.oldPositionY, target.oldPositionZ); bool detectSight = forceSight || (owner.aggroType & AggroType.Sight) != 0; bool hasSneak = false; diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs index 9059f63c..8ac1a63f 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs @@ -43,7 +43,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers // todo: actual stat based range if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > 10) { - owner.aiContainer.pathFind.PreparePath(target.positionX, target.positionY, target.positionZ); + { + // todo: out of range error + } ChangeTarget(target); return false; } diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs index ce62aeca..864153f6 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs @@ -87,12 +87,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state lua.LuaEngine.CallLuaBattleAction(owner, "onAttack", false, owner, target, damage); foreach (var player in owner.zone.GetActorsAroundActor(owner, 50)) - player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target.actorId, 223001, 18, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0)); - if (target is Player) - ((Player)target).SendPacket("139.bin"); + player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target.actorId, 0, 537094006, 0, 27260, (ushort)damage, 0)); + //if (target is Player) + // ((Player)target).SendPacket("139.bin"); target.AddHP((short)damage); attackTime = attackTime.AddMilliseconds(owner.GetAttackDelayMs()); + owner.LookAt(target); //this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0); } diff --git a/FFXIVClassic Map Server/dataobjects/Session.cs b/FFXIVClassic Map Server/dataobjects/Session.cs index 73732a3e..1083951e 100644 --- a/FFXIVClassic Map Server/dataobjects/Session.cs +++ b/FFXIVClassic Map Server/dataobjects/Session.cs @@ -72,14 +72,16 @@ namespace FFXIVClassic_Map_Server.dataobjects if (playerActor.positionX == x && playerActor.positionY == y && playerActor.positionZ == z && playerActor.rotation == rot) return; + /* playerActor.oldPositionX = playerActor.positionX; playerActor.oldPositionY = playerActor.positionY; playerActor.oldPositionZ = playerActor.positionZ; playerActor.oldRotation = playerActor.rotation; - + playerActor.positionX = x; playerActor.positionY = y; playerActor.positionZ = z; + */ playerActor.rotation = rot; playerActor.moveState = moveState; diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs index cf57769b..11c2530e 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs @@ -31,7 +31,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle binWriter.Seek(0x20, SeekOrigin.Begin); binWriter.Write((UInt32)1); //Num actions (always 1 for this) binWriter.Write((UInt16)commandId); - binWriter.Write((UInt16)810); //? + binWriter.Write((UInt16)0x810); //? binWriter.Write((UInt32)targetActorId); diff --git a/FFXIVClassic Map Server/utils/NavmeshUtils.cs b/FFXIVClassic Map Server/utils/NavmeshUtils.cs index 0ee151fe..8145d0cb 100644 --- a/FFXIVClassic Map Server/utils/NavmeshUtils.cs +++ b/FFXIVClassic Map Server/utils/NavmeshUtils.cs @@ -58,11 +58,16 @@ namespace FFXIVClassic_Map_Server.utils //return navmesh = new SharpNav.IO.Json.NavMeshJsonSerializer().Deserialize(filePath); } + public static List GetPath(actors.area.Zone zone, float x, float y, float z, float targetX, float targetY, float targetZ, float stepSize = 0.70f, int pathSize = 45, float polyRadius = 0.0f, bool skipToTarget = false) + { + return GetPath(zone, new Vector3(x, y, z), new Vector3(targetX, targetY, targetZ), stepSize, pathSize, polyRadius, skipToTarget); + } + #region sharpnav stuff // 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, bool skipToTarget = false) + public static List GetPath(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; @@ -79,15 +84,6 @@ namespace FFXIVClassic_Map_Server.utils return null; } - // 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) - { - return new List() { endVec }; - } - var smoothPath = new List(pathSize) { }; NavQueryFilter filter = new NavQueryFilter();