From 8f80bb3a41060df1c98b2092804fba5d6b63b85e Mon Sep 17 00:00:00 2001 From: MobiusDevelopment <8391001+MobiusDevelopment@users.noreply.github.com> Date: Mon, 21 Sep 2020 21:39:37 +0000 Subject: [PATCH] Addition of auto play task managers. --- .../model/actor/instance/PlayerInstance.java | 295 +----------------- .../model/holders/AutoPlaySettingsHolder.java | 75 +++++ .../model/holders/AutoUseSettingsHolder.java | 49 +++ .../clientpackets/RequestShortCutDel.java | 5 +- .../autoplay/ExAutoPlaySetting.java | 7 +- .../ExRequestActivateAutoShortcut.java | 13 +- .../taskmanager/AutoPlayTaskManager.java | 170 ++++++++++ .../taskmanager/AutoUseTaskManager.java | 222 +++++++++++++ .../model/actor/instance/PlayerInstance.java | 295 +----------------- .../model/holders/AutoPlaySettingsHolder.java | 75 +++++ .../model/holders/AutoUseSettingsHolder.java | 49 +++ .../clientpackets/RequestShortCutDel.java | 5 +- .../autoplay/ExAutoPlaySetting.java | 7 +- .../ExRequestActivateAutoShortcut.java | 13 +- .../taskmanager/AutoPlayTaskManager.java | 170 ++++++++++ .../taskmanager/AutoUseTaskManager.java | 222 +++++++++++++ 16 files changed, 1076 insertions(+), 596 deletions(-) create mode 100644 L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java create mode 100644 L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java create mode 100644 L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java create mode 100644 L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java create mode 100644 L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java create mode 100644 L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java create mode 100644 L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java create mode 100644 L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index aabf90cc5b..3cf90aeb27 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -39,7 +39,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.stream.Collectors; @@ -220,9 +219,10 @@ import org.l2jmobius.gameserver.model.events.returns.TerminateReturn; import org.l2jmobius.gameserver.model.events.timers.TimerHolder; import org.l2jmobius.gameserver.model.fishing.Fishing; import org.l2jmobius.gameserver.model.holders.AttendanceInfoHolder; +import org.l2jmobius.gameserver.model.holders.AutoPlaySettingsHolder; +import org.l2jmobius.gameserver.model.holders.AutoUseSettingsHolder; import org.l2jmobius.gameserver.model.holders.DamageTakenHolder; import org.l2jmobius.gameserver.model.holders.ItemHolder; -import org.l2jmobius.gameserver.model.holders.ItemSkillHolder; import org.l2jmobius.gameserver.model.holders.MonsterBookCardHolder; import org.l2jmobius.gameserver.model.holders.MonsterBookRewardHolder; import org.l2jmobius.gameserver.model.holders.MovieHolder; @@ -266,7 +266,6 @@ import org.l2jmobius.gameserver.model.skills.CommonSkill; import org.l2jmobius.gameserver.model.skills.Skill; import org.l2jmobius.gameserver.model.skills.SkillCaster; import org.l2jmobius.gameserver.model.skills.SkillCastingType; -import org.l2jmobius.gameserver.model.skills.targets.AffectScope; import org.l2jmobius.gameserver.model.skills.targets.TargetType; import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.Formulas; @@ -348,7 +347,6 @@ import org.l2jmobius.gameserver.network.serverpackets.TradeOtherDone; import org.l2jmobius.gameserver.network.serverpackets.TradeStart; import org.l2jmobius.gameserver.network.serverpackets.UserInfo; import org.l2jmobius.gameserver.network.serverpackets.ValidateLocation; -import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro; import org.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo; import org.l2jmobius.gameserver.network.serverpackets.friend.FriendStatus; import org.l2jmobius.gameserver.network.serverpackets.monsterbook.ExMonsterBook; @@ -869,15 +867,8 @@ public class PlayerInstance extends Playable private final Set _whisperers = ConcurrentHashMap.newKeySet(); - private ScheduledFuture _autoPlayTask = null; - private ScheduledFuture _autoUseTask = null; - private final AtomicBoolean _pickup = new AtomicBoolean(); - private final AtomicBoolean _longRange = new AtomicBoolean(); - private final AtomicBoolean _respectfulHunting = new AtomicBoolean(); - private final AtomicInteger _autoPotionPercent = new AtomicInteger(); - private final Collection _autoSupplyItems = ConcurrentHashMap.newKeySet(); - private final Collection _autoPotionItems = ConcurrentHashMap.newKeySet(); - private final Collection _autoSkills = ConcurrentHashMap.newKeySet(); + private final AutoPlaySettingsHolder _autoPlaySettings = new AutoPlaySettingsHolder(); + private final AutoUseSettingsHolder _autoUseSettings = new AutoUseSettingsHolder(); private ScheduledFuture _timedHuntingZoneFinishTask = null; @@ -13863,16 +13854,6 @@ public class PlayerInstance extends Playable _autoSaveTask.cancel(false); _autoSaveTask = null; } - if ((_autoPlayTask != null) && !_autoPlayTask.isDone() && !_autoPlayTask.isCancelled()) - { - _autoPlayTask.cancel(false); - _autoPlayTask = null; - } - if ((_autoUseTask != null) && !_autoUseTask.isDone() && !_autoUseTask.isCancelled()) - { - _autoUseTask.cancel(false); - _autoUseTask = null; - } if ((_timedHuntingZoneFinishTask != null) && !_timedHuntingZoneFinishTask.isDone() && !_timedHuntingZoneFinishTask.isCancelled()) { _timedHuntingZoneFinishTask.cancel(false); @@ -14170,274 +14151,14 @@ public class PlayerInstance extends Playable } } - public void stopAutoPlayTask() + public AutoPlaySettingsHolder getAutoPlaySettings() { - if ((_autoPlayTask != null) && !_autoPlayTask.isCancelled() && !_autoPlayTask.isDone()) - { - _autoPlayTask.cancel(true); - _autoPlayTask = null; - } + return _autoPlaySettings; } - public void startAutoPlayTask(boolean pickup, boolean longRange, boolean respectfulHunting) + public AutoUseSettingsHolder getAutoUseSettings() { - _pickup.set(pickup); - _longRange.set(longRange); - _respectfulHunting.set(respectfulHunting); - - if (_autoPlayTask != null) - { - return; - } - - _autoPlayTask = ThreadPool.scheduleAtFixedRate(() -> - { - if (!Config.ENABLE_AUTO_PLAY) - { - stopAutoPlayTask(); - return; - } - - // Skip thinking. - final WorldObject target = getTarget(); - if ((target != null) && target.isMonster()) - { - final MonsterInstance monster = (MonsterInstance) target; - if ((monster.getTarget() == this) && !monster.isAlikeDead()) - { - // Check if actually attacking. - if (hasAI() && getAI().isAutoAttacking() && !isAttackingNow() && !isCastingNow()) - { - doAutoAttack(monster); - } - return; - } - } - - // Pickup. - if (_pickup.get()) - { - for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(this, ItemInstance.class, 200)) - { - // Check if item is reachable. - if ((droppedItem == null) // - || (!droppedItem.isSpawned()) // - || !GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), getInstanceWorld())) - { - continue; - } - - // Move to item. - if (calculateDistance2D(droppedItem) > 50) - { - moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0); - return; - } - - // Try to pick it up. - if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == getObjectId())) - { - doPickupItem(droppedItem); - return; // Avoid pickup being skipped. - } - } - } - - // Find target. - MonsterInstance monster = null; - double closestDistance = Double.MAX_VALUE; - for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(this, MonsterInstance.class, _longRange.get() ? 1400 : 600)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue; - } - // Check monster target. - if (_respectfulHunting.get() && (nearby.getTarget() != null) && (nearby.getTarget() != this)) - { - continue; - } - // Check if monster is reachable. - if (nearby.isAutoAttackable(this) // - && GeoEngine.getInstance().canSeeTarget(this, nearby)// - && GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), getInstanceWorld())) - { - final double monsterDistance = calculateDistance2D(nearby); - if (monsterDistance < closestDistance) - { - monster = nearby; - closestDistance = monsterDistance; - } - } - } - - // New target was assigned. - if (monster != null) - { - setTarget(monster); - sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } - }, 0, 1000); - } - - public void stopAutoUseTask() - { - if ((_autoUseTask != null) && !_autoUseTask.isCancelled() && !_autoUseTask.isDone()) - { - _autoUseTask.cancel(true); - _autoUseTask = null; - } - } - - private void startAutoUseTask() - { - if (_autoUseTask != null) - { - return; - } - - _autoUseTask = ThreadPool.scheduleAtFixedRate(() -> - { - if (hasBlockActions() || isControlBlocked() || isAlikeDead() || isInsideZone(ZoneId.PEACE)) - { - return; - } - - if (Config.ENABLE_AUTO_ITEM) - { - ITEMS: for (int itemId : _autoSupplyItems) - { - final ItemInstance item = _inventory.getItemByItemId(itemId); - if (item == null) - { - removeAutoSupplyItem(itemId); - continue; - } - - for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills()) - { - final Skill skill = itemSkillHolder.getSkill(); - if (isAffectedBySkill(skill.getId()) || hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(this, this, false)) - { - continue ITEMS; - } - } - - final int reuseDelay = item.getReuseDelay(); - if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0)) - { - final EtcItem etcItem = item.getEtcItem(); - final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); - if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0)) - { - addTimeStampItem(item, reuseDelay); - } - } - } - } - - if (Config.ENABLE_AUTO_POTION && (getCurrentHpPercent() <= _autoPotionPercent.get())) - { - for (int itemId : _autoPotionItems) - { - final ItemInstance item = _inventory.getItemByItemId(itemId); - if (item == null) - { - removeAutoPotionItem(itemId); - continue; - } - final int reuseDelay = item.getReuseDelay(); - if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0)) - { - final EtcItem etcItem = item.getEtcItem(); - final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); - if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0)) - { - addTimeStampItem(item, reuseDelay); - } - } - } - } - - if (Config.ENABLE_AUTO_BUFF) - { - for (int skillId : _autoSkills) - { - final Skill skill = getKnownSkill(skillId); - if (skill == null) - { - removeAutoSkill(skillId); - continue; - } - if (!isAffectedBySkill(skillId) && !hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(this, this, false)) - { - // Summon check. - if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) - { - if (!hasServitors()) // Is this check truly needed? - { - continue; - } - int occurrences = 0; - for (Summon servitor : _servitors.values()) - { - if (servitor.isAffectedBySkill(skillId)) - { - occurrences++; - } - } - if (occurrences == _servitors.size()) - { - continue; - } - } - doCast(skill); - } - } - } - }, 0, 1000); - } - - public void setAutoPotionPercent(int value) - { - _autoPotionPercent.set(value); - } - - public void addAutoSupplyItem(int itemId) - { - _autoSupplyItems.add(itemId); - startAutoUseTask(); - } - - public void removeAutoSupplyItem(int itemId) - { - _autoSupplyItems.remove(itemId); - stopAutoUseTask(); - } - - public void addAutoPotionItem(int itemId) - { - _autoPotionItems.add(itemId); - startAutoUseTask(); - } - - public void removeAutoPotionItem(int itemId) - { - _autoPotionItems.remove(itemId); - stopAutoUseTask(); - } - - public void addAutoSkill(int skillId) - { - _autoSkills.add(skillId); - startAutoUseTask(); - } - - public void removeAutoSkill(int skillId) - { - _autoSkills.remove(skillId); - stopAutoUseTask(); + return _autoUseSettings; } public boolean isInTimedHuntingZone() diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java new file mode 100644 index 0000000000..9e2c2ddfd1 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java @@ -0,0 +1,75 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.model.holders; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Mobius + */ +public class AutoPlaySettingsHolder +{ + private final AtomicBoolean _pickup = new AtomicBoolean(); + private final AtomicBoolean _longRange = new AtomicBoolean(); + private final AtomicBoolean _respectfulHunting = new AtomicBoolean(); + private final AtomicInteger _autoPotionPercent = new AtomicInteger(); + + public AutoPlaySettingsHolder() + { + } + + public boolean doPickup() + { + return _pickup.get(); + } + + public void setPickup(boolean value) + { + _pickup.set(value); + } + + public boolean isLongRange() + { + return _longRange.get(); + } + + public void setLongRange(boolean value) + { + _longRange.set(value); + } + + public boolean isRespectfulHunting() + { + return _respectfulHunting.get(); + } + + public void setRespectfulHunting(boolean value) + { + _respectfulHunting.set(value); + } + + public int getAutoPotionPercent() + { + return _autoPotionPercent.get(); + } + + public void setAutoPotionPercent(int value) + { + _autoPotionPercent.set(value); + } +} diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java new file mode 100644 index 0000000000..f48e580ad3 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java @@ -0,0 +1,49 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.model.holders; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Mobius + */ +public class AutoUseSettingsHolder +{ + private final Collection _autoSupplyItems = ConcurrentHashMap.newKeySet(); + private final Collection _autoPotionItems = ConcurrentHashMap.newKeySet(); + private final Collection _autoSkills = ConcurrentHashMap.newKeySet(); + + public AutoUseSettingsHolder() + { + } + + public Collection getAutoSupplyItems() + { + return _autoSupplyItems; + } + + public Collection getAutoPotionItems() + { + return _autoPotionItems; + } + + public Collection getAutoSkills() + { + return _autoSkills; + } +} diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java index 52f699d323..a31c55b419 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java @@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.network.clientpackets; import org.l2jmobius.commons.network.PacketReader; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.network.GameClient; +import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager; /** * @version $Revision: 1.3.4.2 $ $Date: 2005/03/27 15:29:30 $ @@ -57,11 +58,11 @@ public class RequestShortCutDel implements IClientIncomingPacket // Remove auto used ids. if (_slot > 263) { - player.removeAutoSupplyItem(_id); + AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, _id); } else { - player.removeAutoSkill(_id); + AutoUseTaskManager.getInstance().removeAutoSkill(player, _id); } } } diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java index 01cac82682..a134fa82b8 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java @@ -22,6 +22,7 @@ import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.network.GameClient; import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket; import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlaySettingSend; +import org.l2jmobius.gameserver.taskmanager.AutoPlayTaskManager; /** * @author Mobius @@ -59,7 +60,7 @@ public class ExAutoPlaySetting implements IClientIncomingPacket } player.sendPacket(new ExAutoPlaySettingSend(_options, _active, _pickUp, _nextTargetMode, _longRange, _potionPercent, _respectfulHunting)); - player.setAutoPotionPercent(_potionPercent); + player.getAutoPlaySettings().setAutoPotionPercent(_potionPercent); if (!Config.ENABLE_AUTO_PLAY) { @@ -68,11 +69,11 @@ public class ExAutoPlaySetting implements IClientIncomingPacket if (_active) { - player.startAutoPlayTask(_pickUp, _longRange, _respectfulHunting); + AutoPlayTaskManager.getInstance().doAutoPlay(player, _pickUp, _longRange, _respectfulHunting); } else { - player.stopAutoPlayTask(); + AutoPlayTaskManager.getInstance().stopAutoPlay(player); } } } diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java index b9a1b94d74..b845c7d093 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java @@ -25,6 +25,7 @@ import org.l2jmobius.gameserver.model.skills.Skill; import org.l2jmobius.gameserver.network.GameClient; import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket; import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExActivateAutoShortcut; +import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager; /** * @author JoeAlisson, Mobius @@ -75,17 +76,17 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket // auto supply if (_room > 263) { - player.removeAutoSupplyItem(item.getId()); + AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, item.getId()); } else // auto potion { - player.removeAutoPotionItem(item.getId()); + AutoUseTaskManager.getInstance().removeAutoPotionItem(player, item.getId()); } } // auto skill if (skill != null) { - player.removeAutoSkill(skill.getId()); + AutoUseTaskManager.getInstance().removeAutoSkill(player, skill.getId()); } return; } @@ -96,7 +97,7 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket // auto supply if (Config.ENABLE_AUTO_ITEM && (item != null)) { - player.addAutoSupplyItem(item.getId()); + AutoUseTaskManager.getInstance().addAutoSupplyItem(player, item.getId()); } } else @@ -106,14 +107,14 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket { if (Config.ENABLE_AUTO_POTION && (item != null) && item.isPotion()) { - player.addAutoPotionItem(item.getId()); + AutoUseTaskManager.getInstance().addAutoPotionItem(player, item.getId()); return; } } // auto skill if (Config.ENABLE_AUTO_BUFF && (skill != null)) { - player.addAutoSkill(skill.getId()); + AutoUseTaskManager.getInstance().addAutoSkill(player, skill.getId()); } } } diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java new file mode 100644 index 0000000000..685243b58d --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -0,0 +1,170 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.taskmanager; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.items.instance.ItemInstance; +import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro; + +/** + * @author Mobius + */ +public class AutoPlayTaskManager +{ + private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static boolean _working = false; + + public AutoPlayTaskManager() + { + ThreadPool.scheduleAtFixedRate(() -> + { + if (_working) + { + return; + } + _working = true; + + PLAY: for (PlayerInstance player : PLAYERS) + { + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + { + stopAutoPlay(player); + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final MonsterInstance monster = (MonsterInstance) target; + if ((monster.getTarget() == player) && !monster.isAlikeDead()) + { + // Check if actually attacking. + if (player.hasAI() && player.getAI().isAutoAttacking() && !player.isAttackingNow() && !player.isCastingNow()) + { + player.doAutoAttack(monster); + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(player, ItemInstance.class, 200)) + { + // Check if item is reachable. + if ((droppedItem == null) // + || (!droppedItem.isSpawned()) // + || !GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), player.getInstanceWorld())) + { + continue PICKUP; + } + + // Move to item. + if (player.calculateDistance2D(droppedItem) > 50) + { + player.moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0); + continue PLAY; + } + + // Try to pick it up. + if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == player.getObjectId())) + { + player.doPickupItem(droppedItem); + continue PLAY; // Avoid pickup being skipped. + } + } + } + + // Find target. + MonsterInstance monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(player, MonsterInstance.class, player.getAutoPlaySettings().isLongRange() ? 1400 : 600)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player)) + { + continue TARGET; + } + // Check if monster is reachable. + if (nearby.isAutoAttackable(player) // + && GeoEngine.getInstance().canSeeTarget(player, nearby)// + && GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld())) + { + final double monsterDistance = player.calculateDistance2D(nearby); + if (monsterDistance < closestDistance) + { + monster = nearby; + closestDistance = monsterDistance; + } + } + } + + // New target was assigned. + if (monster != null) + { + player.setTarget(monster); + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); + } + } + + _working = false; + }, 1000, 1000); + } + + public void doAutoPlay(PlayerInstance player, boolean pickup, boolean longRange, boolean respectfulHunting) + { + player.getAutoPlaySettings().setPickup(pickup); + player.getAutoPlaySettings().setLongRange(longRange); + player.getAutoPlaySettings().setRespectfulHunting(respectfulHunting); + + if (!PLAYERS.contains(player)) + { + PLAYERS.add(player); + } + } + + public void stopAutoPlay(PlayerInstance player) + { + PLAYERS.remove(player); + } + + public static AutoPlayTaskManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final AutoPlayTaskManager INSTANCE = new AutoPlayTaskManager(); + } +} diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java new file mode 100644 index 0000000000..890f65deb8 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -0,0 +1,222 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.taskmanager; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.handler.IItemHandler; +import org.l2jmobius.gameserver.handler.ItemHandler; +import org.l2jmobius.gameserver.model.actor.Summon; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.ItemSkillHolder; +import org.l2jmobius.gameserver.model.items.EtcItem; +import org.l2jmobius.gameserver.model.items.instance.ItemInstance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.targets.AffectScope; +import org.l2jmobius.gameserver.model.zone.ZoneId; + +/** + * @author Mobius + */ +public class AutoUseTaskManager +{ + private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static boolean _working = false; + + public AutoUseTaskManager() + { + ThreadPool.scheduleAtFixedRate(() -> + { + if (_working) + { + return; + } + _working = true; + + for (PlayerInstance player : PLAYERS) + { + if (!player.isOnline() || player.isInOfflineMode()) + { + stopAutoUseTask(player); + continue; + } + + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isInsideZone(ZoneId.PEACE)) + { + continue; + } + + if (Config.ENABLE_AUTO_ITEM) + { + ITEMS: for (int itemId : player.getAutoUseSettings().getAutoSupplyItems()) + { + final ItemInstance item = player.getInventory().getItemByItemId(itemId); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; // TODO: break? + } + + for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills()) + { + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } + } + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) + { + final EtcItem etcItem = item.getEtcItem(); + final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); + if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0)) + { + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_POTION && (player.getCurrentHpPercent() <= player.getAutoPlaySettings().getAutoPotionPercent())) + { + POTIONS: for (int itemId : player.getAutoUseSettings().getAutoPotionItems()) + { + final ItemInstance item = player.getInventory().getItemByItemId(itemId); + if (item == null) + { + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; // TODO: break? + } + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) + { + final EtcItem etcItem = item.getEtcItem(); + final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); + if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0)) + { + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_BUFF) + { + BUFFS: for (int skillId : player.getAutoUseSettings().getAutoSkills()) + { + final Skill skill = player.getKnownSkill(skillId); + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + continue BUFFS; // TODO: break? + } + if (!player.isAffectedBySkill(skillId) && !player.hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(player, player, false)) + { + // Summon check. + if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) + { + if (!player.hasServitors()) // Is this check truly needed? + { + continue BUFFS; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skillId)) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + continue BUFFS; + } + } + player.doCast(skill); + } + } + } + } + + _working = false; + }, 1000, 1000); + } + + public void startAutoUseTask(PlayerInstance player) + { + if (!PLAYERS.contains(player)) + { + PLAYERS.add(player); + } + } + + public void stopAutoUseTask(PlayerInstance player) + { + PLAYERS.remove(player); + } + + public void addAutoSupplyItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoSupplyItems().add(itemId); + startAutoUseTask(player); + } + + public void removeAutoSupplyItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + stopAutoUseTask(player); + } + + public void addAutoPotionItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoPotionItems().add(itemId); + startAutoUseTask(player); + } + + public void removeAutoPotionItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + stopAutoUseTask(player); + } + + public void addAutoSkill(PlayerInstance player, int skillId) + { + player.getAutoUseSettings().getAutoSkills().add(skillId); + startAutoUseTask(player); + } + + public void removeAutoSkill(PlayerInstance player, int skillId) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + stopAutoUseTask(player); + } + + public static AutoUseTaskManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final AutoUseTaskManager INSTANCE = new AutoUseTaskManager(); + } +} diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 2e10f3123b..d79064ed6b 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -40,7 +40,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.stream.Collectors; @@ -223,10 +222,11 @@ import org.l2jmobius.gameserver.model.events.returns.TerminateReturn; import org.l2jmobius.gameserver.model.events.timers.TimerHolder; import org.l2jmobius.gameserver.model.fishing.Fishing; import org.l2jmobius.gameserver.model.holders.AttendanceInfoHolder; +import org.l2jmobius.gameserver.model.holders.AutoPlaySettingsHolder; +import org.l2jmobius.gameserver.model.holders.AutoUseSettingsHolder; import org.l2jmobius.gameserver.model.holders.DamageTakenHolder; import org.l2jmobius.gameserver.model.holders.ElementalSpiritDataHolder; import org.l2jmobius.gameserver.model.holders.ItemHolder; -import org.l2jmobius.gameserver.model.holders.ItemSkillHolder; import org.l2jmobius.gameserver.model.holders.MovieHolder; import org.l2jmobius.gameserver.model.holders.PlayerEventHolder; import org.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder; @@ -267,7 +267,6 @@ import org.l2jmobius.gameserver.model.skills.CommonSkill; import org.l2jmobius.gameserver.model.skills.Skill; import org.l2jmobius.gameserver.model.skills.SkillCaster; import org.l2jmobius.gameserver.model.skills.SkillCastingType; -import org.l2jmobius.gameserver.model.skills.targets.AffectScope; import org.l2jmobius.gameserver.model.skills.targets.TargetType; import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.Formulas; @@ -348,7 +347,6 @@ import org.l2jmobius.gameserver.network.serverpackets.TradeOtherDone; import org.l2jmobius.gameserver.network.serverpackets.TradeStart; import org.l2jmobius.gameserver.network.serverpackets.UserInfo; import org.l2jmobius.gameserver.network.serverpackets.ValidateLocation; -import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro; import org.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo; import org.l2jmobius.gameserver.network.serverpackets.friend.FriendStatus; import org.l2jmobius.gameserver.network.serverpackets.sessionzones.TimedHuntingZoneExit; @@ -866,15 +864,8 @@ public class PlayerInstance extends Playable private ElementalSpirit[] _spirits; private ElementalType _activeElementalSpiritType; - private ScheduledFuture _autoPlayTask = null; - private ScheduledFuture _autoUseTask = null; - private final AtomicBoolean _pickup = new AtomicBoolean(); - private final AtomicBoolean _longRange = new AtomicBoolean(); - private final AtomicBoolean _respectfulHunting = new AtomicBoolean(); - private final AtomicInteger _autoPotionPercent = new AtomicInteger(); - private final Collection _autoSupplyItems = ConcurrentHashMap.newKeySet(); - private final Collection _autoPotionItems = ConcurrentHashMap.newKeySet(); - private final Collection _autoSkills = ConcurrentHashMap.newKeySet(); + private final AutoPlaySettingsHolder _autoPlaySettings = new AutoPlaySettingsHolder(); + private final AutoUseSettingsHolder _autoUseSettings = new AutoUseSettingsHolder(); private ScheduledFuture _timedHuntingZoneFinishTask = null; @@ -13714,16 +13705,6 @@ public class PlayerInstance extends Playable _autoSaveTask.cancel(false); _autoSaveTask = null; } - if ((_autoPlayTask != null) && !_autoPlayTask.isDone() && !_autoPlayTask.isCancelled()) - { - _autoPlayTask.cancel(false); - _autoPlayTask = null; - } - if ((_autoUseTask != null) && !_autoUseTask.isDone() && !_autoUseTask.isCancelled()) - { - _autoUseTask.cancel(false); - _autoUseTask = null; - } if ((_timedHuntingZoneFinishTask != null) && !_timedHuntingZoneFinishTask.isDone() && !_timedHuntingZoneFinishTask.isCancelled()) { _timedHuntingZoneFinishTask.cancel(false); @@ -14117,274 +14098,14 @@ public class PlayerInstance extends Playable return AttackStanceTaskManager.getInstance().hasAttackStanceTask(this); } - public void stopAutoPlayTask() + public AutoPlaySettingsHolder getAutoPlaySettings() { - if ((_autoPlayTask != null) && !_autoPlayTask.isCancelled() && !_autoPlayTask.isDone()) - { - _autoPlayTask.cancel(true); - _autoPlayTask = null; - } + return _autoPlaySettings; } - public void startAutoPlayTask(boolean pickup, boolean longRange, boolean respectfulHunting) + public AutoUseSettingsHolder getAutoUseSettings() { - _pickup.set(pickup); - _longRange.set(longRange); - _respectfulHunting.set(respectfulHunting); - - if (_autoPlayTask != null) - { - return; - } - - _autoPlayTask = ThreadPool.scheduleAtFixedRate(() -> - { - if (!Config.ENABLE_AUTO_PLAY) - { - stopAutoPlayTask(); - return; - } - - // Skip thinking. - final WorldObject target = getTarget(); - if ((target != null) && target.isMonster()) - { - final MonsterInstance monster = (MonsterInstance) target; - if ((monster.getTarget() == this) && !monster.isAlikeDead()) - { - // Check if actually attacking. - if (hasAI() && getAI().isAutoAttacking() && !isAttackingNow() && !isCastingNow()) - { - doAutoAttack(monster); - } - return; - } - } - - // Pickup. - if (_pickup.get()) - { - for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(this, ItemInstance.class, 200)) - { - // Check if item is reachable. - if ((droppedItem == null) // - || (!droppedItem.isSpawned()) // - || !GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), getInstanceWorld())) - { - continue; - } - - // Move to item. - if (calculateDistance2D(droppedItem) > 50) - { - moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0); - return; - } - - // Try to pick it up. - if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == getObjectId())) - { - doPickupItem(droppedItem); - return; // Avoid pickup being skipped. - } - } - } - - // Find target. - MonsterInstance monster = null; - double closestDistance = Double.MAX_VALUE; - for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(this, MonsterInstance.class, _longRange.get() ? 1400 : 600)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue; - } - // Check monster target. - if (_respectfulHunting.get() && (nearby.getTarget() != null) && (nearby.getTarget() != this)) - { - continue; - } - // Check if monster is reachable. - if (nearby.isAutoAttackable(this) // - && GeoEngine.getInstance().canSeeTarget(this, nearby)// - && GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), getInstanceWorld())) - { - final double monsterDistance = calculateDistance2D(nearby); - if (monsterDistance < closestDistance) - { - monster = nearby; - closestDistance = monsterDistance; - } - } - } - - // New target was assigned. - if (monster != null) - { - setTarget(monster); - sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } - }, 0, 1000); - } - - public void stopAutoUseTask() - { - if ((_autoUseTask != null) && !_autoUseTask.isCancelled() && !_autoUseTask.isDone()) - { - _autoUseTask.cancel(true); - _autoUseTask = null; - } - } - - private void startAutoUseTask() - { - if (_autoUseTask != null) - { - return; - } - - _autoUseTask = ThreadPool.scheduleAtFixedRate(() -> - { - if (hasBlockActions() || isControlBlocked() || isAlikeDead() || isInsideZone(ZoneId.PEACE)) - { - return; - } - - if (Config.ENABLE_AUTO_ITEM) - { - ITEMS: for (int itemId : _autoSupplyItems) - { - final ItemInstance item = _inventory.getItemByItemId(itemId); - if (item == null) - { - removeAutoSupplyItem(itemId); - continue; - } - - for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills()) - { - final Skill skill = itemSkillHolder.getSkill(); - if (isAffectedBySkill(skill.getId()) || hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(this, this, false)) - { - continue ITEMS; - } - } - - final int reuseDelay = item.getReuseDelay(); - if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0)) - { - final EtcItem etcItem = item.getEtcItem(); - final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); - if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0)) - { - addTimeStampItem(item, reuseDelay); - } - } - } - } - - if (Config.ENABLE_AUTO_POTION && (getCurrentHpPercent() <= _autoPotionPercent.get())) - { - for (int itemId : _autoPotionItems) - { - final ItemInstance item = _inventory.getItemByItemId(itemId); - if (item == null) - { - removeAutoPotionItem(itemId); - continue; - } - final int reuseDelay = item.getReuseDelay(); - if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0)) - { - final EtcItem etcItem = item.getEtcItem(); - final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); - if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0)) - { - addTimeStampItem(item, reuseDelay); - } - } - } - } - - if (Config.ENABLE_AUTO_BUFF) - { - for (int skillId : _autoSkills) - { - final Skill skill = getKnownSkill(skillId); - if (skill == null) - { - removeAutoSkill(skillId); - continue; - } - if (!isAffectedBySkill(skillId) && !hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(this, this, false)) - { - // Summon check. - if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) - { - if (!hasServitors()) // Is this check truly needed? - { - continue; - } - int occurrences = 0; - for (Summon servitor : _servitors.values()) - { - if (servitor.isAffectedBySkill(skillId)) - { - occurrences++; - } - } - if (occurrences == _servitors.size()) - { - continue; - } - } - doCast(skill); - } - } - } - }, 0, 1000); - } - - public void setAutoPotionPercent(int value) - { - _autoPotionPercent.set(value); - } - - public void addAutoSupplyItem(int itemId) - { - _autoSupplyItems.add(itemId); - startAutoUseTask(); - } - - public void removeAutoSupplyItem(int itemId) - { - _autoSupplyItems.remove(itemId); - stopAutoUseTask(); - } - - public void addAutoPotionItem(int itemId) - { - _autoPotionItems.add(itemId); - startAutoUseTask(); - } - - public void removeAutoPotionItem(int itemId) - { - _autoPotionItems.remove(itemId); - stopAutoUseTask(); - } - - public void addAutoSkill(int skillId) - { - _autoSkills.add(skillId); - startAutoUseTask(); - } - - public void removeAutoSkill(int skillId) - { - _autoSkills.remove(skillId); - stopAutoUseTask(); + return _autoUseSettings; } public boolean isInTimedHuntingZone() diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java new file mode 100644 index 0000000000..9e2c2ddfd1 --- /dev/null +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoPlaySettingsHolder.java @@ -0,0 +1,75 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.model.holders; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Mobius + */ +public class AutoPlaySettingsHolder +{ + private final AtomicBoolean _pickup = new AtomicBoolean(); + private final AtomicBoolean _longRange = new AtomicBoolean(); + private final AtomicBoolean _respectfulHunting = new AtomicBoolean(); + private final AtomicInteger _autoPotionPercent = new AtomicInteger(); + + public AutoPlaySettingsHolder() + { + } + + public boolean doPickup() + { + return _pickup.get(); + } + + public void setPickup(boolean value) + { + _pickup.set(value); + } + + public boolean isLongRange() + { + return _longRange.get(); + } + + public void setLongRange(boolean value) + { + _longRange.set(value); + } + + public boolean isRespectfulHunting() + { + return _respectfulHunting.get(); + } + + public void setRespectfulHunting(boolean value) + { + _respectfulHunting.set(value); + } + + public int getAutoPotionPercent() + { + return _autoPotionPercent.get(); + } + + public void setAutoPotionPercent(int value) + { + _autoPotionPercent.set(value); + } +} diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java new file mode 100644 index 0000000000..f48e580ad3 --- /dev/null +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/holders/AutoUseSettingsHolder.java @@ -0,0 +1,49 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.model.holders; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Mobius + */ +public class AutoUseSettingsHolder +{ + private final Collection _autoSupplyItems = ConcurrentHashMap.newKeySet(); + private final Collection _autoPotionItems = ConcurrentHashMap.newKeySet(); + private final Collection _autoSkills = ConcurrentHashMap.newKeySet(); + + public AutoUseSettingsHolder() + { + } + + public Collection getAutoSupplyItems() + { + return _autoSupplyItems; + } + + public Collection getAutoPotionItems() + { + return _autoPotionItems; + } + + public Collection getAutoSkills() + { + return _autoSkills; + } +} diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java index 52f699d323..a31c55b419 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/RequestShortCutDel.java @@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.network.clientpackets; import org.l2jmobius.commons.network.PacketReader; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.network.GameClient; +import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager; /** * @version $Revision: 1.3.4.2 $ $Date: 2005/03/27 15:29:30 $ @@ -57,11 +58,11 @@ public class RequestShortCutDel implements IClientIncomingPacket // Remove auto used ids. if (_slot > 263) { - player.removeAutoSupplyItem(_id); + AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, _id); } else { - player.removeAutoSkill(_id); + AutoUseTaskManager.getInstance().removeAutoSkill(player, _id); } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java index 01cac82682..a134fa82b8 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExAutoPlaySetting.java @@ -22,6 +22,7 @@ import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.network.GameClient; import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket; import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlaySettingSend; +import org.l2jmobius.gameserver.taskmanager.AutoPlayTaskManager; /** * @author Mobius @@ -59,7 +60,7 @@ public class ExAutoPlaySetting implements IClientIncomingPacket } player.sendPacket(new ExAutoPlaySettingSend(_options, _active, _pickUp, _nextTargetMode, _longRange, _potionPercent, _respectfulHunting)); - player.setAutoPotionPercent(_potionPercent); + player.getAutoPlaySettings().setAutoPotionPercent(_potionPercent); if (!Config.ENABLE_AUTO_PLAY) { @@ -68,11 +69,11 @@ public class ExAutoPlaySetting implements IClientIncomingPacket if (_active) { - player.startAutoPlayTask(_pickUp, _longRange, _respectfulHunting); + AutoPlayTaskManager.getInstance().doAutoPlay(player, _pickUp, _longRange, _respectfulHunting); } else { - player.stopAutoPlayTask(); + AutoPlayTaskManager.getInstance().stopAutoPlay(player); } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java index b9a1b94d74..b845c7d093 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/clientpackets/autoplay/ExRequestActivateAutoShortcut.java @@ -25,6 +25,7 @@ import org.l2jmobius.gameserver.model.skills.Skill; import org.l2jmobius.gameserver.network.GameClient; import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket; import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExActivateAutoShortcut; +import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager; /** * @author JoeAlisson, Mobius @@ -75,17 +76,17 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket // auto supply if (_room > 263) { - player.removeAutoSupplyItem(item.getId()); + AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, item.getId()); } else // auto potion { - player.removeAutoPotionItem(item.getId()); + AutoUseTaskManager.getInstance().removeAutoPotionItem(player, item.getId()); } } // auto skill if (skill != null) { - player.removeAutoSkill(skill.getId()); + AutoUseTaskManager.getInstance().removeAutoSkill(player, skill.getId()); } return; } @@ -96,7 +97,7 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket // auto supply if (Config.ENABLE_AUTO_ITEM && (item != null)) { - player.addAutoSupplyItem(item.getId()); + AutoUseTaskManager.getInstance().addAutoSupplyItem(player, item.getId()); } } else @@ -106,14 +107,14 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket { if (Config.ENABLE_AUTO_POTION && (item != null) && item.isPotion()) { - player.addAutoPotionItem(item.getId()); + AutoUseTaskManager.getInstance().addAutoPotionItem(player, item.getId()); return; } } // auto skill if (Config.ENABLE_AUTO_BUFF && (skill != null)) { - player.addAutoSkill(skill.getId()); + AutoUseTaskManager.getInstance().addAutoSkill(player, skill.getId()); } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java new file mode 100644 index 0000000000..685243b58d --- /dev/null +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -0,0 +1,170 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.taskmanager; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.items.instance.ItemInstance; +import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro; + +/** + * @author Mobius + */ +public class AutoPlayTaskManager +{ + private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static boolean _working = false; + + public AutoPlayTaskManager() + { + ThreadPool.scheduleAtFixedRate(() -> + { + if (_working) + { + return; + } + _working = true; + + PLAY: for (PlayerInstance player : PLAYERS) + { + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + { + stopAutoPlay(player); + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final MonsterInstance monster = (MonsterInstance) target; + if ((monster.getTarget() == player) && !monster.isAlikeDead()) + { + // Check if actually attacking. + if (player.hasAI() && player.getAI().isAutoAttacking() && !player.isAttackingNow() && !player.isCastingNow()) + { + player.doAutoAttack(monster); + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(player, ItemInstance.class, 200)) + { + // Check if item is reachable. + if ((droppedItem == null) // + || (!droppedItem.isSpawned()) // + || !GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), player.getInstanceWorld())) + { + continue PICKUP; + } + + // Move to item. + if (player.calculateDistance2D(droppedItem) > 50) + { + player.moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0); + continue PLAY; + } + + // Try to pick it up. + if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == player.getObjectId())) + { + player.doPickupItem(droppedItem); + continue PLAY; // Avoid pickup being skipped. + } + } + } + + // Find target. + MonsterInstance monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(player, MonsterInstance.class, player.getAutoPlaySettings().isLongRange() ? 1400 : 600)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player)) + { + continue TARGET; + } + // Check if monster is reachable. + if (nearby.isAutoAttackable(player) // + && GeoEngine.getInstance().canSeeTarget(player, nearby)// + && GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld())) + { + final double monsterDistance = player.calculateDistance2D(nearby); + if (monsterDistance < closestDistance) + { + monster = nearby; + closestDistance = monsterDistance; + } + } + } + + // New target was assigned. + if (monster != null) + { + player.setTarget(monster); + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); + } + } + + _working = false; + }, 1000, 1000); + } + + public void doAutoPlay(PlayerInstance player, boolean pickup, boolean longRange, boolean respectfulHunting) + { + player.getAutoPlaySettings().setPickup(pickup); + player.getAutoPlaySettings().setLongRange(longRange); + player.getAutoPlaySettings().setRespectfulHunting(respectfulHunting); + + if (!PLAYERS.contains(player)) + { + PLAYERS.add(player); + } + } + + public void stopAutoPlay(PlayerInstance player) + { + PLAYERS.remove(player); + } + + public static AutoPlayTaskManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final AutoPlayTaskManager INSTANCE = new AutoPlayTaskManager(); + } +} diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java new file mode 100644 index 0000000000..890f65deb8 --- /dev/null +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -0,0 +1,222 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.taskmanager; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.handler.IItemHandler; +import org.l2jmobius.gameserver.handler.ItemHandler; +import org.l2jmobius.gameserver.model.actor.Summon; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.ItemSkillHolder; +import org.l2jmobius.gameserver.model.items.EtcItem; +import org.l2jmobius.gameserver.model.items.instance.ItemInstance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.targets.AffectScope; +import org.l2jmobius.gameserver.model.zone.ZoneId; + +/** + * @author Mobius + */ +public class AutoUseTaskManager +{ + private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static boolean _working = false; + + public AutoUseTaskManager() + { + ThreadPool.scheduleAtFixedRate(() -> + { + if (_working) + { + return; + } + _working = true; + + for (PlayerInstance player : PLAYERS) + { + if (!player.isOnline() || player.isInOfflineMode()) + { + stopAutoUseTask(player); + continue; + } + + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isInsideZone(ZoneId.PEACE)) + { + continue; + } + + if (Config.ENABLE_AUTO_ITEM) + { + ITEMS: for (int itemId : player.getAutoUseSettings().getAutoSupplyItems()) + { + final ItemInstance item = player.getInventory().getItemByItemId(itemId); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; // TODO: break? + } + + for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills()) + { + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } + } + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) + { + final EtcItem etcItem = item.getEtcItem(); + final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); + if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0)) + { + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_POTION && (player.getCurrentHpPercent() <= player.getAutoPlaySettings().getAutoPotionPercent())) + { + POTIONS: for (int itemId : player.getAutoUseSettings().getAutoPotionItems()) + { + final ItemInstance item = player.getInventory().getItemByItemId(itemId); + if (item == null) + { + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; // TODO: break? + } + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) + { + final EtcItem etcItem = item.getEtcItem(); + final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem); + if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0)) + { + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_BUFF) + { + BUFFS: for (int skillId : player.getAutoUseSettings().getAutoSkills()) + { + final Skill skill = player.getKnownSkill(skillId); + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + continue BUFFS; // TODO: break? + } + if (!player.isAffectedBySkill(skillId) && !player.hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(player, player, false)) + { + // Summon check. + if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) + { + if (!player.hasServitors()) // Is this check truly needed? + { + continue BUFFS; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skillId)) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + continue BUFFS; + } + } + player.doCast(skill); + } + } + } + } + + _working = false; + }, 1000, 1000); + } + + public void startAutoUseTask(PlayerInstance player) + { + if (!PLAYERS.contains(player)) + { + PLAYERS.add(player); + } + } + + public void stopAutoUseTask(PlayerInstance player) + { + PLAYERS.remove(player); + } + + public void addAutoSupplyItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoSupplyItems().add(itemId); + startAutoUseTask(player); + } + + public void removeAutoSupplyItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + stopAutoUseTask(player); + } + + public void addAutoPotionItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoPotionItems().add(itemId); + startAutoUseTask(player); + } + + public void removeAutoPotionItem(PlayerInstance player, int itemId) + { + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + stopAutoUseTask(player); + } + + public void addAutoSkill(PlayerInstance player, int skillId) + { + player.getAutoUseSettings().getAutoSkills().add(skillId); + startAutoUseTask(player); + } + + public void removeAutoSkill(PlayerInstance player, int skillId) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + stopAutoUseTask(player); + } + + public static AutoUseTaskManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final AutoUseTaskManager INSTANCE = new AutoUseTaskManager(); + } +}