Addition of auto play task managers.

This commit is contained in:
MobiusDevelopment 2020-09-21 21:39:37 +00:00
parent 561895582e
commit 8f80bb3a41
16 changed files with 1076 additions and 596 deletions

View File

@ -39,7 +39,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -220,9 +219,10 @@ import org.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import org.l2jmobius.gameserver.model.events.timers.TimerHolder;
import org.l2jmobius.gameserver.model.fishing.Fishing;
import org.l2jmobius.gameserver.model.holders.AttendanceInfoHolder;
import org.l2jmobius.gameserver.model.holders.AutoPlaySettingsHolder;
import org.l2jmobius.gameserver.model.holders.AutoUseSettingsHolder;
import org.l2jmobius.gameserver.model.holders.DamageTakenHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.ItemSkillHolder;
import org.l2jmobius.gameserver.model.holders.MonsterBookCardHolder;
import org.l2jmobius.gameserver.model.holders.MonsterBookRewardHolder;
import org.l2jmobius.gameserver.model.holders.MovieHolder;
@ -266,7 +266,6 @@ import org.l2jmobius.gameserver.model.skills.CommonSkill;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
import org.l2jmobius.gameserver.model.skills.SkillCastingType;
import org.l2jmobius.gameserver.model.skills.targets.AffectScope;
import org.l2jmobius.gameserver.model.skills.targets.TargetType;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Formulas;
@ -348,7 +347,6 @@ import org.l2jmobius.gameserver.network.serverpackets.TradeOtherDone;
import org.l2jmobius.gameserver.network.serverpackets.TradeStart;
import org.l2jmobius.gameserver.network.serverpackets.UserInfo;
import org.l2jmobius.gameserver.network.serverpackets.ValidateLocation;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro;
import org.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo;
import org.l2jmobius.gameserver.network.serverpackets.friend.FriendStatus;
import org.l2jmobius.gameserver.network.serverpackets.monsterbook.ExMonsterBook;
@ -869,15 +867,8 @@ public class PlayerInstance extends Playable
private final Set<Integer> _whisperers = ConcurrentHashMap.newKeySet();
private ScheduledFuture<?> _autoPlayTask = null;
private ScheduledFuture<?> _autoUseTask = null;
private final AtomicBoolean _pickup = new AtomicBoolean();
private final AtomicBoolean _longRange = new AtomicBoolean();
private final AtomicBoolean _respectfulHunting = new AtomicBoolean();
private final AtomicInteger _autoPotionPercent = new AtomicInteger();
private final Collection<Integer> _autoSupplyItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoPotionItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoSkills = ConcurrentHashMap.newKeySet();
private final AutoPlaySettingsHolder _autoPlaySettings = new AutoPlaySettingsHolder();
private final AutoUseSettingsHolder _autoUseSettings = new AutoUseSettingsHolder();
private ScheduledFuture<?> _timedHuntingZoneFinishTask = null;
@ -13863,16 +13854,6 @@ public class PlayerInstance extends Playable
_autoSaveTask.cancel(false);
_autoSaveTask = null;
}
if ((_autoPlayTask != null) && !_autoPlayTask.isDone() && !_autoPlayTask.isCancelled())
{
_autoPlayTask.cancel(false);
_autoPlayTask = null;
}
if ((_autoUseTask != null) && !_autoUseTask.isDone() && !_autoUseTask.isCancelled())
{
_autoUseTask.cancel(false);
_autoUseTask = null;
}
if ((_timedHuntingZoneFinishTask != null) && !_timedHuntingZoneFinishTask.isDone() && !_timedHuntingZoneFinishTask.isCancelled())
{
_timedHuntingZoneFinishTask.cancel(false);
@ -14170,274 +14151,14 @@ public class PlayerInstance extends Playable
}
}
public void stopAutoPlayTask()
public AutoPlaySettingsHolder getAutoPlaySettings()
{
if ((_autoPlayTask != null) && !_autoPlayTask.isCancelled() && !_autoPlayTask.isDone())
{
_autoPlayTask.cancel(true);
_autoPlayTask = null;
}
return _autoPlaySettings;
}
public void startAutoPlayTask(boolean pickup, boolean longRange, boolean respectfulHunting)
public AutoUseSettingsHolder getAutoUseSettings()
{
_pickup.set(pickup);
_longRange.set(longRange);
_respectfulHunting.set(respectfulHunting);
if (_autoPlayTask != null)
{
return;
}
_autoPlayTask = ThreadPool.scheduleAtFixedRate(() ->
{
if (!Config.ENABLE_AUTO_PLAY)
{
stopAutoPlayTask();
return;
}
// Skip thinking.
final WorldObject target = getTarget();
if ((target != null) && target.isMonster())
{
final MonsterInstance monster = (MonsterInstance) target;
if ((monster.getTarget() == this) && !monster.isAlikeDead())
{
// Check if actually attacking.
if (hasAI() && getAI().isAutoAttacking() && !isAttackingNow() && !isCastingNow())
{
doAutoAttack(monster);
}
return;
}
}
// Pickup.
if (_pickup.get())
{
for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(this, ItemInstance.class, 200))
{
// Check if item is reachable.
if ((droppedItem == null) //
|| (!droppedItem.isSpawned()) //
|| !GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), getInstanceWorld()))
{
continue;
}
// Move to item.
if (calculateDistance2D(droppedItem) > 50)
{
moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0);
return;
}
// Try to pick it up.
if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == getObjectId()))
{
doPickupItem(droppedItem);
return; // Avoid pickup being skipped.
}
}
}
// Find target.
MonsterInstance monster = null;
double closestDistance = Double.MAX_VALUE;
for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(this, MonsterInstance.class, _longRange.get() ? 1400 : 600))
{
// Skip unavailable monsters.
if ((nearby == null) || nearby.isAlikeDead())
{
continue;
}
// Check monster target.
if (_respectfulHunting.get() && (nearby.getTarget() != null) && (nearby.getTarget() != this))
{
continue;
}
// Check if monster is reachable.
if (nearby.isAutoAttackable(this) //
&& GeoEngine.getInstance().canSeeTarget(this, nearby)//
&& GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), getInstanceWorld()))
{
final double monsterDistance = calculateDistance2D(nearby);
if (monsterDistance < closestDistance)
{
monster = nearby;
closestDistance = monsterDistance;
}
}
}
// New target was assigned.
if (monster != null)
{
setTarget(monster);
sendPacket(ExAutoPlayDoMacro.STATIC_PACKET);
}
}, 0, 1000);
}
public void stopAutoUseTask()
{
if ((_autoUseTask != null) && !_autoUseTask.isCancelled() && !_autoUseTask.isDone())
{
_autoUseTask.cancel(true);
_autoUseTask = null;
}
}
private void startAutoUseTask()
{
if (_autoUseTask != null)
{
return;
}
_autoUseTask = ThreadPool.scheduleAtFixedRate(() ->
{
if (hasBlockActions() || isControlBlocked() || isAlikeDead() || isInsideZone(ZoneId.PEACE))
{
return;
}
if (Config.ENABLE_AUTO_ITEM)
{
ITEMS: for (int itemId : _autoSupplyItems)
{
final ItemInstance item = _inventory.getItemByItemId(itemId);
if (item == null)
{
removeAutoSupplyItem(itemId);
continue;
}
for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills())
{
final Skill skill = itemSkillHolder.getSkill();
if (isAffectedBySkill(skill.getId()) || hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(this, this, false))
{
continue ITEMS;
}
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0))
{
addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_POTION && (getCurrentHpPercent() <= _autoPotionPercent.get()))
{
for (int itemId : _autoPotionItems)
{
final ItemInstance item = _inventory.getItemByItemId(itemId);
if (item == null)
{
removeAutoPotionItem(itemId);
continue;
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0))
{
addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_BUFF)
{
for (int skillId : _autoSkills)
{
final Skill skill = getKnownSkill(skillId);
if (skill == null)
{
removeAutoSkill(skillId);
continue;
}
if (!isAffectedBySkill(skillId) && !hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(this, this, false))
{
// Summon check.
if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER)
{
if (!hasServitors()) // Is this check truly needed?
{
continue;
}
int occurrences = 0;
for (Summon servitor : _servitors.values())
{
if (servitor.isAffectedBySkill(skillId))
{
occurrences++;
}
}
if (occurrences == _servitors.size())
{
continue;
}
}
doCast(skill);
}
}
}
}, 0, 1000);
}
public void setAutoPotionPercent(int value)
{
_autoPotionPercent.set(value);
}
public void addAutoSupplyItem(int itemId)
{
_autoSupplyItems.add(itemId);
startAutoUseTask();
}
public void removeAutoSupplyItem(int itemId)
{
_autoSupplyItems.remove(itemId);
stopAutoUseTask();
}
public void addAutoPotionItem(int itemId)
{
_autoPotionItems.add(itemId);
startAutoUseTask();
}
public void removeAutoPotionItem(int itemId)
{
_autoPotionItems.remove(itemId);
stopAutoUseTask();
}
public void addAutoSkill(int skillId)
{
_autoSkills.add(skillId);
startAutoUseTask();
}
public void removeAutoSkill(int skillId)
{
_autoSkills.remove(skillId);
stopAutoUseTask();
return _autoUseSettings;
}
public boolean isInTimedHuntingZone()

