diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java index 9e40544962..3f658b4128 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java index 9e40544962..3f658b4128 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java index 9e40544962..3f658b4128 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java index 9e40544962..3f658b4128 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java index f18b60cf85..bcf8ffe8a9 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index cf7a5f4fa0..cffa27dff1 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -256,14 +256,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java index f18b60cf85..bcf8ffe8a9 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 50663ac0cc..362c93ea7d 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java index f18b60cf85..bcf8ffe8a9 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 50663ac0cc..362c93ea7d 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java index 4f94704ab3..f8790fdeaa 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3344,13 +3355,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3664,7 +3675,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3734,7 +3745,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3744,8 +3755,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 50663ac0cc..362c93ea7d 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java index 4d0157f0af..767255a726 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3344,13 +3355,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3664,7 +3675,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3734,7 +3745,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3744,8 +3755,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 818dfd3f4f..01028a22fe 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -266,14 +266,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java index 4d0157f0af..767255a726 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3344,13 +3355,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3664,7 +3675,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3734,7 +3745,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3744,8 +3755,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 818dfd3f4f..01028a22fe 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -266,14 +266,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java index ec717573a5..4d23f5e683 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1186,7 +1186,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1235,7 +1241,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3354,13 +3365,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
* The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
@@ -3674,7 +3685,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3744,7 +3755,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3754,8 +3765,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 121b56214a..fb86f44517 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -267,14 +267,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java index fe2c424ece..df419d6ab7 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -5200,19 +5200,19 @@ public abstract class Creature extends WorldObject implements ISkillsHolder } /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
+ * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
*
* Concept:
*
* At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature. The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
- * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
+ * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
*
* Actions:
*
  • Get current position of the Creature
  • *
  • Calculate distance (dx,dy) between current position and destination including offset
  • *
  • Create and Init a MoveData object
  • *
  • Set the Creature _move object to MoveData object
  • - *
  • Add the Creature to movingObjects of the GameTimeTaskManager
  • + *
  • Add the Creature to MOVING_OBJECTS of the MovementTaskManager
  • *
  • Create a task to notify the AI that Creature arrives at a check point of the movement

  • * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation
    *
    @@ -5613,7 +5613,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -5623,7 +5623,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder ThreadPool.schedule(new NotifyAITask(CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index 93271ae582..44994e15ea 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -5246,19 +5246,19 @@ public abstract class Creature extends WorldObject implements ISkillsHolder } /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature. The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions:
    *
  • Get current position of the Creature
  • *
  • Calculate distance (dx,dy) between current position and destination including offset
  • *
  • Create and Init a MoveData object
  • *
  • Set the Creature _move object to MoveData object
  • - *
  • Add the Creature to movingObjects of the GameTimeTaskManager
  • + *
  • Add the Creature to MOVING_OBJECTS of the MovementTaskManager
  • *
  • Create a task to notify the AI that Creature arrives at a check point of the movement

  • * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation
    *
    @@ -5659,7 +5659,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -5669,7 +5669,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder ThreadPool.schedule(new NotifyAITask(CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 273b661c8e..a2ef5ce25f 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -309,9 +309,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.getBowAttackEndTime() > GameTimeTaskManager.getInstance().getGameTicks()) + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + final int bowAttackEndTime = _actor.getBowAttackEndTime(); + if (bowAttackEndTime > gameTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target), (_actor.getBowAttackEndTime() - GameTimeTaskManager.getInstance().getGameTicks()) * GameTimeTaskManager.MILLIS_IN_TICK); + ThreadPool.schedule(new CastTask(_actor, skill, target), (bowAttackEndTime - gameTime) * GameTimeTaskManager.MILLIS_IN_TICK); } else { diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index b142ca89c3..c3fd27ef73 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1054,6 +1054,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final Attack attack = new Attack(this, target, isChargedShot(ShotType.SOULSHOTS), (weaponItem != null) ? weaponItem.getCrystalTypePlus().getLevel() : 0); setHeading(Util.calculateHeadingFrom(this, target)); final int reuse = calculateReuseTime(weaponItem); + final long currentTime = System.nanoTime(); boolean hitted = false; switch (getAttackType()) { @@ -1063,13 +1064,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { return; } - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeToHit + (reuse / 2)); hitted = doAttackHitByBow(attack, target, timeAtk, reuse); break; } case POLE: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByPole(attack, target, timeToHit); break; } @@ -1077,7 +1078,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { if (!isPlayer()) { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } @@ -1087,18 +1088,24 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe case DUALFIST: case DUALDAGGER: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByDual(attack, target, timeToHit); break; } default: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } } + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) { final Npc npc = ((Npc) this); @@ -1226,7 +1233,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new HitTask(this, target, damage1, crit1, miss1, shld1, attack.hasSoulshot(), true), sAtk); // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableBowAttackEndTime = ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK) + GameTimeTaskManager.getInstance().getGameTicks(); + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + _disableBowAttackEndTime = gameTime + ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableBowAttackEndTime < gameTime) + { + _disableBowAttackEndTime = Integer.MAX_VALUE; + } // Add this hit to the Server-Client packet Attack attack.addHit(target, damage1, miss1, crit1, shld1); @@ -4124,13 +4137,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -4435,7 +4448,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -4444,7 +4457,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -4524,8 +4537,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 8a05e9897e..83dbdf1b36 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -225,14 +225,18 @@ public class UseItem implements IClientIncomingPacket // Binding next action to AI. player.getAI().setNextAction(nextAction); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.MILLISECONDS.convert(player.getAttackEndTime() - System.nanoTime(), TimeUnit.NANOSECONDS)); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/CreatureAI.java index c2097d8213..19daece758 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -311,9 +311,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.getBowAttackEndTime() > GameTimeTaskManager.getInstance().getGameTicks()) + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + final int bowAttackEndTime = _actor.getBowAttackEndTime(); + if (bowAttackEndTime > gameTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target), (_actor.getBowAttackEndTime() - GameTimeTaskManager.getInstance().getGameTicks()) * GameTimeTaskManager.MILLIS_IN_TICK); + ThreadPool.schedule(new CastTask(_actor, skill, target), (bowAttackEndTime - gameTime) * GameTimeTaskManager.MILLIS_IN_TICK); } else { diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java index 1dfab2e8df..7bbbe6bd7c 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1103,6 +1103,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final Attack attack = new Attack(this, target, isChargedShot(ShotType.SOULSHOTS), (weaponItem != null) ? weaponItem.getCrystalTypePlus().getLevel() : 0); setHeading(Util.calculateHeadingFrom(this, target)); final int reuse = calculateReuseTime(weaponItem); + final long currentTime = System.nanoTime(); boolean hitted = false; switch (getAttackType()) { @@ -1112,7 +1113,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { return; } - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeToHit + (reuse / 2)); hitted = doAttackHitByBow(attack, target, timeAtk, reuse); break; } @@ -1122,13 +1123,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { return; } - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeToHit + (reuse / 2)); hitted = doAttackHitByCrossBow(attack, target, timeAtk, reuse); break; } case POLE: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByPole(attack, target, timeToHit); break; } @@ -1136,7 +1137,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { if (!isPlayer()) { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } @@ -1146,18 +1147,24 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe case DUALFIST: case DUALDAGGER: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByDual(attack, target, timeToHit); break; } default: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } } + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) { final Npc npc = ((Npc) this); @@ -1285,7 +1292,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new HitTask(this, target, damage1, crit1, miss1, shld1, attack.hasSoulshot(), true), sAtk); // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableBowAttackEndTime = ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK) + GameTimeTaskManager.getInstance().getGameTicks(); + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + _disableBowAttackEndTime = gameTime + ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableBowAttackEndTime < gameTime) + { + _disableBowAttackEndTime = Integer.MAX_VALUE; + } // Add this hit to the Server-Client packet Attack attack.addHit(target, damage1, miss1, crit1, shld1); @@ -1355,7 +1368,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new HitTask(this, target, damage1, crit1, miss1, shld1, attack.hasSoulshot(), true), sAtk); // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableBowAttackEndTime = ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK) + GameTimeTaskManager.getInstance().getGameTicks(); + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + _disableBowAttackEndTime = gameTime + ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableBowAttackEndTime < gameTime) + { + _disableBowAttackEndTime = Integer.MAX_VALUE; + } // Add this hit to the Server-Client packet Attack attack.addHit(target, damage1, miss1, crit1, shld1); @@ -4309,13 +4328,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -4629,7 +4648,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -4699,7 +4718,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -4709,8 +4728,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 3215fbdb8f..8119d01fc3 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -302,14 +302,18 @@ public class UseItem implements IClientIncomingPacket // Binding next action to AI. player.getAI().setNextAction(nextAction); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.MILLISECONDS.convert(player.getAttackEndTime() - System.nanoTime(), TimeUnit.NANOSECONDS)); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/CreatureAI.java index c2097d8213..19daece758 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -311,9 +311,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.getBowAttackEndTime() > GameTimeTaskManager.getInstance().getGameTicks()) + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + final int bowAttackEndTime = _actor.getBowAttackEndTime(); + if (bowAttackEndTime > gameTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target), (_actor.getBowAttackEndTime() - GameTimeTaskManager.getInstance().getGameTicks()) * GameTimeTaskManager.MILLIS_IN_TICK); + ThreadPool.schedule(new CastTask(_actor, skill, target), (bowAttackEndTime - gameTime) * GameTimeTaskManager.MILLIS_IN_TICK); } else { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java index 60c376b00c..86703c1670 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -284,7 +284,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe /** Table of calculators containing all standard NPC calculator (ex : ACCURACY_COMBAT, EVASION_RATE) */ private static final Calculator[] NPC_STD_CALCULATOR = Formulas.getStdNPCCalculators(); - private CreatureAI _ai = null; + private volatile CreatureAI _ai = null; /** Future Skill Cast */ protected Future _skillCast; @@ -1104,6 +1104,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final Attack attack = new Attack(this, target, isChargedShot(ShotType.SOULSHOTS), (weaponItem != null) ? weaponItem.getCrystalTypePlus().getLevel() : 0); setHeading(Util.calculateHeadingFrom(this, target)); final int reuse = calculateReuseTime(weaponItem); + final long currentTime = System.nanoTime(); boolean hitted = false; switch (getAttackType()) { @@ -1113,7 +1114,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { return; } - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeToHit + (reuse / 2)); hitted = doAttackHitByBow(attack, target, timeAtk, reuse); break; } @@ -1123,13 +1124,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { return; } - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeToHit + (reuse / 2)); hitted = doAttackHitByCrossBow(attack, target, timeAtk, reuse); break; } case POLE: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByPole(attack, target, timeToHit); break; } @@ -1137,7 +1138,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { if (!isPlayer()) { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } @@ -1147,18 +1148,24 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe case DUALFIST: case DUALDAGGER: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitByDual(attack, target, timeToHit); break; } default: { - _attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); hitted = doAttackHitSimple(attack, target, timeToHit); break; } } + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) { final Npc npc = ((Npc) this); @@ -1286,7 +1293,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new HitTask(this, target, damage1, crit1, miss1, shld1, attack.hasSoulshot(), true), sAtk); // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableBowAttackEndTime = ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK) + GameTimeTaskManager.getInstance().getGameTicks(); + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + _disableBowAttackEndTime = gameTime + ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableBowAttackEndTime < gameTime) + { + _disableBowAttackEndTime = Integer.MAX_VALUE; + } // Add this hit to the Server-Client packet Attack attack.addHit(target, damage1, miss1, crit1, shld1); @@ -1356,7 +1369,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new HitTask(this, target, damage1, crit1, miss1, shld1, attack.hasSoulshot(), true), sAtk); // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableBowAttackEndTime = ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK) + GameTimeTaskManager.getInstance().getGameTicks(); + final int gameTime = GameTimeTaskManager.getInstance().getGameTicks(); + _disableBowAttackEndTime = gameTime + ((sAtk + reuse) / GameTimeTaskManager.MILLIS_IN_TICK); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableBowAttackEndTime < gameTime) + { + _disableBowAttackEndTime = Integer.MAX_VALUE; + } // Add this hit to the Server-Client packet Attack attack.addHit(target, damage1, miss1, crit1, shld1); @@ -4311,13 +4330,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -4631,7 +4650,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -4701,7 +4720,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -4711,8 +4730,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 3215fbdb8f..8119d01fc3 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -302,14 +302,18 @@ public class UseItem implements IClientIncomingPacket // Binding next action to AI. player.getAI().setNextAction(nextAction); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.MILLISECONDS.convert(player.getAttackEndTime() - System.nanoTime(), TimeUnit.NANOSECONDS)); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 33dc4e55a8..72bf42a562 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/model/actor/Creature.java index 6970be84ff..f87fb93582 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/model/actor/Creature.java index 6970be84ff..f87fb93582 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java index 6970be84ff..f87fb93582 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java index 6970be84ff..f87fb93582 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 265a24ed5a..07611c317d 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -259,14 +259,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java index 41f585c24b..169e3c34d3 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index e4eb4c9ad8..b6e0cfed67 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -256,14 +256,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java index 65ee8bcc9b..8e534cbd96 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1177,7 +1177,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1226,7 +1232,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3358,13 +3369,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3678,7 +3689,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3748,7 +3759,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3758,8 +3769,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 2b37a81230..cd3c98a997 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java index a89b3874cf..8fe58f9524 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1177,7 +1177,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1226,7 +1232,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3358,13 +3369,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3678,7 +3689,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3748,7 +3759,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3758,8 +3769,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 61b8302c2d..5b281c08d1 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java index 65ee8bcc9b..8e534cbd96 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1177,7 +1177,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1226,7 +1232,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3358,13 +3369,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3678,7 +3689,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3748,7 +3759,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3758,8 +3769,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 2b37a81230..cd3c98a997 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java index 2f75f2d546..708ab95bf0 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1177,7 +1177,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1226,7 +1232,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3357,13 +3368,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3677,7 +3688,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3747,7 +3758,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3757,8 +3768,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 2b37a81230..cd3c98a997 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -265,14 +265,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index 6970be84ff..f87fb93582 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1176,7 +1176,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1225,7 +1231,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3345,13 +3356,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3665,7 +3676,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3735,7 +3746,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3745,8 +3756,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index a7fb9d4f4b..1f243259d8 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -267,14 +267,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI. player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java index e5993d1a35..e90328172f 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1180,7 +1180,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1229,7 +1235,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3360,13 +3371,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3680,7 +3691,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3750,7 +3761,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3760,8 +3771,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 7ded4ed21d..b548c9b86a 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -277,14 +277,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java index 771560cd17..6a195d4e81 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1187,7 +1187,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1236,7 +1242,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3367,13 +3378,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3687,7 +3698,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3757,7 +3768,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3767,8 +3778,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 76ea55aa8d..c9403e2780 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -293,14 +293,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/CreatureAI.java index 477eec97f6..5c84260d5c 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -310,9 +310,11 @@ public class CreatureAI extends AbstractAI return; } - if (_actor.isAttackingNow()) + final long currentTime = System.nanoTime(); + final long attackEndTime = _actor.getAttackEndTime(); + if (attackEndTime > currentTime) { - ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), _actor.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); + ThreadPool.schedule(new CastTask(_actor, skill, target, item, forceUse, dontMove), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); } else { diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java index f2a395d96c..fee9e5d2e1 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -1197,7 +1197,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe final boolean isTwoHanded = (weaponItem != null) && (weaponItem.getBodyPart() == ItemTemplate.SLOT_LR_HAND); final int timeAtk = Formulas.calculateTimeBetweenAttacks(_stat.getPAtkSpd()); final int timeToHit = Formulas.calculateTimeToHit(timeAtk, weaponType, isTwoHanded, false); - _attackEndTime = System.nanoTime() + (TimeUnit.MILLISECONDS.toNanos(timeAtk)); + final long currentTime = System.nanoTime(); + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(timeAtk); + // Precaution. It has happened in the past. Probably impossible to happen now, but will not risk it. + if (_attackEndTime < currentTime) + { + _attackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } // Make sure that char is facing selected target // also works: setHeading(Util.convertDegreeToClientHeading(Util.calculateAngleFrom(this, target))); @@ -1246,7 +1252,12 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe } // Calculate and set the disable delay of the bow in function of the Attack Speed - _disableRangedAttackEndTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(reuse); + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(reuse); + // Precaution. It happened in the past for _attackEndTime. Will not risk it. + if (_disableRangedAttackEndTime < currentTime) + { + _disableRangedAttackEndTime = currentTime + TimeUnit.MILLISECONDS.toNanos(Integer.MAX_VALUE); + } _hitTask = ThreadPool.schedule(() -> onHitTimeNotDual(weaponItem, attack, timeToHit, timeAtk), timeToHit); break; } @@ -3377,13 +3388,13 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // called from AIAccessor only /** - * Calculate movement data for a move to location action and add the Creature to movingObjects of GameTimeTaskManager (only called by AI Accessor).
    + * Calculate movement data for a move to location action and add the Creature to MOVING_OBJECTS of MovementTaskManager (only called by AI Accessor).
    *
    * Concept:
    *
    * At the beginning of the move action, all properties of the movement are stored in the MoveData object called _move of the Creature.
    * The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.
    - * All Creature in movement are identified in movingObjects of GameTimeTaskManager that will call the updatePosition method of those Creature each 0.1s.
    + * All Creature in movement are identified in MOVING_OBJECTS of MovementTaskManager that will call the updatePosition method of those Creature each 0.1s.
    *
    * Actions: * * Caution: This method DOESN'T send Server->Client packet MoveToPawn/MoveToLocation.
    @@ -3697,7 +3708,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager } public boolean moveToNextRoutePoint() @@ -3767,7 +3778,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Set the Creature _move object to MoveData object _move = m; - // Add the Creature to moving objects of the GameTimeTaskManager. + // Add the Creature to moving objects of the MovementTaskManager. // The MovementTaskManager manages object movement. MovementTaskManager.getInstance().registerMovingObject(this); @@ -3777,8 +3788,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe ThreadPool.schedule(new NotifyAITask(this, CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); } - // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive - // to destination by GameTimeTaskManager + // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive to destination by MovementTaskManager // Send a Server->Client packet MoveToLocation to the actor and all Player in its _knownPlayers broadcastMoveToLocation(); diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java index 21bf550f2a..e5f8e5df4a 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/clientpackets/UseItem.java @@ -295,14 +295,18 @@ public class UseItem implements IClientIncomingPacket // Create and Bind the next action to the AI player.getAI().setNextAction(new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, () -> player.useEquippableItem(item, true))); } - else if (player.isAttackingNow()) + else // Equip or unEquip. { - // Equip or unEquip. - ThreadPool.schedule(() -> player.useEquippableItem(item, false), player.getAttackEndTime() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())); - } - else - { - player.useEquippableItem(item, true); + final long currentTime = System.nanoTime(); + final long attackEndTime = player.getAttackEndTime(); + if (attackEndTime > currentTime) + { + ThreadPool.schedule(() -> player.useEquippableItem(item, false), TimeUnit.NANOSECONDS.toMillis(attackEndTime - currentTime)); + } + else + { + player.useEquippableItem(item, true); + } } } else