/// <summary> /// Used by physics engine to actually update a player position /// Automatically notifies clients of updated position /// </summary> /// <param name="newPosition">The new position being requested, before verification through physics engine</param> /// <returns>TRUE if object moves to a different landblock</returns> public bool UpdatePlayerPhysics(ACE.Entity.Position newPosition, bool forceUpdate = false) { //Console.WriteLine($"UpdatePlayerPhysics: {newPosition.Cell:X8}, {newPosition.Pos}"); var player = this as Player; // only handles player movement if (player == null) { return(false); } // possible bug: while teleporting, client can still send AutoPos packets from old landblock if (Teleporting && !forceUpdate) { return(false); } if (PhysicsObj != null) { var dist = (newPosition.Pos - PhysicsObj.Position.Frame.Origin).Length(); if (dist > PhysicsGlobals.EPSILON) { var curCell = LScape.get_landcell(newPosition.Cell); if (curCell != null) { //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID) //PhysicsObj.change_cell_server(curCell); PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell, Location.LandblockId.Raw); PhysicsObj.update_object_server(); if (PhysicsObj.CurCell == null) { PhysicsObj.CurCell = curCell; } player.CheckMonsters(); if (curCell.ID != prevCell) { //prevCell = curCell.ID; //Console.WriteLine("Player cell: " + curCell.ID.ToString("X8")); //var envCell = curCell as Physics.Common.EnvCell; //var seenOutside = envCell != null ? envCell.SeenOutside : true; //Console.WriteLine($"CurCell: {curCell.ID:X8}, SeenOutside: {seenOutside}"); } } } } // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch if (Teleporting && !forceUpdate) { return(true); } var landblockUpdate = Location.Cell >> 16 != newPosition.Cell >> 16; Location = newPosition; SendUpdatePosition(); if (!InUpdate) { LandblockManager.RelocateObjectForPhysics(this, true); } return(landblockUpdate); }
/// <summary> /// Used by physics engine to actually update a player position /// Automatically notifies clients of updated position /// </summary> /// <param name="newPosition">The new position being requested, before verification through physics engine</param> /// <returns>TRUE if object moves to a different landblock</returns> public bool UpdatePlayerPosition(ACE.Entity.Position newPosition, bool forceUpdate = false) { //Console.WriteLine($"{Name}.UpdatePlayerPhysics({newPosition}, {forceUpdate}, {Teleporting})"); bool verifyContact = false; // possible bug: while teleporting, client can still send AutoPos packets from old landblock if (Teleporting && !forceUpdate) { return(false); } // pre-validate movement if (!ValidateMovement(newPosition)) { log.Error($"{Name}.UpdatePlayerPosition() - movement pre-validation failed from {Location} to {newPosition}"); return(false); } try { if (!forceUpdate) // This is needed beacuse this function might be called recursively { stopwatch.Restart(); } var success = true; if (PhysicsObj != null) { var distSq = Location.SquaredDistanceTo(newPosition); if (distSq > PhysicsGlobals.EpsilonSq) { /*var p = new Physics.Common.Position(newPosition); * var dist = PhysicsObj.Position.Distance(p); * Console.WriteLine($"Dist: {dist}");*/ if (newPosition.Landblock == 0x18A && Location.Landblock != 0x18A) { log.Info($"{Name} is getting swanky"); } if (!Teleporting) { var blockDist = PhysicsObj.GetBlockDist(Location.Cell, newPosition.Cell); // verify movement if (distSq > MaxSpeedSq && blockDist > 1) { //Session.Network.EnqueueSend(new GameMessageSystemChat("Movement error", ChatMessageType.Broadcast)); log.Warn($"MOVEMENT SPEED: {Name} trying to move from {Location} to {newPosition}, speed: {Math.Sqrt(distSq)}"); return(false); } // verify z-pos if (blockDist == 0 && LastGroundPos != null && newPosition.PositionZ - LastGroundPos.PositionZ > 10 && DateTime.UtcNow - LastJumpTime > TimeSpan.FromSeconds(1) && GetCreatureSkill(Skill.Jump).Current < 1000) { verifyContact = true; } } var curCell = LScape.get_landcell(newPosition.Cell); if (curCell != null) { //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID) //PhysicsObj.change_cell_server(curCell); PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell, Location.LandblockId.Raw); if (FastTick) { success = PhysicsObj.update_object_server_new(); } else { success = PhysicsObj.update_object_server(); } if (PhysicsObj.CurCell == null && curCell.ID >> 16 != 0x18A) { PhysicsObj.CurCell = curCell; } if (verifyContact && IsJumping) { var blockDist = PhysicsObj.GetBlockDist(newPosition.Cell, LastGroundPos.Cell); if (blockDist <= 1) { log.Warn($"z-pos hacking detected for {Name}, lastGroundPos: {LastGroundPos.ToLOCString()} - requestPos: {newPosition.ToLOCString()}"); Location = new ACE.Entity.Position(LastGroundPos); Sequences.GetNextSequence(SequenceType.ObjectForcePosition); SendUpdatePosition(); return(false); } } CheckMonsters(); } } else { PhysicsObj.Position.Frame.Orientation = newPosition.Rotation; } } // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch if (Teleporting && !forceUpdate) { return(true); } if (!success) { return(false); } var landblockUpdate = Location.Cell >> 16 != newPosition.Cell >> 16; Location = newPosition; if (RecordCast.Enabled) { RecordCast.Log($"CurPos: {Location.ToLOCString()}"); } if (RequestedLocationBroadcast || DateTime.UtcNow - LastUpdatePosition >= MoveToState_UpdatePosition_Threshold) { SendUpdatePosition(); } else { Session.Network.EnqueueSend(new GameMessageUpdatePosition(this)); } if (!InUpdate) { LandblockManager.RelocateObjectForPhysics(this, true); } return(landblockUpdate); } finally { if (!forceUpdate) // This is needed beacuse this function might be called recursively { var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; ServerPerformanceMonitor.AddToCumulativeEvent(ServerPerformanceMonitor.CumulativeEventHistoryType.Player_Tick_UpdateObjectPhysics, elapsedSeconds); if (elapsedSeconds >= 0.100) // Yea, that ain't good.... { log.Warn($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPosition() at loc: {Location}"); } else if (elapsedSeconds >= 0.010) { log.Debug($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPosition() at loc: {Location}"); } } } }
/// <summary> /// Called when a monster changes landblocks /// </summary> public void UpdateLandblock() { PreviousLocation = Location; LandblockManager.RelocateObjectForPhysics(this); }
/// <summary> /// Called when a monster changes landblocks /// </summary> public void UpdateLandblock() { LandblockManager.RelocateObjectForPhysics(this, true); //Console.WriteLine("Relocating " + Name + " to " + Location.LandblockId); }
/// <summary> /// Used by physics engine to actually update a player position /// Automatically notifies clients of updated position /// </summary> /// <param name="newPosition">The new position being requested, before verification through physics engine</param> /// <returns>TRUE if object moves to a different landblock</returns> public bool UpdatePlayerPhysics(ACE.Entity.Position newPosition, bool forceUpdate = false) { //Console.WriteLine($"{Name}.UpdatePlayerPhysics({newPosition}, {forceUpdate}, {Teleporting})"); // possible bug: while teleporting, client can still send AutoPos packets from old landblock if (Teleporting && !forceUpdate) { return(false); } // pre-validate movement if (!ValidateMovement(newPosition)) { log.Error($"{Name}.UpdatePlayerPhysics() - movement pre-validation failed from {Location} to {newPosition}"); return(false); } try { if (!forceUpdate) // This is needed beacuse this function might be called recursively { stopwatch.Restart(); } var success = true; if (PhysicsObj != null) { var distSq = Location.SquaredDistanceTo(newPosition); if (distSq > PhysicsGlobals.EpsilonSq) { var curCell = LScape.get_landcell(newPosition.Cell); if (curCell != null) { //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID) //PhysicsObj.change_cell_server(curCell); PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell, Location.LandblockId.Raw); success = PhysicsObj.update_object_server(); if (PhysicsObj.CurCell == null && curCell.ID >> 16 != 0x18A) { PhysicsObj.CurCell = curCell; } CheckMonsters(); } } } // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch if (Teleporting && !forceUpdate) { return(true); } if (!success) { return(false); } var landblockUpdate = Location.Cell >> 16 != newPosition.Cell >> 16; Location = newPosition; SendUpdatePosition(); if (!InUpdate) { LandblockManager.RelocateObjectForPhysics(this, true); } return(landblockUpdate); } finally { if (!forceUpdate) // This is needed beacuse this function might be called recursively { var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; ServerPerformanceMonitor.AddToCumulativeEvent(ServerPerformanceMonitor.CumulativeEventHistoryType.WorldObject_Tick_UpdatePlayerPhysics, elapsedSeconds); if (elapsedSeconds >= 1) // Yea, that ain't good.... { log.Warn($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPhysics() at loc: {Location}"); } else if (elapsedSeconds >= 0.010) { log.Debug($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPhysics() at loc: {Location}"); } } } }