View File

@ -0,0 +1,75 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.holders;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Mobius
*/
public class AutoPlaySettingsHolder
{
private final AtomicBoolean _pickup = new AtomicBoolean();
private final AtomicBoolean _longRange = new AtomicBoolean();
private final AtomicBoolean _respectfulHunting = new AtomicBoolean();
private final AtomicInteger _autoPotionPercent = new AtomicInteger();
public AutoPlaySettingsHolder()
{
}
public boolean doPickup()
{
return _pickup.get();
}
public void setPickup(boolean value)
{
_pickup.set(value);
}
public boolean isLongRange()
{
return _longRange.get();
}
public void setLongRange(boolean value)
{
_longRange.set(value);
}
public boolean isRespectfulHunting()
{
return _respectfulHunting.get();
}
public void setRespectfulHunting(boolean value)
{
_respectfulHunting.set(value);
}
public int getAutoPotionPercent()
{
return _autoPotionPercent.get();
}
public void setAutoPotionPercent(int value)
{
_autoPotionPercent.set(value);
}
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.holders;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Mobius
*/
public class AutoUseSettingsHolder
{
private final Collection<Integer> _autoSupplyItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoPotionItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoSkills = ConcurrentHashMap.newKeySet();
public AutoUseSettingsHolder()
{
}
public Collection<Integer> getAutoSupplyItems()
{
return _autoSupplyItems;
}
public Collection<Integer> getAutoPotionItems()
{
return _autoPotionItems;
}
public Collection<Integer> getAutoSkills()
{
return _autoSkills;
}
}

View File

@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.network.clientpackets;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager;
/**
* @version $Revision: 1.3.4.2 $ $Date: 2005/03/27 15:29:30 $
@ -57,11 +58,11 @@ public class RequestShortCutDel implements IClientIncomingPacket
// Remove auto used ids.
if (_slot > 263)
{
player.removeAutoSupplyItem(_id);
AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, _id);
}
else
{
player.removeAutoSkill(_id);
AutoUseTaskManager.getInstance().removeAutoSkill(player, _id);
}
}
}

View File

@ -22,6 +22,7 @@ import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlaySettingSend;
import org.l2jmobius.gameserver.taskmanager.AutoPlayTaskManager;
/**
* @author Mobius
@ -59,7 +60,7 @@ public class ExAutoPlaySetting implements IClientIncomingPacket
}
player.sendPacket(new ExAutoPlaySettingSend(_options, _active, _pickUp, _nextTargetMode, _longRange, _potionPercent, _respectfulHunting));
player.setAutoPotionPercent(_potionPercent);
player.getAutoPlaySettings().setAutoPotionPercent(_potionPercent);
if (!Config.ENABLE_AUTO_PLAY)
{
@ -68,11 +69,11 @@ public class ExAutoPlaySetting implements IClientIncomingPacket
if (_active)
{
player.startAutoPlayTask(_pickUp, _longRange, _respectfulHunting);
AutoPlayTaskManager.getInstance().doAutoPlay(player, _pickUp, _longRange, _respectfulHunting);
}
else
{
player.stopAutoPlayTask();
AutoPlayTaskManager.getInstance().stopAutoPlay(player);
}
}
}

View File

@ -25,6 +25,7 @@ import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExActivateAutoShortcut;
import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager;
/**
* @author JoeAlisson, Mobius
@ -75,17 +76,17 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
// auto supply
if (_room > 263)
{
player.removeAutoSupplyItem(item.getId());
AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, item.getId());
}
else // auto potion
{
player.removeAutoPotionItem(item.getId());
AutoUseTaskManager.getInstance().removeAutoPotionItem(player, item.getId());
}
}
// auto skill
if (skill != null)
{
player.removeAutoSkill(skill.getId());
AutoUseTaskManager.getInstance().removeAutoSkill(player, skill.getId());
}
return;
}
@ -96,7 +97,7 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
// auto supply
if (Config.ENABLE_AUTO_ITEM && (item != null))
{
player.addAutoSupplyItem(item.getId());
AutoUseTaskManager.getInstance().addAutoSupplyItem(player, item.getId());
}
}
else
@ -106,14 +107,14 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
{
if (Config.ENABLE_AUTO_POTION && (item != null) && item.isPotion())
{
player.addAutoPotionItem(item.getId());
AutoUseTaskManager.getInstance().addAutoPotionItem(player, item.getId());
return;
}
}
// auto skill
if (Config.ENABLE_AUTO_BUFF && (skill != null))
{
player.addAutoSkill(skill.getId());
AutoUseTaskManager.getInstance().addAutoSkill(player, skill.getId());
}
}
}

View File

@ -0,0 +1,170 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.taskmanager;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro;
/**
* @author Mobius
*/
public class AutoPlayTaskManager
{
private static final Set<PlayerInstance> PLAYERS = ConcurrentHashMap.newKeySet();
private static boolean _working = false;
public AutoPlayTaskManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_working)
{
return;
}
_working = true;
PLAY: for (PlayerInstance player : PLAYERS)
{
if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY)
{
stopAutoPlay(player);
continue PLAY;
}
// Skip thinking.
final WorldObject target = player.getTarget();
if ((target != null) && target.isMonster())
{
final MonsterInstance monster = (MonsterInstance) target;
if ((monster.getTarget() == player) && !monster.isAlikeDead())
{
// Check if actually attacking.
if (player.hasAI() && player.getAI().isAutoAttacking() && !player.isAttackingNow() && !player.isCastingNow())
{
player.doAutoAttack(monster);
}
continue PLAY;
}
}
// Pickup.
if (player.getAutoPlaySettings().doPickup())
{
PICKUP: for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(player, ItemInstance.class, 200))
{
// Check if item is reachable.
if ((droppedItem == null) //
|| (!droppedItem.isSpawned()) //
|| !GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), player.getInstanceWorld()))
{
continue PICKUP;
}
// Move to item.
if (player.calculateDistance2D(droppedItem) > 50)
{
player.moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0);
continue PLAY;
}
// Try to pick it up.
if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == player.getObjectId()))
{
player.doPickupItem(droppedItem);
continue PLAY; // Avoid pickup being skipped.
}
}
}
// Find target.
MonsterInstance monster = null;
double closestDistance = Double.MAX_VALUE;
TARGET: for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(player, MonsterInstance.class, player.getAutoPlaySettings().isLongRange() ? 1400 : 600))
{
// Skip unavailable monsters.
if ((nearby == null) || nearby.isAlikeDead())
{
continue TARGET;
}
// Check monster target.
if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player))
{
continue TARGET;
}
// Check if monster is reachable.
if (nearby.isAutoAttackable(player) //
&& GeoEngine.getInstance().canSeeTarget(player, nearby)//
&& GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld()))
{
final double monsterDistance = player.calculateDistance2D(nearby);
if (monsterDistance < closestDistance)
{
monster = nearby;
closestDistance = monsterDistance;
}
}
}
// New target was assigned.
if (monster != null)
{
player.setTarget(monster);
player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET);
}
}
_working = false;
}, 1000, 1000);
}
public void doAutoPlay(PlayerInstance player, boolean pickup, boolean longRange, boolean respectfulHunting)
{
player.getAutoPlaySettings().setPickup(pickup);
player.getAutoPlaySettings().setLongRange(longRange);
player.getAutoPlaySettings().setRespectfulHunting(respectfulHunting);
if (!PLAYERS.contains(player))
{
PLAYERS.add(player);
}
}
public void stopAutoPlay(PlayerInstance player)
{
PLAYERS.remove(player);
}
public static AutoPlayTaskManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final AutoPlayTaskManager INSTANCE = new AutoPlayTaskManager();
}
}

