From 99c556eade5f3bb8a3dfa3ed900233925dd94320 Mon Sep 17 00:00:00 2001 From: MobiusDevelopment <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sat, 22 Oct 2022 00:14:41 +0000 Subject: [PATCH] Addition of AutoPlay and AutoUse task pools. --- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 350 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 350 +++++---- .../taskmanager/AutoUseTaskManager.java | 641 ++++++++-------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 705 +++++++++--------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 705 +++++++++--------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 705 +++++++++--------- .../taskmanager/AutoPlayTaskManager.java | 360 +++++---- .../taskmanager/AutoUseTaskManager.java | 705 +++++++++--------- 22 files changed, 5937 insertions(+), 5310 deletions(-) diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index f3c3ad4991..a46e5a6985 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,212 +38,244 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // Iss classes considered fighters. + final int classId = player.getActiveClass(); + if ((classId > 170) && (classId < 176)) + { + return false; + } + + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // Iss classes considered fighters. - final int classId = player.getActiveClass(); - if ((classId > 170) && (classId < 176)) + for (Set pool : POOLS) { - return false; + if (pool.contains(player)) + { + return true; + } } - - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index f3c3ad4991..a46e5a6985 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,212 +38,244 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // Iss classes considered fighters. + final int classId = player.getActiveClass(); + if ((classId > 170) && (classId < 176)) + { + return false; + } + + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // Iss classes considered fighters. - final int classId = player.getActiveClass(); - if ((classId > 170) && (classId < 176)) + for (Set pool : POOLS) { - return false; + if (pool.contains(player)) + { + return true; + } } - - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index f3c3ad4991..a46e5a6985 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,212 +38,244 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // Iss classes considered fighters. + final int classId = player.getActiveClass(); + if ((classId > 170) && (classId < 176)) + { + return false; + } + + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // Iss classes considered fighters. - final int classId = player.getActiveClass(); - if ((classId > 170) && (classId < 176)) + for (Set pool : POOLS) { - return false; + if (pool.contains(player)) + { + return true; + } } - - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index f3c3ad4991..a46e5a6985 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,212 +38,244 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // Iss classes considered fighters. + final int classId = player.getActiveClass(); + if ((classId > 170) && (classId < 176)) + { + return false; + } + + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // Iss classes considered fighters. - final int classId = player.getActiveClass(); - if ((classId > 170) && (classId < 176)) + for (Set pool : POOLS) { - return false; + if (pool.contains(player)) + { + return true; + } } - - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index f3c3ad4991..a46e5a6985 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,212 +38,244 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // Iss classes considered fighters. + final int classId = player.getActiveClass(); + if ((classId > 170) && (classId < 176)) + { + return false; + } + + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // Iss classes considered fighters. - final int classId = player.getActiveClass(); - if ((classId > 170) && (classId < 176)) + for (Set pool : POOLS) { - return false; + if (pool.contains(player)) + { + return true; + } } - - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index b6f19781ed..e4a0e4632d 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,205 +38,237 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - return player.isMageClass() && (player.getRace() != Race.ORC); + for (Set pool : POOLS) + { + if (pool.contains(player)) + { + return true; + } + } + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index d5c1bd05f3..b5fe7ed877 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } 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 index b6f19781ed..e4a0e4632d 100644 --- 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 @@ -38,205 +38,237 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); - private static boolean _working = false; + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - return player.isMageClass() && (player.getRace() != Race.ORC); + for (Set pool : POOLS) + { + if (pool.contains(player)) + { + return true; + } + } + return false; } public static AutoPlayTaskManager getInstance() 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 index d5c1bd05f3..b5fe7ed877 100644 --- 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 @@ -53,383 +53,402 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -437,7 +456,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index 2159e88ba6..cc71782c45 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,213 +38,245 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final Integer AUTO_ATTACK_ACTION = 2; - private static boolean _working = false; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // On Essence auto attack is enabled via the Auto Attack action. + if (Config.AUTO_PLAY_ATTACK_ACTION) + { + return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + } + + // Non Essence like. + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // On Essence auto attack is enabled via the Auto Attack action. - if (Config.AUTO_PLAY_ATTACK_ACTION) + for (Set pool : POOLS) { - return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + if (pool.contains(player)) + { + return true; + } } - - // Non Essence like. - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index ff8798caf5..883d77a086 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -54,415 +54,434 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_PET_POTION && !isInPeaceZone) - { - final Pet pet = player.getPet(); - if ((pet != null) && !pet.isDead()) - { - final int percent = pet.getCurrentHpPercent(); - if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_PET_POTION && !isInPeaceZone) + { + final Pet pet = player.getPet(); + if ((pet != null) && !pet.isDead()) + { + final int percent = pet.getCurrentHpPercent(); + if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) + { + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) + { + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); + continue POTIONS; + } + + 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_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -470,7 +489,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index 2159e88ba6..cc71782c45 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,213 +38,245 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final Integer AUTO_ATTACK_ACTION = 2; - private static boolean _working = false; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // On Essence auto attack is enabled via the Auto Attack action. + if (Config.AUTO_PLAY_ATTACK_ACTION) + { + return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + } + + // Non Essence like. + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // On Essence auto attack is enabled via the Auto Attack action. - if (Config.AUTO_PLAY_ATTACK_ACTION) + for (Set pool : POOLS) { - return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + if (pool.contains(player)) + { + return true; + } } - - // Non Essence like. - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index ff8798caf5..883d77a086 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -54,415 +54,434 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_PET_POTION && !isInPeaceZone) - { - final Pet pet = player.getPet(); - if ((pet != null) && !pet.isDead()) - { - final int percent = pet.getCurrentHpPercent(); - if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_PET_POTION && !isInPeaceZone) + { + final Pet pet = player.getPet(); + if ((pet != null) && !pet.isDead()) + { + final int percent = pet.getCurrentHpPercent(); + if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) + { + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) + { + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); + continue POTIONS; + } + + 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_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -470,7 +489,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index 2159e88ba6..cc71782c45 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,213 +38,245 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final Integer AUTO_ATTACK_ACTION = 2; - private static boolean _working = false; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // On Essence auto attack is enabled via the Auto Attack action. + if (Config.AUTO_PLAY_ATTACK_ACTION) + { + return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + } + + // Non Essence like. + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // On Essence auto attack is enabled via the Auto Attack action. - if (Config.AUTO_PLAY_ATTACK_ACTION) + for (Set pool : POOLS) { - return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + if (pool.contains(player)) + { + return true; + } } - - // Non Essence like. - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index ff8798caf5..883d77a086 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -54,415 +54,434 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_PET_POTION && !isInPeaceZone) - { - final Pet pet = player.getPet(); - if ((pet != null) && !pet.isDead()) - { - final int percent = pet.getCurrentHpPercent(); - if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_PET_POTION && !isInPeaceZone) + { + final Pet pet = player.getPet(); + if ((pet != null) && !pet.isDead()) + { + final int percent = pet.getCurrentHpPercent(); + if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) + { + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) + { + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); + continue POTIONS; + } + + 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_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -470,7 +489,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } } diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java index 2159e88ba6..cc71782c45 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoPlayTaskManager.java @@ -38,213 +38,245 @@ import org.l2jmobius.gameserver.util.Util; /** * @author Mobius */ -public class AutoPlayTaskManager implements Runnable +public class AutoPlayTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final Integer AUTO_ATTACK_ACTION = 2; - private static boolean _working = false; protected AutoPlayTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoPlay implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - PLAY: for (Player player : PLAYERS) + public AutoPlay(Set players) { - if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) + _players = players; + } + + @Override + public void run() + { + PLAY: for (Player player : _players) { - stopAutoPlay(player); - continue PLAY; - } - - if (player.isCastingNow() || (player.getQueuedSkill() != null)) - { - continue PLAY; - } - - // Skip thinking. - final WorldObject target = player.getTarget(); - if ((target != null) && target.isMonster()) - { - final Monster monster = (Monster) target; - if (monster.isAlikeDead()) + if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY) { - player.setTarget(null); + stopAutoPlay(player); + continue PLAY; } - else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + + if (player.isCastingNow() || (player.getQueuedSkill() != null)) { + continue PLAY; + } + + // Skip thinking. + final WorldObject target = player.getTarget(); + if ((target != null) && target.isMonster()) + { + final Monster monster = (Monster) target; + if (monster.isAlikeDead()) + { + player.setTarget(null); + } + else if ((monster.getTarget() == player) || (monster.getTarget() == null)) + { + // We take granted that mage classes do not auto hit. + if (isMageCaster(player)) + { + continue PLAY; + } + + // Check if actually attacking. + if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) + { + if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); + } + else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) + { + final Weapon weapon = player.getActiveWeaponItem(); + if (weapon != null) + { + final boolean ranged = weapon.getItemType().isRanged(); + final double angle = Util.calculateHeadingFrom(player, monster); + final double radian = Math.toRadians(angle); + final double course = Math.toRadians(180); + final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; + final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); + final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); + final Location location; + if (ranged) + { + location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); + } + else + { + location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); + } + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); + } + } + } + continue PLAY; + } + } + + // Pickup. + if (player.getAutoPlaySettings().doPickup()) + { + PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) + { + if (!player.isMoving()) + { + player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); + } + 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. + Monster monster = null; + double closestDistance = Double.MAX_VALUE; + TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) + { + // Skip unavailable monsters. + if ((nearby == null) || nearby.isAlikeDead()) + { + continue TARGET; + } + // Check monster target. + if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) + { + 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); + // We take granted that mage classes do not auto hit. if (isMageCaster(player)) { continue PLAY; } - // Check if actually attacking. - if (player.hasAI() && !player.isAttackingNow() && !player.isCastingNow() && !player.isMoving() && !player.isDisabled()) - { - if (player.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, monster); - } - else if (monster.hasAI() && !monster.getAI().isAutoAttacking()) - { - final Weapon weapon = player.getActiveWeaponItem(); - if (weapon != null) - { - final boolean ranged = weapon.getItemType().isRanged(); - final double angle = Util.calculateHeadingFrom(player, monster); - final double radian = Math.toRadians(angle); - final double course = Math.toRadians(180); - final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + monster.getCollisionRadius()) * 2; - final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance); - final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance); - final Location location; - if (ranged) - { - location = new Location(player.getX() + x1, player.getY() + y1, player.getZ()); - } - else - { - location = new Location(monster.getX() + x1, monster.getY() + y1, player.getZ()); - } - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location); - } - } - } - continue PLAY; + player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); } } - - // Pickup. - if (player.getAutoPlaySettings().doPickup()) - { - PICKUP: for (Item droppedItem : World.getInstance().getVisibleObjectsInRange(player, Item.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) > 70) - { - if (!player.isMoving()) - { - player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, droppedItem); - } - 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. - Monster monster = null; - double closestDistance = Double.MAX_VALUE; - TARGET: for (Monster nearby : World.getInstance().getVisibleObjectsInRange(player, Monster.class, player.getAutoPlaySettings().isShortRange() ? 600 : 1400)) - { - // Skip unavailable monsters. - if ((nearby == null) || nearby.isAlikeDead()) - { - continue TARGET; - } - // Check monster target. - if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId())) - { - 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); - - // We take granted that mage classes do not auto hit. - if (isMageCaster(player)) - { - continue PLAY; - } - - player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET); - } } - _working = false; + private boolean isMageCaster(Player player) + { + // On Essence auto attack is enabled via the Auto Attack action. + if (Config.AUTO_PLAY_ATTACK_ACTION) + { + return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + } + + // Non Essence like. + return player.isMageClass() && (player.getRace() != Race.ORC); + } } - public void doAutoPlay(Player player) + public synchronized void doAutoPlay(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - player.onActionRequest(); - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + player.onActionRequest(); + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + player.onActionRequest(); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoPlay(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoPlay(Player player) { - PLAYERS.remove(player); - - // Pets must follow their owner. - if (player.hasServitors()) + for (Set pool : POOLS) { - for (Summon summon : player.getServitors().values()) + if (pool.remove(player)) { - summon.followOwner(); + // Pets must follow their owner. + if (player.hasServitors()) + { + for (Summon summon : player.getServitors().values()) + { + summon.followOwner(); + } + } + if (player.hasPet()) + { + player.getPet().followOwner(); + } + return; } } - if (player.hasPet()) - { - player.getPet().followOwner(); - } } public boolean isAutoPlay(Player player) { - return PLAYERS.contains(player); - } - - private boolean isMageCaster(Player player) - { - // On Essence auto attack is enabled via the Auto Attack action. - if (Config.AUTO_PLAY_ATTACK_ACTION) + for (Set pool : POOLS) { - return !player.getAutoUseSettings().getAutoActions().contains(AUTO_ATTACK_ACTION); + if (pool.contains(player)) + { + return true; + } } - - // Non Essence like. - return player.isMageClass() && (player.getRace() != Race.ORC); + return false; } public static AutoPlayTaskManager getInstance() diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java index ff8798caf5..883d77a086 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/taskmanager/AutoUseTaskManager.java @@ -54,415 +54,434 @@ import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList; /** * @author Mobius */ -public class AutoUseTaskManager implements Runnable +public class AutoUseTaskManager { - private static final Set PLAYERS = ConcurrentHashMap.newKeySet(); + private static final Set> POOLS = ConcurrentHashMap.newKeySet(); + private static final int POOL_SIZE = 300; + private static final int TASK_DELAY = 300; private static final int REUSE_MARGIN_TIME = 3; - private static boolean _working = false; protected AutoUseTaskManager() { - ThreadPool.scheduleAtFixedRate(this, 500, 500); } - @Override - public void run() + private class AutoUse implements Runnable { - if (_working) - { - return; - } - _working = true; + private final Set _players; - for (Player player : PLAYERS) + public AutoUse(Set players) { - if (!player.isOnline() || player.isInOfflineMode()) + _players = players; + } + + @Override + public void run() + { + for (Player player : _players) { - stopAutoUseTask(player); - continue; - } - - if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) - { - continue; - } - - final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); - - if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) - { - ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) + if (!player.isOnline() || player.isInOfflineMode()) { - if (player.isTeleporting()) - { - break ITEMS; - } - - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); - continue ITEMS; - } - - final ItemTemplate it = item.getTemplate(); - if (it != null) - { - if (!it.checkCondition(player, player, false)) - { - continue ITEMS; - } - - final List skills = it.getAllSkills(); - if (skills != null) - { - for (ItemSkillHolder itemSkillHolder : skills) - { - 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 && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPotionItems().remove(itemId); - continue POTIONS; - } - - 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_PET_POTION && !isInPeaceZone) - { - final Pet pet = player.getPet(); - if ((pet != null) && !pet.isDead()) - { - final int percent = pet.getCurrentHpPercent(); - if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) - { - POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) - { - final Item item = player.getInventory().getItemByItemId(itemId.intValue()); - if (item == null) - { - player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); - continue POTIONS; - } - - 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_SKILL) - { - BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) - { - // Fixes start area issue. - if (isInPeaceZone) - { - break BUFFS; - } - - // Already casting. - if (player.isCastingNow()) - { - break BUFFS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break BUFFS; - } - - Playable pet = null; - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) - { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) - { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) - { - pet = summon; - break SUMMON_SEARCH; - } - } - } - if ((skill == null) && player.hasPet()) - { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); - } - if (skill == null) - { - player.getAutoUseSettings().getAutoBuffs().remove(skillId); - continue BUFFS; - } - } - - final WorldObject target = player.getTarget(); - if (canCastBuff(player, target, skill)) - { - ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId())) - { - skill = holder.getSkill(); - break ATTACH_SEARCH; - } - } - - // Playable target cast. - final Playable caster = pet != null ? pet : player; - if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) - { - caster.doCast(skill); - } - else // Target self, cast and re-target. - { - final WorldObject savedTarget = target; - caster.setTarget(caster); - caster.doCast(skill); - caster.setTarget(savedTarget); - } - } + stopAutoUseTask(player); + continue; } - // Continue when auto play is not enabled. - if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) + if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isMounted() || (player.isTransformed() && player.getTransformation().get().isRiding())) { continue; } - SKILLS: + final boolean isInPeaceZone = player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.SAYUNE); + + if (Config.ENABLE_AUTO_ITEM && !isInPeaceZone) { - // Already casting. - if (player.isCastingNow()) + ITEMS: for (Integer itemId : player.getAutoUseSettings().getAutoSupplyItems()) { - break SKILLS; - } - - // Player is teleporting. - if (player.isTeleporting()) - { - break SKILLS; - } - - // Acquire next skill. - Playable pet = null; - final Integer skillId = player.getAutoUseSettings().getNextSkillId(); - Skill skill = player.getKnownSkill(skillId.intValue()); - if (skill == null) - { - if (player.hasServitors()) + if (player.isTeleporting()) { - SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + break ITEMS; + } + + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoSupplyItems().remove(itemId); + continue ITEMS; + } + + final ItemTemplate it = item.getTemplate(); + if (it != null) + { + if (!it.checkCondition(player, player, false)) { - skill = summon.getKnownSkill(skillId.intValue()); - if (skill != null) + continue ITEMS; + } + + final List skills = it.getAllSkills(); + if (skills != null) + { + for (ItemSkillHolder itemSkillHolder : skills) { - pet = summon; - break SUMMON_SEARCH; + final Skill skill = itemSkillHolder.getSkill(); + if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false)) + { + continue ITEMS; + } } } } - if ((skill == null) && player.hasPet()) + + final int reuseDelay = item.getReuseDelay(); + if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0)) { - pet = player.getPet(); - skill = pet.getKnownSkill(skillId.intValue()); + 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 (skill == null) - { - player.getAutoUseSettings().getAutoSkills().remove(skillId); - player.getAutoUseSettings().resetSkillOrder(); - break SKILLS; - } - } - - // Casting on self stops movement. - final WorldObject target = player.getTarget(); - if (target == player) - { - break SKILLS; - } - - // Check bad skill target. - if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) - { - break SKILLS; - } - - // Do not attack guards. - if (target instanceof Guard) - { - break SKILLS; - } - - if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) - { - player.getAutoUseSettings().incrementSkillOrder(); } } - ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) + if (Config.ENABLE_AUTO_POTION && !isInPeaceZone && (player.getCurrentHpPercent() < player.getAutoPlaySettings().getAutoPotionPercent())) { - final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); - if (info != null) + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPotionItems()) { - for (AbstractEffect effect : info.getEffects()) + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) { - if (!effect.checkCondition(actionId)) + player.getAutoUseSettings().getAutoPotionItems().remove(itemId); + continue POTIONS; + } + + 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.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); - break ACTIONS; + player.addTimeStampItem(item, reuseDelay); + } + } + } + } + + if (Config.ENABLE_AUTO_PET_POTION && !isInPeaceZone) + { + final Pet pet = player.getPet(); + if ((pet != null) && !pet.isDead()) + { + final int percent = pet.getCurrentHpPercent(); + if ((percent < 100) && (percent <= player.getAutoPlaySettings().getAutoPetPotionPercent())) + { + POTIONS: for (Integer itemId : player.getAutoUseSettings().getAutoPetPotionItems()) + { + final Item item = player.getInventory().getItemByItemId(itemId.intValue()); + if (item == null) + { + player.getAutoUseSettings().getAutoPetPotionItems().remove(itemId); + continue POTIONS; + } + + 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_SKILL) + { + BUFFS: for (Integer skillId : player.getAutoUseSettings().getAutoBuffs()) + { + // Fixes start area issue. + if (isInPeaceZone) + { + break BUFFS; + } + + // Already casting. + if (player.isCastingNow()) + { + break BUFFS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break BUFFS; + } + + Playable pet = null; + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoBuffs().remove(skillId); + continue BUFFS; + } + } + + final WorldObject target = player.getTarget(); + if (canCastBuff(player, target, skill)) + { + ATTACH_SEARCH: for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId())) + { + skill = holder.getSkill(); + break ATTACH_SEARCH; + } + } + + // Playable target cast. + final Playable caster = pet != null ? pet : player; + if ((target != null) && target.isPlayable() && (target.getActingPlayer().getPvpFlag() == 0) && (target.getActingPlayer().getReputation() >= 0)) + { + caster.doCast(skill); + } + else // Target self, cast and re-target. + { + final WorldObject savedTarget = target; + caster.setTarget(caster); + caster.doCast(skill); + caster.setTarget(savedTarget); } } } - // Do not allow to do some action if player is transformed. - if (player.isTransformed()) + // Continue when auto play is not enabled. + if (!AutoPlayTaskManager.getInstance().isAutoPlay(player)) { - final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; - if (Arrays.binarySearch(allowedActions, actionId) < 0) + continue; + } + + SKILLS: + { + // Already casting. + if (player.isCastingNow()) { - continue ACTIONS; + break SKILLS; + } + + // Player is teleporting. + if (player.isTeleporting()) + { + break SKILLS; + } + + // Acquire next skill. + Playable pet = null; + final Integer skillId = player.getAutoUseSettings().getNextSkillId(); + Skill skill = player.getKnownSkill(skillId.intValue()); + if (skill == null) + { + if (player.hasServitors()) + { + SUMMON_SEARCH: for (Summon summon : player.getServitors().values()) + { + skill = summon.getKnownSkill(skillId.intValue()); + if (skill != null) + { + pet = summon; + break SUMMON_SEARCH; + } + } + } + if ((skill == null) && player.hasPet()) + { + pet = player.getPet(); + skill = pet.getKnownSkill(skillId.intValue()); + } + if (skill == null) + { + player.getAutoUseSettings().getAutoSkills().remove(skillId); + player.getAutoUseSettings().resetSkillOrder(); + break SKILLS; + } + } + + // Casting on self stops movement. + final WorldObject target = player.getTarget(); + if (target == player) + { + break SKILLS; + } + + // Check bad skill target. + if ((target == null) || !target.isAttackable() || ((Creature) target).isDead()) + { + break SKILLS; + } + + // Do not attack guards. + if (target instanceof Guard) + { + break SKILLS; + } + + if (!canUseMagic(player, target, skill) || (pet != null ? pet : player).useMagic(skill, null, true, false)) + { + player.getAutoUseSettings().incrementSkillOrder(); } } - final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); - if (actionHolder != null) + ACTIONS: for (Integer actionId : player.getAutoUseSettings().getAutoActions()) { - final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); - if (actionHandler != null) + final BuffInfo info = player.getEffectList().getFirstBuffInfoByAbnormalType(AbnormalType.BOT_PENALTY); + if (info != null) { - actionHandler.useAction(player, actionHolder, false, false); + for (AbstractEffect effect : info.getEffects()) + { + if (!effect.checkCondition(actionId)) + { + player.sendPacket(SystemMessageId.YOU_HAVE_BEEN_REPORTED_AS_AN_ILLEGAL_PROGRAM_USER_SO_YOUR_ACTIONS_HAVE_BEEN_RESTRICTED); + break ACTIONS; + } + } + } + + // Do not allow to do some action if player is transformed. + if (player.isTransformed()) + { + final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST; + if (Arrays.binarySearch(allowedActions, actionId) < 0) + { + continue ACTIONS; + } + } + + final ActionDataHolder actionHolder = ActionData.getInstance().getActionData(actionId); + if (actionHolder != null) + { + final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler()); + if (actionHandler != null) + { + actionHandler.useAction(player, actionHolder, false, false); + } } } } } } - _working = false; - } - - private boolean canCastBuff(Player player, WorldObject target, Skill skill) - { - // Summon check. - if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) + private boolean canCastBuff(Player player, WorldObject target, Skill skill) { - if (!player.hasServitors()) + // Summon check. + if ((skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER) || (skill.getTargetType() == TargetType.SUMMON)) { - return false; - } - int occurrences = 0; - for (Summon servitor : player.getServitors().values()) - { - if (servitor.isAffectedBySkill(skill.getId())) + if (!player.hasServitors()) { - occurrences++; + return false; + } + int occurrences = 0; + for (Summon servitor : player.getServitors().values()) + { + if (servitor.isAffectedBySkill(skill.getId())) + { + occurrences++; + } + } + if (occurrences == player.getServitors().size()) + { + return false; } } - if (occurrences == player.getServitors().size()) + + if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) { return false; } - } - - if ((target != null) && target.isCreature() && ((Creature) target).isAlikeDead() && (skill.getTargetType() != TargetType.SELF) && (skill.getTargetType() != TargetType.NPC_BODY) && (skill.getTargetType() != TargetType.PC_BODY)) - { - return false; - } - - final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; - if (!canUseMagic(player, playableTarget, skill)) - { - return false; - } - - final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); - final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); - if (abnormalBuffInfo != null) - { - if (buffInfo != null) - { - return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); - } - return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); - } - return buffInfo == null; - } - - private boolean canUseMagic(Player player, WorldObject target, Skill skill) - { - if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) - { - return false; - } - - for (AttachSkillHolder holder : skill.getAttachSkills()) - { - if (player.isAffectedBySkill(holder.getRequiredSkillId()) // - && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + + final Playable playableTarget = (target == null) || !target.isPlayable() || (skill.getTargetType() == TargetType.SELF) ? player : (Playable) target; + if (!canUseMagic(player, playableTarget, skill)) { return false; } + + final BuffInfo buffInfo = playableTarget.getEffectList().getBuffInfoBySkillId(skill.getId()); + final BuffInfo abnormalBuffInfo = playableTarget.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType()); + if (abnormalBuffInfo != null) + { + if (buffInfo != null) + { + return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel())); + } + return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE); + } + return buffInfo == null; } - return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + private boolean canUseMagic(Player player, WorldObject target, Skill skill) + { + if ((skill.getItemConsumeCount() > 0) && (player.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount())) + { + return false; + } + + for (AttachSkillHolder holder : skill.getAttachSkills()) + { + if (player.isAffectedBySkill(holder.getRequiredSkillId()) // + && (player.hasSkillReuse(holder.getSkill().getReuseHashCode()) || player.isAffectedBySkill(holder))) + { + return false; + } + } + + return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false); + } } - public void startAutoUseTask(Player player) + public synchronized void startAutoUseTask(Player player) { - if (!PLAYERS.contains(player)) + for (Set pool : POOLS) { - PLAYERS.add(player); + if (pool.contains(player)) + { + return; + } } + + for (Set pool : POOLS) + { + if (pool.size() < POOL_SIZE) + { + pool.add(player); + return; + } + } + + final Set pool = ConcurrentHashMap.newKeySet(POOL_SIZE); + pool.add(player); + ThreadPool.scheduleAtFixedRate(new AutoUse(pool), TASK_DELAY, TASK_DELAY); + POOLS.add(pool); } public void stopAutoUseTask(Player player) @@ -470,7 +489,13 @@ public class AutoUseTaskManager implements Runnable player.getAutoUseSettings().resetSkillOrder(); if (player.getAutoUseSettings().isEmpty() || !player.isOnline() || player.isInOfflineMode()) { - PLAYERS.remove(player); + for (Set pool : POOLS) + { + if (pool.remove(player)) + { + return; + } + } } }