From 22dc5e4b65a56f1857bd7f5b4d8f8e53a8f04320 Mon Sep 17 00:00:00 2001 From: Killfrra Date: Sat, 26 Mar 2022 02:33:13 +0300 Subject: [PATCH] Progress #1366 -- Various TeleportID-related fixes (#1367) I wrote "progress" because I still have to use teleportation for collisions. Otherwise, collision avoidance comes into play and the minions go in different directions. They are already trying to do this, but in the *indev* branch they are teleported away every tick of the server. This also looks ugly, but I decided to keep this behavior. At least now, instead of recalculating the entire path, a collision only changes the zero point of the path. And this is usually enough, because the collision only throws the unit back a little. --- .../Packets/Interfaces/IPacketNotifier.cs | 5 +- .../Chatbox/Commands/SpawnCommand.cs | 2 +- .../AttackableUnits/AttackableUnit.cs | 61 ++++++++++---- GameServerLib/GameObjects/GameObject.cs | 10 +-- GameServerLib/ObjectManager.cs | 2 +- PacketDefinitions420/PacketExtensions.cs | 83 +++++-------------- PacketDefinitions420/PacketNotifier.cs | 20 ++--- 7 files changed, 80 insertions(+), 103 deletions(-) diff --git a/GameServerCore/Packets/Interfaces/IPacketNotifier.cs b/GameServerCore/Packets/Interfaces/IPacketNotifier.cs index 5c46a4b9b..0ca484984 100644 --- a/GameServerCore/Packets/Interfaces/IPacketNotifier.cs +++ b/GameServerCore/Packets/Interfaces/IPacketNotifier.cs @@ -195,11 +195,10 @@ public interface IPacketNotifier /// GameObject entering vision. /// User to send the packet to. /// Whether or not the GameObject entering vision is a Champion. - /// Whether or not to teleport the object to its current position. /// Optionally ignore vision checks when sending this packet. /// Takes in a list of packets to send alongside this vision packet. /// TODO: Incomplete implementation. - void NotifyEnterVisibilityClient(IGameObject o, int userId = 0, bool isChampion = false, bool useTeleportID = false, bool ignoreVision = false, List packets = null); + void NotifyEnterVisibilityClient(IGameObject o, int userId = 0, bool isChampion = false, bool ignoreVision = false, List packets = null); /// /// Sends a packet to all players with vision of the specified unit detailing that the unit has begun facing the specified direction. /// @@ -938,7 +937,7 @@ public interface IPacketNotifier /// AttackableUnit that is moving. /// UserId to send the packet to. If not specified or zero, the packet is broadcasted to all players that have vision of the specified unit. /// Whether or not to teleport the unit to its current position in its path. - void NotifyWaypointGroup(IAttackableUnit u, int userId = 0, bool useTeleportID = true); + void NotifyWaypointGroup(IAttackableUnit u, int userId = 0, bool useTeleportID = false); /// /// Sends a packet to all players that have vision of the specified unit. /// The packet details a group of waypoints with speed parameters which determine what kind of movement will be done to reach the waypoints, or optionally a GameObject. diff --git a/GameServerLib/Chatbox/Commands/SpawnCommand.cs b/GameServerLib/Chatbox/Commands/SpawnCommand.cs index 5cade4389..914eddb5d 100644 --- a/GameServerLib/Chatbox/Commands/SpawnCommand.cs +++ b/GameServerLib/Chatbox/Commands/SpawnCommand.cs @@ -178,7 +178,7 @@ public void SpawnChampForTeam(TeamId team, int userId, string model) c.Stats.SetSummonerSpellEnabled(0, true); c.Stats.SetSummonerSpellEnabled(1, true); - Game.PacketNotifier.NotifyEnterVisibilityClient(c, 0, true, false, true); + Game.PacketNotifier.NotifyEnterVisibilityClient(c, 0, true, true); ChatCommandManager.SendDebugMsgFormatted(DebugMsgType.INFO, "Spawned Bot" + clientInfoTemp.Name + " as " + c.Model + " with NetID: " + c.NetId + "."); } diff --git a/GameServerLib/GameObjects/AttackableUnits/AttackableUnit.cs b/GameServerLib/GameObjects/AttackableUnits/AttackableUnit.cs index 90e3e8214..2fe65c0a1 100644 --- a/GameServerLib/GameObjects/AttackableUnits/AttackableUnit.cs +++ b/GameServerLib/GameObjects/AttackableUnits/AttackableUnit.cs @@ -176,21 +176,29 @@ public uint GetObjHash() public void SetPosition(Vector2 vec, bool repath = true) { Position = vec; + _movementUpdated = true; - // Reevaluate our current path to account for the starting position being changed. - if (repath && !IsPathEnded()) + if(!IsPathEnded()) { - List safePath = _game.Map.PathingHandler.GetPath(Position, _game.Map.NavigationGrid.GetClosestTerrainExit(Waypoints.Last(), PathfindingRadius)); + // Reevaluate our current path to account for the starting position being changed. + if(repath) + { + List safePath = _game.Map.PathingHandler.GetPath(Position, _game.Map.NavigationGrid.GetClosestTerrainExit(Waypoints.Last(), PathfindingRadius)); - // TODO: When using this safePath, sometimes we collide with the terrain again, so we use an unsafe path the next collision, however, - // sometimes we collide again before we can finish the unsafe path, so we end up looping collisions between safe and unsafe paths, never actually escaping (ex: sharp corners). - // This is a more fundamental issue where the pathfinding should be taking into account collision radius, rather than simply pathing from center of an object. - if (safePath != null) + // TODO: When using this safePath, sometimes we collide with the terrain again, so we use an unsafe path the next collision, however, + // sometimes we collide again before we can finish the unsafe path, so we end up looping collisions between safe and unsafe paths, never actually escaping (ex: sharp corners). + // This is a more fundamental issue where the pathfinding should be taking into account collision radius, rather than simply pathing from center of an object. + if (safePath != null) + { + SetWaypoints(safePath); + } + } + else { - SetWaypoints(safePath); + Waypoints[0] = Position; } } - else if (!repath && !IsPathEnded()) + else { ResetWaypoints(); } @@ -264,7 +272,7 @@ public override void OnCollision(IGameObject collider, bool isTerrain = false) // only time we would collide with terrain is if we are inside of it, so we should teleport out of it. Vector2 exit = _game.Map.NavigationGrid.GetClosestTerrainExit(Position, PathfindingRadius + 1.0f); - TeleportTo(exit.X, exit.Y, true); + SetPosition(exit, false); } else { @@ -280,7 +288,11 @@ public override void OnCollision(IGameObject collider, bool isTerrain = false) // We should not teleport here because Pathfinding should handle it. // TODO: Implement a PathfindingHandler, and remove currently implemented manual pathfinding. Vector2 exit = Extensions.GetCircleEscapePoint(Position, PathfindingRadius + 1, collider.Position, collider.PathfindingRadius); - TeleportTo(exit.X, exit.Y, true); + if (!_game.Map.PathingHandler.IsWalkable(exit, PathfindingRadius)) + { + exit = _game.Map.NavigationGrid.GetClosestTerrainExit(exit, PathfindingRadius + 1.0f); + } + SetPosition(exit, false); } } @@ -962,16 +974,29 @@ public void UpdateStatus() /// Whether or not to repath from the new position. public void TeleportTo(float x, float y, bool repath = false) { - var position = new Vector2(x, y); + TeleportTo(new Vector2(x, y), repath); + } - if (!_game.Map.PathingHandler.IsWalkable(new Vector2(x, y), PathfindingRadius)) + /// + /// Teleports this unit to the given position, and optionally repaths from the new position. + /// + public void TeleportTo(Vector2 position, bool repath = false) + { + position = _game.Map.NavigationGrid.GetClosestTerrainExit(position, PathfindingRadius + 1.0f); + + if(repath) + { + SetPosition(position, true); + } + else { - position = _game.Map.NavigationGrid.GetClosestTerrainExit(new Vector2(x, y), PathfindingRadius + 1.0f); + Position = position; + ResetWaypoints(); } - SetPosition(position, repath); TeleportID++; - _game.PacketNotifier.NotifyTeleport(this, position); + _game.PacketNotifier.NotifyWaypointGroup(this, useTeleportID: true); + _movementUpdated = false; } /// @@ -1680,11 +1705,11 @@ public void DashToLocation(Vector2 endPos, float dashSpeed, string animation = " SetAnimStates(animPairs); } - _game.PacketNotifier.NotifyWaypointGroupWithSpeed(this); - // Movement is networked this way instead. // TODO: Verify if we want to use NotifyWaypointListWithSpeed instead as it does not require conversions. //_game.PacketNotifier.NotifyWaypointListWithSpeed(this, dashSpeed, leapGravity, keepFacingLastDirection, null, 0, 0, 20000.0f); + _game.PacketNotifier.NotifyWaypointGroupWithSpeed(this); + _movementUpdated = false; } /// diff --git a/GameServerLib/GameObjects/GameObject.cs b/GameServerLib/GameObjects/GameObject.cs index 92fbb53ac..b42ef621e 100644 --- a/GameServerLib/GameObjects/GameObject.cs +++ b/GameServerLib/GameObjects/GameObject.cs @@ -236,7 +236,7 @@ public virtual void OnCollision(IGameObject collider, bool isTerrain = false) // Escape functionality should be moved to GameObject.OnCollision. // only time we would collide with terrain is if we are inside of it, so we should teleport out of it. Vector2 exit = _game.Map.NavigationGrid.GetClosestTerrainExit(Position, PathfindingRadius + 1.0f); - TeleportTo(exit.X, exit.Y); + SetPosition(exit); } } @@ -320,12 +320,12 @@ public void SetSpawnedForPlayer(int userId) public virtual void TeleportTo(float x, float y) { var position = _game.Map.NavigationGrid.GetClosestTerrainExit(new Vector2(x, y), PathfindingRadius + 1.0f); - + SetPosition(position); - // TODO: Verify which one we want to use. WaypointList does not require conversions, however WaypointGroup does (and it has TeleportID functionality). - //_game.PacketNotifier.NotifyWaypointList(this, new List { Position }); - _game.PacketNotifier.NotifyEnterVisibilityClient(this, useTeleportID: true); + // TODO: Find a suitable function for this. Maybe modify NotifyWaypointGroup to accept simple objects. + _game.PacketNotifier.NotifyEnterVisibilityClient(this); + _movementUpdated = false; } /// diff --git a/GameServerLib/ObjectManager.cs b/GameServerLib/ObjectManager.cs index 8ae13e588..b31a9fc6c 100644 --- a/GameServerLib/ObjectManager.cs +++ b/GameServerLib/ObjectManager.cs @@ -236,7 +236,7 @@ void Sync(IGameObject obj, int userId = 0) // TODO: Verify which one we want to use. WaypointList does not require conversions, however WaypointGroup does (and it has TeleportID functionality). //_game.PacketNotifier.NotifyWaypointList(u); // TODO: Verify if we want to use TeleportID. - _game.PacketNotifier.NotifyWaypointGroup(u, userId, true); + _game.PacketNotifier.NotifyWaypointGroup(u, userId, false); } } } diff --git a/PacketDefinitions420/PacketExtensions.cs b/PacketDefinitions420/PacketExtensions.cs index 8fc527040..ce9aaa20e 100644 --- a/PacketDefinitions420/PacketExtensions.cs +++ b/PacketDefinitions420/PacketExtensions.cs @@ -132,88 +132,47 @@ public static MovementData CreateMovementData(IGameObject o, INavigationGrid gri return md; } + var currentWaypoints = new List(unit.Waypoints); + currentWaypoints[0] = unit.Position; + + int count = 2 + ((currentWaypoints.Count - 1) - unit.CurrentWaypoint.Key); + if (count >= 2) + { + currentWaypoints.RemoveRange(1, currentWaypoints.Count - count); + } + + var waypoints = currentWaypoints.ConvertAll(v => Vector2ToWaypoint(TranslateToCenteredCoordinates(v, grid))); + switch (type) { case MovementDataType.WithSpeed: { - if (speeds == null) - { - break; - } - - var waypoints = unit.Waypoints.ConvertAll(v => Vector2ToWaypoint(TranslateToCenteredCoordinates(v, grid))); - - if (useTeleportID) + if (speeds != null) { - var currentWaypoints = new List(); - currentWaypoints.AddRange(unit.Waypoints); - currentWaypoints.RemoveAt(0); - currentWaypoints.Insert(0, unit.Position); - - var count = 2 + ((currentWaypoints.Count - 1) - unit.CurrentWaypoint.Key); - if (count >= 2) + md = new MovementDataWithSpeed { - currentWaypoints.RemoveRange(1, currentWaypoints.Count - count); - } - - waypoints = currentWaypoints.ConvertAll(v => Vector2ToWaypoint(TranslateToCenteredCoordinates(v, grid))); - } - - md = new MovementDataWithSpeed - { - SyncID = unit.SyncId, - TeleportNetID = unit.NetId, - // TODO: Implement teleportID (likely to be the index (starting at 1) of a waypoint we want to TP to). - // Crucial in syncing client positions with server positions, especially when entering vision - HasTeleportID = useTeleportID, - TeleportID = unit.TeleportID, - Waypoints = waypoints, - SpeedParams = speeds - }; - - if (useTeleportID) - { - unit.TeleportID++; + SyncID = unit.SyncId, + TeleportNetID = unit.NetId, + HasTeleportID = useTeleportID, + TeleportID = useTeleportID ? unit.TeleportID : (byte)0, + Waypoints = waypoints, + SpeedParams = speeds + }; } break; } case MovementDataType.Normal: { - var waypoints = unit.Waypoints.ConvertAll(v => Vector2ToWaypoint(TranslateToCenteredCoordinates(v, grid))); - - if (useTeleportID) - { - var currentWaypoints = new List(); - currentWaypoints.AddRange(unit.Waypoints); - currentWaypoints.RemoveAt(0); - currentWaypoints.Insert(0, unit.Position); - - var count = 2 + ((currentWaypoints.Count - 1) - unit.CurrentWaypoint.Key); - if (count >= 2) - { - currentWaypoints.RemoveRange(1, currentWaypoints.Count - count); - } - - waypoints = currentWaypoints.ConvertAll(v => Vector2ToWaypoint(TranslateToCenteredCoordinates(v, grid))); - } - md = new MovementDataNormal { SyncID = unit.SyncId, TeleportNetID = unit.NetId, - // TODO: Implement teleportID (likely to be the index (starting at 1) of a waypoint we want to TP to). - // Crucial in syncing client positions with server positions, especially when entering vision HasTeleportID = useTeleportID, - TeleportID = unit.TeleportID, + TeleportID = useTeleportID ? unit.TeleportID : (byte)0, Waypoints = waypoints }; - if (useTeleportID) - { - unit.TeleportID++; - } - break; } } diff --git a/PacketDefinitions420/PacketNotifier.cs b/PacketDefinitions420/PacketNotifier.cs index 1a56e7f8b..427cad3f1 100644 --- a/PacketDefinitions420/PacketNotifier.cs +++ b/PacketDefinitions420/PacketNotifier.cs @@ -724,7 +724,7 @@ public void NotifyEnterLocalVisibilityClient(IGameObject o, int userId = 0, bool } } - OnEnterVisibilityClient ConstructEnterVisibilityClientPacket(IGameObject o, bool isChampion = false, bool useTeleportID = false, List packets = null) + OnEnterVisibilityClient ConstructEnterVisibilityClientPacket(IGameObject o, bool isChampion = false, List packets = null) { var itemData = new List(); //TODO: Fix item system so this can be finished var shields = new ShieldValues(); //TODO: Implement shields so this can be finished @@ -793,7 +793,7 @@ OnEnterVisibilityClient ConstructEnterVisibilityClientPacket(IGameObject o, bool } } - var md = PacketExtensions.CreateMovementData(o, _navGrid, type, speeds, useTeleportID: useTeleportID); + var md = PacketExtensions.CreateMovementData(o, _navGrid, type, speeds, useTeleportID: true); var enterVis = new OnEnterVisibilityClient // TYPO >:( { @@ -822,14 +822,13 @@ OnEnterVisibilityClient ConstructEnterVisibilityClientPacket(IGameObject o, bool /// GameObject entering vision. /// User to send the packet to. /// Whether or not the GameObject entering vision is a Champion. - /// Whether or not to teleport the object to its current position. /// Optionally ignore vision checks when sending this packet. /// Takes in a list of packets to send alongside this vision packet. /// TODO: Incomplete implementation. - public void NotifyEnterVisibilityClient(IGameObject o, int userId = 0, bool isChampion = false, bool useTeleportID = false, bool ignoreVision = false, List packets = null) + public void NotifyEnterVisibilityClient(IGameObject o, int userId = 0, bool isChampion = false, bool ignoreVision = false, List packets = null) { - var enterVis = ConstructEnterVisibilityClientPacket(o, isChampion, useTeleportID, packets); + var enterVis = ConstructEnterVisibilityClientPacket(o, isChampion, packets); if (userId != 0) { @@ -3312,7 +3311,7 @@ GamePacket ConstructSpawnPacket(IGameObject o, float gameTime = 0) return ConstructFXCreateGroupPacket(particle); } // Generic object - return ConstructEnterVisibilityClientPacket(o, useTeleportID: true); + return ConstructEnterVisibilityClientPacket(o); } /// @@ -3802,12 +3801,7 @@ void NotifyEnterTeamVision(IGameObject obj, TeamId team, int userId = 0, GamePac { packets = new List(1){ spawnPacket }; } - visibilityPacket = ConstructEnterVisibilityClientPacket( - obj, - isChampion: obj is IChampion, - useTeleportID: true, - packets: packets - ); + visibilityPacket = ConstructEnterVisibilityClientPacket(obj, obj is IChampion, packets); } var healthbarPacket = ConstructEnterLocalVisibilityClientPacket(obj); //TODO: try to include it to packets too? @@ -3873,7 +3867,7 @@ void NotifyLeaveTeamVision(IGameObject obj, TeamId team, int userId = 0) /// AttackableUnit that is moving. /// UserId to send the packet to. If not specified or zero, the packet is broadcasted to all players that have vision of the specified unit. /// Whether or not to teleport the unit to its current position in its path. - public void NotifyWaypointGroup(IAttackableUnit u, int userId = 0, bool useTeleportID = true) + public void NotifyWaypointGroup(IAttackableUnit u, int userId = 0, bool useTeleportID = false) { // TODO: Verify if casts correctly var move = (MovementDataNormal)PacketExtensions.CreateMovementData(u, _navGrid, MovementDataType.Normal, useTeleportID: useTeleportID);