View File

@ -0,0 +1,222 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.taskmanager;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.handler.IItemHandler;
import org.l2jmobius.gameserver.handler.ItemHandler;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.holders.ItemSkillHolder;
import org.l2jmobius.gameserver.model.items.EtcItem;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.skills.targets.AffectScope;
import org.l2jmobius.gameserver.model.zone.ZoneId;
/**
* @author Mobius
*/
public class AutoUseTaskManager
{
private static final Set<PlayerInstance> PLAYERS = ConcurrentHashMap.newKeySet();
private static boolean _working = false;
public AutoUseTaskManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_working)
{
return;
}
_working = true;
for (PlayerInstance player : PLAYERS)
{
if (!player.isOnline() || player.isInOfflineMode())
{
stopAutoUseTask(player);
continue;
}
if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isInsideZone(ZoneId.PEACE))
{
continue;
}
if (Config.ENABLE_AUTO_ITEM)
{
ITEMS: for (int itemId : player.getAutoUseSettings().getAutoSupplyItems())
{
final ItemInstance item = player.getInventory().getItemByItemId(itemId);
if (item == null)
{
player.getAutoUseSettings().getAutoSupplyItems().remove(itemId);
continue ITEMS; // TODO: break?
}
for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills())
{
final Skill skill = itemSkillHolder.getSkill();
if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false))
{
continue ITEMS;
}
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0))
{
player.addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_POTION && (player.getCurrentHpPercent() <= player.getAutoPlaySettings().getAutoPotionPercent()))
{
POTIONS: for (int itemId : player.getAutoUseSettings().getAutoPotionItems())
{
final ItemInstance item = player.getInventory().getItemByItemId(itemId);
if (item == null)
{
player.getAutoUseSettings().getAutoPotionItems().remove(itemId);
continue POTIONS; // TODO: break?
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0))
{
player.addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_BUFF)
{
BUFFS: for (int skillId : player.getAutoUseSettings().getAutoSkills())
{
final Skill skill = player.getKnownSkill(skillId);
if (skill == null)
{
player.getAutoUseSettings().getAutoSkills().remove(skillId);
continue BUFFS; // TODO: break?
}
if (!player.isAffectedBySkill(skillId) && !player.hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(player, player, false))
{
// Summon check.
if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER)
{
if (!player.hasServitors()) // Is this check truly needed?
{
continue BUFFS;
}
int occurrences = 0;
for (Summon servitor : player.getServitors().values())
{
if (servitor.isAffectedBySkill(skillId))
{
occurrences++;
}
}
if (occurrences == player.getServitors().size())
{
continue BUFFS;
}
}
player.doCast(skill);
}
}
}
}
_working = false;
}, 1000, 1000);
}
public void startAutoUseTask(PlayerInstance player)
{
if (!PLAYERS.contains(player))
{
PLAYERS.add(player);
}
}
public void stopAutoUseTask(PlayerInstance player)
{
PLAYERS.remove(player);
}
public void addAutoSupplyItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoSupplyItems().add(itemId);
startAutoUseTask(player);
}
public void removeAutoSupplyItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoSupplyItems().remove(itemId);
stopAutoUseTask(player);
}
public void addAutoPotionItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoPotionItems().add(itemId);
startAutoUseTask(player);
}
public void removeAutoPotionItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoPotionItems().remove(itemId);
stopAutoUseTask(player);
}
public void addAutoSkill(PlayerInstance player, int skillId)
{
player.getAutoUseSettings().getAutoSkills().add(skillId);
startAutoUseTask(player);
}
public void removeAutoSkill(PlayerInstance player, int skillId)
{
player.getAutoUseSettings().getAutoSkills().remove(skillId);
stopAutoUseTask(player);
}
public static AutoUseTaskManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final AutoUseTaskManager INSTANCE = new AutoUseTaskManager();
}
}

