diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index da53d50781..634d41614e 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -151,7 +151,7 @@ public class L2CharacterAI extends AbstractAI // This is only for mobs - town npcs are handled in their constructor if (_actor instanceof L2Attackable) { - ((L2NpcInstance) _actor).startRandomAnimationTimer(); + ((L2NpcInstance) _actor).startRandomAnimationTask(); } // Launch the Think Event @@ -1219,7 +1219,7 @@ public class L2CharacterAI extends AbstractAI // This is only for mobs - town npcs are handled in their constructor if (_actor instanceof L2Attackable) { - ((L2NpcInstance) _actor).startRandomAnimationTimer(); + ((L2NpcInstance) _actor).startRandomAnimationTask(); } // Launch the Think Event diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2WorldRegion.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2WorldRegion.java index f2c4c19073..65d58bbd0f 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2WorldRegion.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2WorldRegion.java @@ -265,7 +265,7 @@ public final class L2WorldRegion { // Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it // L2Monsterinstance/L2Attackable socials are handled by AI (TODO: check the instances) - ((L2NpcInstance) o).startRandomAnimationTimer(); + ((L2NpcInstance) o).startRandomAnimationTask(); } } if (Config.DEBUG) diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 71903019e1..373468279c 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -485,8 +485,8 @@ public class L2Attackable extends L2NpcInstance } /* * // CommandChannel if(_commandChannelTimer == null && isRaid() && attacker != null) { if(attacker.isInParty() && attacker.getParty().isInCommandChannel() && attacker.getParty().getCommandChannel().meetRaidWarCondition(this)) { _firstCommandChannelAttacked = - * attacker.getParty().getCommandChannel(); _commandChannelTimer = new CommandChannelTimer(this, attacker.getParty().getCommandChannel()); ThreadPoolManager.scheduleGeneral(_commandChannelTimer, 300000); // 5 min _firstCommandChannelAttacked.broadcastToChannelMembers(new - * CreatureSay(0, Say2.PARTYROOM_ALL, "", "You have looting rights!")); } } + * attacker.getParty().getCommandChannel(); _commandChannelTimer = new CommandChannelTimer(this, attacker.getParty().getCommandChannel()); ThreadPoolManager.scheduleGeneral(_commandChannelTimer, 300000); // 5 min _firstCommandChannelAttacked.broadcastToChannelMembers(new CreatureSay(0, + * Say2.PARTYROOM_ALL, "", "You have looting rights!")); } } */ if (isEventMob) { @@ -3342,12 +3342,6 @@ public class L2Attackable extends L2NpcInstance return (Config.MAX_MONSTER_ANIMATION > 0) && !(this instanceof L2GrandBossInstance); } - @Override - public boolean isMob() - { - return true; // This means we use MAX_MONSTER_ANIMATION instead of MAX_NPC_ANIMATION - } - protected void setCommandChannelTimer(CommandChannelTimer commandChannelTimer) { _commandChannelTimer = commandChannelTimer; diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2NpcInstance.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2NpcInstance.java index b2ef37d82f..f857481cca 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2NpcInstance.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2NpcInstance.java @@ -150,8 +150,12 @@ public class L2NpcInstance extends L2Character /** The _is spoiled by. */ private int _isSpoiledBy = 0; + /** Time of last social packet broadcast */ + private long _lastSocialBroadcast = 0; + /** Minimum interval between social packets */ + private static final int MINIMUM_SOCIAL_INTERVAL = 6000; /** The _r ani task. */ - protected RandomAnimationTask _rAniTask = null; + protected RandomAnimationTask _rAniTask; /** The _current l hand id. */ private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -167,89 +171,122 @@ public class L2NpcInstance extends L2Character private int _scriptValue = 0; - /** - * Task launching the function onRandomAnimation(). - */ - protected class RandomAnimationTask implements Runnable + public class RandomAnimationTask implements Runnable { - /* - * (non-Javadoc) - * @see java.lang.Runnable#run() - */ + private final L2NpcInstance _npc; + private boolean _stopTask; + + public RandomAnimationTask(L2NpcInstance npc) + { + _npc = npc; + } + @Override public void run() { + if (_stopTask) + { + return; + } + try { - if (this != _rAniTask) + if (!_npc.isInActiveRegion()) { - return; // Shouldn't happen, but who knows... just to make sure every active npc has only one timer. + return; } - if (isMob()) + // Cancel further animation timers until intention is changed to ACTIVE again. + if (_npc.isAttackable() && (_npc.getAI().getIntention() != AI_INTENTION_ACTIVE)) { - // Cancel further animation timers until intention is changed to ACTIVE again. - if (getAI().getIntention() != AI_INTENTION_ACTIVE) - { - return; - } - } - else - { - if (!isInActiveRegion()) - { - return; - } - // update knownlist to remove playable which aren't in range any more - getKnownList().updateKnownObjects(); + return; } - if ((!isDead() && !isStunned() && !isSleeping() && !isParalyzed())) + if (!(_npc.isDead() || _npc.isStunned() || _npc.isSleeping() || _npc.isParalyzed())) { - onRandomAnimation(); + _npc.onRandomAnimation(Rnd.get(2, 3)); } startRandomAnimationTimer(); } - catch (Throwable t) + catch (Exception e) { } } + + /** + * Create a RandomAnimation Task that will be launched after the calculated delay. + */ + public void startRandomAnimationTimer() + { + if (!_npc.hasRandomAnimation() || _stopTask) + { + return; + } + + final int minWait = _npc.isAttackable() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION; + final int maxWait = _npc.isAttackable() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION; + + // Calculate the delay before the next animation + final int interval = Rnd.get(minWait, maxWait) * 1000; + + // Create a RandomAnimation Task that will be launched after the calculated delay + ThreadPool.schedule(this, interval); + } + + /** + * Stops the task from continuing and blocks it from continuing ever again. You need to create new task if you want to start it again. + */ + public void stopRandomAnimationTimer() + { + _stopTask = true; + } } - /** - * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance and create a new RandomAnimation Task.
- *
- */ - public void onRandomAnimation() - { - final int min = _customNpcInstance != null ? 1 : 2; - final int max = _customNpcInstance != null ? 13 : 3; - // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance - SocialAction sa = new SocialAction(getObjectId(), Rnd.get(min, max)); - broadcastPacket(sa); - } - - /** - * Create a RandomAnimation Task that will be launched after the calculated delay.
- *
- */ - public void startRandomAnimationTimer() + public void startRandomAnimationTask() { if (!hasRandomAnimation()) { return; } - final int minWait = isMob() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION; - final int maxWait = isMob() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION; + if (_rAniTask == null) + { + synchronized (this) + { + if (_rAniTask == null) + { + _rAniTask = new RandomAnimationTask(this); + } + } + } - // Calculate the delay before the next animation - final int interval = Rnd.get(minWait, maxWait) * 1000; - - // Create a RandomAnimation Task that will be launched after the calculated delay - _rAniTask = new RandomAnimationTask(); - ThreadPool.schedule(_rAniTask, interval); + _rAniTask.startRandomAnimationTimer(); + } + + public void stopRandomAnimationTask() + { + final RandomAnimationTask rAniTask = _rAniTask; + if (rAniTask != null) + { + rAniTask.stopRandomAnimationTimer(); + _rAniTask = null; + } + } + + /** + * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance and create a new RandomAnimation Task. + * @param animationId + */ + public void onRandomAnimation(int animationId) + { + // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance + final long now = System.currentTimeMillis(); + if ((now - _lastSocialBroadcast) > MINIMUM_SOCIAL_INTERVAL) + { + _lastSocialBroadcast = now; + broadcastPacket(new SocialAction(getObjectId(), animationId)); + } } /** @@ -3355,15 +3392,6 @@ public class L2NpcInstance extends L2Character } } - /** - * Checks if is mob. - * @return true, if is mob - */ - public boolean isMob() // rather delete this check - { - return false; // This means we use MAX_NPC_ANIMATION instead of MAX_MONSTER_ANIMATION - } - // Two functions to change the appearance of the equipped weapons on the NPC // This is only useful for a few NPCs and is most likely going to be called from AI /** diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 7e16986a99..262015a7fa 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -1620,13 +1620,7 @@ public class L2Attackable extends L2Npc @Override public boolean hasRandomAnimation() { - return (Config.MAX_MONSTER_ANIMATION > 0) && isRandomAnimationEnabled() && !(this instanceof L2GrandBossInstance); - } - - @Override - public boolean isMob() - { - return true; // This means we use MAX_MONSTER_ANIMATION instead of MAX_NPC_ANIMATION + return ((Config.MAX_MONSTER_ANIMATION > 0) && isRandomAnimationEnabled() && !(this instanceof L2GrandBossInstance)); } public void setCommandChannelTimer(CommandChannelTimer commandChannelTimer) diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 33451b4007..c23537c07b 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -16,8 +16,6 @@ */ package com.l2jmobius.gameserver.model.actor; -import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE; - import java.util.Collection; import java.util.Collections; import java.util.List; @@ -65,6 +63,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2TrainerInstance; import com.l2jmobius.gameserver.model.actor.instance.L2WarehouseInstance; import com.l2jmobius.gameserver.model.actor.stat.NpcStat; import com.l2jmobius.gameserver.model.actor.status.NpcStatus; +import com.l2jmobius.gameserver.model.actor.tasks.npc.RandomAnimationTask; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.model.entity.Castle; import com.l2jmobius.gameserver.model.entity.Fort; @@ -138,7 +137,7 @@ public class L2Npc extends L2Character private boolean _isTalkable = getTemplate().isTalkable(); private final boolean _isFakePlayer = getTemplate().isFakePlayer(); - protected RandomAnimationTask _rAniTask = null; + protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions private int _currentRHandId; // normally this shouldn't change from the template, but there exist exceptions private int _currentEnchant; // normally this shouldn't change from the template, but there exist exceptions @@ -241,48 +240,35 @@ public class L2Npc extends L2Character return getTemplate().getAISkills(AISkillScope.SHORT_RANGE); } - /** Task launching the function onRandomAnimation() */ - protected static class RandomAnimationTask implements Runnable + public void startRandomAnimationTask() { - private final L2Npc _npc; - - protected RandomAnimationTask(L2Npc npc) + if (!hasRandomAnimation()) { - _npc = npc; + return; } - @Override - public void run() + if (_rAniTask == null) { - try + synchronized (this) { - if (_npc.isMob()) + if (_rAniTask == null) { - // Cancel further animation timers until intention is changed to ACTIVE again. - if (_npc.getAI().getIntention() != AI_INTENTION_ACTIVE) - { - return; - } + _rAniTask = new RandomAnimationTask(this); } - else - { - if (!_npc.isInActiveRegion()) - { - return; - } - } - - if (!(_npc.isDead() || _npc.isStunned() || _npc.isSleeping() || _npc.isParalyzed())) - { - _npc.onRandomAnimation(Rnd.get(2, 3)); - } - - _npc.startRandomAnimationTask(); - } - catch (Exception e) - { } } + + _rAniTask.startRandomAnimationTimer(); + } + + public void stopRandomAnimationTask() + { + final RandomAnimationTask rAniTask = _rAniTask; + if (rAniTask != null) + { + rAniTask.stopRandomAnimationTimer(); + _rAniTask = null; + } } /** @@ -300,27 +286,6 @@ public class L2Npc extends L2Character } } - /** - * Create a RandomAnimation Task that will be launched after the calculated delay. - */ - public void startRandomAnimationTask() - { - if (!hasRandomAnimation()) - { - return; - } - - final int minWait = isMob() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION; - final int maxWait = isMob() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION; - - // Calculate the delay before the next animation - final int interval = Rnd.get(minWait, maxWait) * 1000; - - // Create a RandomAnimation Task that will be launched after the calculated delay - _rAniTask = new RandomAnimationTask(this); - ThreadPool.schedule(_rAniTask, interval); - } - /** * @return true if the server allows Random Animation. */ @@ -1460,11 +1425,6 @@ public class L2Npc extends L2Character } } - public boolean isMob() // rather delete this check - { - return false; // This means we use MAX_NPC_ANIMATION instead of MAX_MONSTER_ANIMATION - } - // Two functions to change the appearance of the equipped weapons on the NPC // This is only useful for a few NPCs and is most likely going to be called from AI public void setLHandId(int newWeaponId) diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/tasks/npc/RandomAnimationTask.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/tasks/npc/RandomAnimationTask.java new file mode 100644 index 0000000000..59d49884de --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/tasks/npc/RandomAnimationTask.java @@ -0,0 +1,104 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.actor.tasks.npc; + +import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.concurrent.ThreadPool; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.model.actor.L2Npc; + +/** + * @author Nik + */ +public class RandomAnimationTask implements Runnable +{ + private static final Logger LOGGER = Logger.getLogger(RandomAnimationTask.class.getName()); + private final L2Npc _npc; + private boolean _stopTask; + + public RandomAnimationTask(L2Npc npc) + { + _npc = npc; + } + + @Override + public void run() + { + if (_stopTask) + { + return; + } + + try + { + if (!_npc.isInActiveRegion()) + { + return; + } + + // Cancel further animation timers until intention is changed to ACTIVE again. + if (_npc.isAttackable() && (_npc.getAI().getIntention() != AI_INTENTION_ACTIVE)) + { + return; + } + + if (!(_npc.isDead() || _npc.isStunned() || _npc.isSleeping() || _npc.isParalyzed())) + { + _npc.onRandomAnimation(Rnd.get(2, 3)); + } + + startRandomAnimationTimer(); + } + catch (Exception e) + { + LOGGER.log(Level.SEVERE, "Execution of RandomAnimationTask has failed.", e); + } + } + + /** + * Create a RandomAnimation Task that will be launched after the calculated delay. + */ + public void startRandomAnimationTimer() + { + if (!_npc.hasRandomAnimation() || _stopTask) + { + return; + } + + final int minWait = _npc.isAttackable() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION; + final int maxWait = _npc.isAttackable() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION; + + // Calculate the delay before the next animation + final int interval = Rnd.get(minWait, maxWait) * 1000; + + // Create a RandomAnimation Task that will be launched after the calculated delay + ThreadPool.schedule(this, interval); + } + + /** + * Stops the task from continuing and blocks it from continuing ever again. You need to create new task if you want to start it again. + */ + public void stopRandomAnimationTimer() + { + _stopTask = true; + } +}