View File

@ -40,7 +40,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -223,10 +222,11 @@ import org.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import org.l2jmobius.gameserver.model.events.timers.TimerHolder;
import org.l2jmobius.gameserver.model.fishing.Fishing;
import org.l2jmobius.gameserver.model.holders.AttendanceInfoHolder;
import org.l2jmobius.gameserver.model.holders.AutoPlaySettingsHolder;
import org.l2jmobius.gameserver.model.holders.AutoUseSettingsHolder;
import org.l2jmobius.gameserver.model.holders.DamageTakenHolder;
import org.l2jmobius.gameserver.model.holders.ElementalSpiritDataHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.ItemSkillHolder;
import org.l2jmobius.gameserver.model.holders.MovieHolder;
import org.l2jmobius.gameserver.model.holders.PlayerEventHolder;
import org.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
@ -267,7 +267,6 @@ import org.l2jmobius.gameserver.model.skills.CommonSkill;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
import org.l2jmobius.gameserver.model.skills.SkillCastingType;
import org.l2jmobius.gameserver.model.skills.targets.AffectScope;
import org.l2jmobius.gameserver.model.skills.targets.TargetType;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Formulas;
@ -348,7 +347,6 @@ import org.l2jmobius.gameserver.network.serverpackets.TradeOtherDone;
import org.l2jmobius.gameserver.network.serverpackets.TradeStart;
import org.l2jmobius.gameserver.network.serverpackets.UserInfo;
import org.l2jmobius.gameserver.network.serverpackets.ValidateLocation;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro;
import org.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo;
import org.l2jmobius.gameserver.network.serverpackets.friend.FriendStatus;
import org.l2jmobius.gameserver.network.serverpackets.sessionzones.TimedHuntingZoneExit;
@ -866,15 +864,8 @@ public class PlayerInstance extends Playable
private ElementalSpirit[] _spirits;
private ElementalType _activeElementalSpiritType;
private ScheduledFuture<?> _autoPlayTask = null;
private ScheduledFuture<?> _autoUseTask = null;
private final AtomicBoolean _pickup = new AtomicBoolean();
private final AtomicBoolean _longRange = new AtomicBoolean();
private final AtomicBoolean _respectfulHunting = new AtomicBoolean();
private final AtomicInteger _autoPotionPercent = new AtomicInteger();
private final Collection<Integer> _autoSupplyItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoPotionItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoSkills = ConcurrentHashMap.newKeySet();
private final AutoPlaySettingsHolder _autoPlaySettings = new AutoPlaySettingsHolder();
private final AutoUseSettingsHolder _autoUseSettings = new AutoUseSettingsHolder();
private ScheduledFuture<?> _timedHuntingZoneFinishTask = null;
@ -13714,16 +13705,6 @@ public class PlayerInstance extends Playable
_autoSaveTask.cancel(false);
_autoSaveTask = null;
}
if ((_autoPlayTask != null) && !_autoPlayTask.isDone() && !_autoPlayTask.isCancelled())
{
_autoPlayTask.cancel(false);
_autoPlayTask = null;
}
if ((_autoUseTask != null) && !_autoUseTask.isDone() && !_autoUseTask.isCancelled())
{
_autoUseTask.cancel(false);
_autoUseTask = null;
}
if ((_timedHuntingZoneFinishTask != null) && !_timedHuntingZoneFinishTask.isDone() && !_timedHuntingZoneFinishTask.isCancelled())
{
_timedHuntingZoneFinishTask.cancel(false);
@ -14117,274 +14098,14 @@ public class PlayerInstance extends Playable
return AttackStanceTaskManager.getInstance().hasAttackStanceTask(this);
}
public void stopAutoPlayTask()
public AutoPlaySettingsHolder getAutoPlaySettings()
{
if ((_autoPlayTask != null) && !_autoPlayTask.isCancelled() && !_autoPlayTask.isDone())
{
_autoPlayTask.cancel(true);
_autoPlayTask = null;
}
return _autoPlaySettings;
}
public void startAutoPlayTask(boolean pickup, boolean longRange, boolean respectfulHunting)
public AutoUseSettingsHolder getAutoUseSettings()
{
_pickup.set(pickup);
_longRange.set(longRange);
_respectfulHunting.set(respectfulHunting);
if (_autoPlayTask != null)
{
return;
}
_autoPlayTask = ThreadPool.scheduleAtFixedRate(() ->
{
if (!Config.ENABLE_AUTO_PLAY)
{
stopAutoPlayTask();
return;
}
// Skip thinking.
final WorldObject target = getTarget();
if ((target != null) && target.isMonster())
{
final MonsterInstance monster = (MonsterInstance) target;
if ((monster.getTarget() == this) && !monster.isAlikeDead())
{
// Check if actually attacking.
if (hasAI() && getAI().isAutoAttacking() && !isAttackingNow() && !isCastingNow())
{
doAutoAttack(monster);
}
return;
}
}
// Pickup.
if (_pickup.get())
{
for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(this, ItemInstance.class, 200))
{
// Check if item is reachable.
if ((droppedItem == null) //
|| (!droppedItem.isSpawned()) //
|| !GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), getInstanceWorld()))
{
continue;
}
// Move to item.
if (calculateDistance2D(droppedItem) > 50)
{
moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0);
return;
}
// Try to pick it up.
if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == getObjectId()))
{
doPickupItem(droppedItem);
return; // Avoid pickup being skipped.
}
}
}
// Find target.
MonsterInstance monster = null;
double closestDistance = Double.MAX_VALUE;
for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(this, MonsterInstance.class, _longRange.get() ? 1400 : 600))
{
// Skip unavailable monsters.
if ((nearby == null) || nearby.isAlikeDead())
{
continue;
}
// Check monster target.
if (_respectfulHunting.get() && (nearby.getTarget() != null) && (nearby.getTarget() != this))
{
continue;
}
// Check if monster is reachable.
if (nearby.isAutoAttackable(this) //
&& GeoEngine.getInstance().canSeeTarget(this, nearby)//
&& GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), getInstanceWorld()))
{
final double monsterDistance = calculateDistance2D(nearby);
if (monsterDistance < closestDistance)
{
monster = nearby;
closestDistance = monsterDistance;
}
}
}
// New target was assigned.
if (monster != null)
{
setTarget(monster);
sendPacket(ExAutoPlayDoMacro.STATIC_PACKET);
}
}, 0, 1000);
}
public void stopAutoUseTask()
{
if ((_autoUseTask != null) && !_autoUseTask.isCancelled() && !_autoUseTask.isDone())
{
_autoUseTask.cancel(true);
_autoUseTask = null;
}
}
private void startAutoUseTask()
{
if (_autoUseTask != null)
{
return;
}
_autoUseTask = ThreadPool.scheduleAtFixedRate(() ->
{
if (hasBlockActions() || isControlBlocked() || isAlikeDead() || isInsideZone(ZoneId.PEACE))
{
return;
}
if (Config.ENABLE_AUTO_ITEM)
{
ITEMS: for (int itemId : _autoSupplyItems)
{
final ItemInstance item = _inventory.getItemByItemId(itemId);
if (item == null)
{
removeAutoSupplyItem(itemId);
continue;
}
for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills())
{
final Skill skill = itemSkillHolder.getSkill();
if (isAffectedBySkill(skill.getId()) || hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(this, this, false))
{
continue ITEMS;
}
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0))
{
addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_POTION && (getCurrentHpPercent() <= _autoPotionPercent.get()))
{
for (int itemId : _autoPotionItems)
{
final ItemInstance item = _inventory.getItemByItemId(itemId);
if (item == null)
{
removeAutoPotionItem(itemId);
continue;
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(this, item, false) && (reuseDelay > 0))
{
addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_BUFF)
{
for (int skillId : _autoSkills)
{
final Skill skill = getKnownSkill(skillId);
if (skill == null)
{
removeAutoSkill(skillId);
continue;
}
if (!isAffectedBySkill(skillId) && !hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(this, this, false))
{
// Summon check.
if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER)
{
if (!hasServitors()) // Is this check truly needed?
{
continue;
}
int occurrences = 0;
for (Summon servitor : _servitors.values())
{
if (servitor.isAffectedBySkill(skillId))
{
occurrences++;
}
}
if (occurrences == _servitors.size())
{
continue;
}
}
doCast(skill);
}
}
}
}, 0, 1000);
}
public void setAutoPotionPercent(int value)
{
_autoPotionPercent.set(value);
}
public void addAutoSupplyItem(int itemId)
{
_autoSupplyItems.add(itemId);
startAutoUseTask();
}
public void removeAutoSupplyItem(int itemId)
{
_autoSupplyItems.remove(itemId);
stopAutoUseTask();
}
public void addAutoPotionItem(int itemId)
{
_autoPotionItems.add(itemId);
startAutoUseTask();
}
public void removeAutoPotionItem(int itemId)
{
_autoPotionItems.remove(itemId);
stopAutoUseTask();
}
public void addAutoSkill(int skillId)
{
_autoSkills.add(skillId);
startAutoUseTask();
}
public void removeAutoSkill(int skillId)
{
_autoSkills.remove(skillId);
stopAutoUseTask();
return _autoUseSettings;
}
public boolean isInTimedHuntingZone()

View File

@ -0,0 +1,75 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.holders;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Mobius
*/
public class AutoPlaySettingsHolder
{
private final AtomicBoolean _pickup = new AtomicBoolean();
private final AtomicBoolean _longRange = new AtomicBoolean();
private final AtomicBoolean _respectfulHunting = new AtomicBoolean();
private final AtomicInteger _autoPotionPercent = new AtomicInteger();
public AutoPlaySettingsHolder()
{
}
public boolean doPickup()
{
return _pickup.get();
}
public void setPickup(boolean value)
{
_pickup.set(value);
}
public boolean isLongRange()
{
return _longRange.get();
}
public void setLongRange(boolean value)
{
_longRange.set(value);
}
public boolean isRespectfulHunting()
{
return _respectfulHunting.get();
}
public void setRespectfulHunting(boolean value)
{
_respectfulHunting.set(value);
}
public int getAutoPotionPercent()
{
return _autoPotionPercent.get();
}
public void setAutoPotionPercent(int value)
{
_autoPotionPercent.set(value);
}
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.holders;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Mobius
*/
public class AutoUseSettingsHolder
{
private final Collection<Integer> _autoSupplyItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoPotionItems = ConcurrentHashMap.newKeySet();
private final Collection<Integer> _autoSkills = ConcurrentHashMap.newKeySet();
public AutoUseSettingsHolder()
{
}
public Collection<Integer> getAutoSupplyItems()
{
return _autoSupplyItems;
}
public Collection<Integer> getAutoPotionItems()
{
return _autoPotionItems;
}
public Collection<Integer> getAutoSkills()
{
return _autoSkills;
}
}

View File

@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.network.clientpackets;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager;
/**
* @version $Revision: 1.3.4.2 $ $Date: 2005/03/27 15:29:30 $
@ -57,11 +58,11 @@ public class RequestShortCutDel implements IClientIncomingPacket
// Remove auto used ids.
if (_slot > 263)
{
player.removeAutoSupplyItem(_id);
AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, _id);
}
else
{
player.removeAutoSkill(_id);
AutoUseTaskManager.getInstance().removeAutoSkill(player, _id);
}
}
}

View File

@ -22,6 +22,7 @@ import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlaySettingSend;
import org.l2jmobius.gameserver.taskmanager.AutoPlayTaskManager;
/**
* @author Mobius
@ -59,7 +60,7 @@ public class ExAutoPlaySetting implements IClientIncomingPacket
}
player.sendPacket(new ExAutoPlaySettingSend(_options, _active, _pickUp, _nextTargetMode, _longRange, _potionPercent, _respectfulHunting));
player.setAutoPotionPercent(_potionPercent);
player.getAutoPlaySettings().setAutoPotionPercent(_potionPercent);
if (!Config.ENABLE_AUTO_PLAY)
{
@ -68,11 +69,11 @@ public class ExAutoPlaySetting implements IClientIncomingPacket
if (_active)
{
player.startAutoPlayTask(_pickUp, _longRange, _respectfulHunting);
AutoPlayTaskManager.getInstance().doAutoPlay(player, _pickUp, _longRange, _respectfulHunting);
}
else
{
player.stopAutoPlayTask();
AutoPlayTaskManager.getInstance().stopAutoPlay(player);
}
}
}

View File

@ -25,6 +25,7 @@ import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExActivateAutoShortcut;
import org.l2jmobius.gameserver.taskmanager.AutoUseTaskManager;
/**
* @author JoeAlisson, Mobius
@ -75,17 +76,17 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
// auto supply
if (_room > 263)
{
player.removeAutoSupplyItem(item.getId());
AutoUseTaskManager.getInstance().removeAutoSupplyItem(player, item.getId());
}
else // auto potion
{
player.removeAutoPotionItem(item.getId());
AutoUseTaskManager.getInstance().removeAutoPotionItem(player, item.getId());
}
}
// auto skill
if (skill != null)
{
player.removeAutoSkill(skill.getId());
AutoUseTaskManager.getInstance().removeAutoSkill(player, skill.getId());
}
return;
}
@ -96,7 +97,7 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
// auto supply
if (Config.ENABLE_AUTO_ITEM && (item != null))
{
player.addAutoSupplyItem(item.getId());
AutoUseTaskManager.getInstance().addAutoSupplyItem(player, item.getId());
}
}
else
@ -106,14 +107,14 @@ public class ExRequestActivateAutoShortcut implements IClientIncomingPacket
{
if (Config.ENABLE_AUTO_POTION && (item != null) && item.isPotion())
{
player.addAutoPotionItem(item.getId());
AutoUseTaskManager.getInstance().addAutoPotionItem(player, item.getId());
return;
}
}
// auto skill
if (Config.ENABLE_AUTO_BUFF && (skill != null))
{
player.addAutoSkill(skill.getId());
AutoUseTaskManager.getInstance().addAutoSkill(player, skill.getId());
}
}
}

View File

@ -0,0 +1,170 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.taskmanager;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.network.serverpackets.autoplay.ExAutoPlayDoMacro;
/**
* @author Mobius
*/
public class AutoPlayTaskManager
{
private static final Set<PlayerInstance> PLAYERS = ConcurrentHashMap.newKeySet();
private static boolean _working = false;
public AutoPlayTaskManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_working)
{
return;
}
_working = true;
PLAY: for (PlayerInstance player : PLAYERS)
{
if (!player.isOnline() || player.isInOfflineMode() || !Config.ENABLE_AUTO_PLAY)
{
stopAutoPlay(player);
continue PLAY;
}
// Skip thinking.
final WorldObject target = player.getTarget();
if ((target != null) && target.isMonster())
{
final MonsterInstance monster = (MonsterInstance) target;
if ((monster.getTarget() == player) && !monster.isAlikeDead())
{
// Check if actually attacking.
if (player.hasAI() && player.getAI().isAutoAttacking() && !player.isAttackingNow() && !player.isCastingNow())
{
player.doAutoAttack(monster);
}
continue PLAY;
}
}
// Pickup.
if (player.getAutoPlaySettings().doPickup())
{
PICKUP: for (ItemInstance droppedItem : World.getInstance().getVisibleObjectsInRange(player, ItemInstance.class, 200))
{
// Check if item is reachable.
if ((droppedItem == null) //
|| (!droppedItem.isSpawned()) //
|| !GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), player.getInstanceWorld()))
{
continue PICKUP;
}
// Move to item.
if (player.calculateDistance2D(droppedItem) > 50)
{
player.moveToLocation(droppedItem.getX(), droppedItem.getY(), droppedItem.getZ(), 0);
continue PLAY;
}
// Try to pick it up.
if (!droppedItem.isProtected() || (droppedItem.getOwnerId() == player.getObjectId()))
{
player.doPickupItem(droppedItem);
continue PLAY; // Avoid pickup being skipped.
}
}
}
// Find target.
MonsterInstance monster = null;
double closestDistance = Double.MAX_VALUE;
TARGET: for (MonsterInstance nearby : World.getInstance().getVisibleObjectsInRange(player, MonsterInstance.class, player.getAutoPlaySettings().isLongRange() ? 1400 : 600))
{
// Skip unavailable monsters.
if ((nearby == null) || nearby.isAlikeDead())
{
continue TARGET;
}
// Check monster target.
if (player.getAutoPlaySettings().isRespectfulHunting() && (nearby.getTarget() != null) && (nearby.getTarget() != player))
{
continue TARGET;
}
// Check if monster is reachable.
if (nearby.isAutoAttackable(player) //
&& GeoEngine.getInstance().canSeeTarget(player, nearby)//
&& GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld()))
{
final double monsterDistance = player.calculateDistance2D(nearby);
if (monsterDistance < closestDistance)
{
monster = nearby;
closestDistance = monsterDistance;
}
}
}
// New target was assigned.
if (monster != null)
{
player.setTarget(monster);
player.sendPacket(ExAutoPlayDoMacro.STATIC_PACKET);
}
}
_working = false;
}, 1000, 1000);
}
public void doAutoPlay(PlayerInstance player, boolean pickup, boolean longRange, boolean respectfulHunting)
{
player.getAutoPlaySettings().setPickup(pickup);
player.getAutoPlaySettings().setLongRange(longRange);
player.getAutoPlaySettings().setRespectfulHunting(respectfulHunting);
if (!PLAYERS.contains(player))
{
PLAYERS.add(player);
}
}
public void stopAutoPlay(PlayerInstance player)
{
PLAYERS.remove(player);
}
public static AutoPlayTaskManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final AutoPlayTaskManager INSTANCE = new AutoPlayTaskManager();
}
}

View File

@ -0,0 +1,222 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.taskmanager;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.handler.IItemHandler;
import org.l2jmobius.gameserver.handler.ItemHandler;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.holders.ItemSkillHolder;
import org.l2jmobius.gameserver.model.items.EtcItem;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.skills.targets.AffectScope;
import org.l2jmobius.gameserver.model.zone.ZoneId;
/**
* @author Mobius
*/
public class AutoUseTaskManager
{
private static final Set<PlayerInstance> PLAYERS = ConcurrentHashMap.newKeySet();
private static boolean _working = false;
public AutoUseTaskManager()
{
ThreadPool.scheduleAtFixedRate(() ->
{
if (_working)
{
return;
}
_working = true;
for (PlayerInstance player : PLAYERS)
{
if (!player.isOnline() || player.isInOfflineMode())
{
stopAutoUseTask(player);
continue;
}
if (player.hasBlockActions() || player.isControlBlocked() || player.isAlikeDead() || player.isInsideZone(ZoneId.PEACE))
{
continue;
}
if (Config.ENABLE_AUTO_ITEM)
{
ITEMS: for (int itemId : player.getAutoUseSettings().getAutoSupplyItems())
{
final ItemInstance item = player.getInventory().getItemByItemId(itemId);
if (item == null)
{
player.getAutoUseSettings().getAutoSupplyItems().remove(itemId);
continue ITEMS; // TODO: break?
}
for (ItemSkillHolder itemSkillHolder : item.getItem().getAllSkills())
{
final Skill skill = itemSkillHolder.getSkill();
if (player.isAffectedBySkill(skill.getId()) || player.hasSkillReuse(skill.getReuseHashCode()) || !skill.checkCondition(player, player, false))
{
continue ITEMS;
}
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0))
{
player.addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_POTION && (player.getCurrentHpPercent() <= player.getAutoPlaySettings().getAutoPotionPercent()))
{
POTIONS: for (int itemId : player.getAutoUseSettings().getAutoPotionItems())
{
final ItemInstance item = player.getInventory().getItemByItemId(itemId);
if (item == null)
{
player.getAutoUseSettings().getAutoPotionItems().remove(itemId);
continue POTIONS; // TODO: break?
}
final int reuseDelay = item.getReuseDelay();
if ((reuseDelay <= 0) || (player.getItemRemainingReuseTime(item.getObjectId()) <= 0))
{
final EtcItem etcItem = item.getEtcItem();
final IItemHandler handler = ItemHandler.getInstance().getHandler(etcItem);
if ((handler != null) && handler.useItem(player, item, false) && (reuseDelay > 0))
{
player.addTimeStampItem(item, reuseDelay);
}
}
}
}
if (Config.ENABLE_AUTO_BUFF)
{
BUFFS: for (int skillId : player.getAutoUseSettings().getAutoSkills())
{
final Skill skill = player.getKnownSkill(skillId);
if (skill == null)
{
player.getAutoUseSettings().getAutoSkills().remove(skillId);
continue BUFFS; // TODO: break?
}
if (!player.isAffectedBySkill(skillId) && !player.hasSkillReuse(skill.getReuseHashCode()) && skill.checkCondition(player, player, false))
{
// Summon check.
if (skill.getAffectScope() == AffectScope.SUMMON_EXCEPT_MASTER)
{
if (!player.hasServitors()) // Is this check truly needed?
{
continue BUFFS;
}
int occurrences = 0;
for (Summon servitor : player.getServitors().values())
{
if (servitor.isAffectedBySkill(skillId))
{
occurrences++;
}
}
if (occurrences == player.getServitors().size())
{
continue BUFFS;
}
}
player.doCast(skill);
}
}
}
}
_working = false;
}, 1000, 1000);
}
public void startAutoUseTask(PlayerInstance player)
{
if (!PLAYERS.contains(player))
{
PLAYERS.add(player);
}
}
public void stopAutoUseTask(PlayerInstance player)
{
PLAYERS.remove(player);
}
public void addAutoSupplyItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoSupplyItems().add(itemId);
startAutoUseTask(player);
}
public void removeAutoSupplyItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoSupplyItems().remove(itemId);
stopAutoUseTask(player);
}
public void addAutoPotionItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoPotionItems().add(itemId);
startAutoUseTask(player);
}
public void removeAutoPotionItem(PlayerInstance player, int itemId)
{
player.getAutoUseSettings().getAutoPotionItems().remove(itemId);
stopAutoUseTask(player);
}
public void addAutoSkill(PlayerInstance player, int skillId)
{
player.getAutoUseSettings().getAutoSkills().add(skillId);
startAutoUseTask(player);
}
public void removeAutoSkill(PlayerInstance player, int skillId)
{
player.getAutoUseSettings().getAutoSkills().remove(skillId);
stopAutoUseTask(player);
}
public static AutoUseTaskManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final AutoUseTaskManager INSTANCE = new AutoUseTaskManager();
}
}