Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2MinionInstance.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2MinionInstance.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2MinionInstance.java (working copy) @@ -18,7 +18,10 @@ */ package net.sf.l2j.gameserver.model.actor.instance; +import net.sf.l2j.gameserver.ai.L2AttackableAI; import net.sf.l2j.gameserver.model.L2Character; +import net.sf.l2j.gameserver.model.L2World; +import net.sf.l2j.gameserver.model.L2WorldRegion; import net.sf.l2j.gameserver.templates.L2NpcTemplate; /** @@ -69,6 +72,12 @@ { // Notify Leader that Minion has Spawned getLeader().notifyMinionSpawned(this); + + // check the region where this mob is, do not activate the AI if region is inactive. + L2WorldRegion region = L2World.getInstance().getRegion(getX(),getY()); + if ((region !=null) && (!region.isActive())) + ((L2AttackableAI) getAI()).stopAITask(); + } /** Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2GuardInstance.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2GuardInstance.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2GuardInstance.java (working copy) @@ -23,9 +23,12 @@ import net.sf.l2j.Config; import net.sf.l2j.gameserver.ThreadPoolManager; import net.sf.l2j.gameserver.ai.CtrlIntention; +import net.sf.l2j.gameserver.ai.L2AttackableAI; import net.sf.l2j.gameserver.model.L2Attackable; import net.sf.l2j.gameserver.model.L2CharPosition; import net.sf.l2j.gameserver.model.L2Character; +import net.sf.l2j.gameserver.model.L2World; +import net.sf.l2j.gameserver.model.L2WorldRegion; import net.sf.l2j.gameserver.model.actor.knownlist.GuardKnownList; import net.sf.l2j.gameserver.serverpackets.ActionFailed; import net.sf.l2j.gameserver.serverpackets.MyTargetSelected; @@ -131,7 +134,12 @@ _homeZ = getZ(); if (Config.DEBUG) - _log.finer(getObjectId()+": Home location set to"+" X:" + _homeX + " Y:" + _homeY + " Z:" + _homeZ); + _log.finer(getObjectId()+": Home location set to"+" X:" + _homeX + " Y:" + _homeY + " Z:" + _homeZ); + + // check the region where this mob is, do not activate the AI if region is inactive. + L2WorldRegion region = L2World.getInstance().getRegion(getX(),getY()); + if ((region !=null) && (!region.isActive())) + ((L2AttackableAI) getAI()).stopAITask(); } Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java (working copy) @@ -76,7 +76,7 @@ import net.sf.l2j.gameserver.templates.L2Item; import net.sf.l2j.gameserver.templates.L2NpcTemplate; import net.sf.l2j.gameserver.templates.L2Weapon; - +import net.sf.l2j.gameserver.model.L2WorldRegion; /** * This class represents a Non-Player-Character in the world. It can be a monster or a friendly character. * It also uses a template to fetch some static values. The templates are hardcoded in the client, so we can rely on them.

Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2WorldRegion.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2WorldRegion.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2WorldRegion.java (working copy) @@ -23,12 +23,16 @@ import java.util.logging.Logger; import javolution.util.FastList; +import java.util.concurrent.ScheduledFuture; import net.sf.l2j.Config; import net.sf.l2j.gameserver.SpawnTable; import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance; import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; +import net.sf.l2j.gameserver.ai.L2AttackableAI; +import net.sf.l2j.gameserver.ThreadPoolManager; import net.sf.l2j.util.L2ObjectSet; + /** * This class ... * @@ -46,6 +50,8 @@ private List _surroundingRegions; private int tileX, tileY; + private Boolean _active = false; + private ScheduledFuture _neighborsTask = null; public L2WorldRegion(int pTileX, int pTileY) { @@ -56,9 +62,172 @@ this.tileX = pTileX; this.tileY = pTileY; + + // default a newly initialized region to inactive + _active = false; } + + /** Task of AI notification */ + public class NeighborsTask implements Runnable + { + private boolean _isActivating; + + public NeighborsTask(boolean isActivating) + { + _isActivating = isActivating; + } + + public void run() + { + if (_isActivating) + { + // for each neighbor, if it's not active, activate. + for (L2WorldRegion neighbor: getSurroundingRegions()) + neighbor.setActive(true); + } + else + { + if(areNeighborsEmpty()) + setActive(false); + + // check and deactivate + for (L2WorldRegion neighbor: getSurroundingRegions()) + if(neighbor.areNeighborsEmpty()) + neighbor.setActive(false); + } + } + } + + private void switchAI(Boolean isOn) + { + int c = 0; + if (!isOn) + { + for(L2Object o: _visibleObjects) + if (o instanceof L2Attackable) + { + c++; + L2Attackable mob = (L2Attackable)o; + // Set target to null and cancel Attack or Cast + mob.setTarget(null); + + // Stop movement + mob.stopMove(null); + + // Stop HP/MP/CP Regeneration task + mob.getStatus().stopHpMpRegeneration(); + + // Stop all active skills effects in progress on the L2Character + mob.stopAllEffects(); + + // stop the ai tasks + ((L2AttackableAI) mob.getAI()).stopAITask(); + } + System.out.println(c+ " mobs were turned off"); + } + else + { + for(L2Object o: _visibleObjects) + if (o instanceof L2Attackable) + { + c++; + L2Attackable mob = (L2Attackable)o; + // Start HP/MP/CP Regeneration task + mob.getStatus().startHpMpRegeneration(); + + // start the ai + ((L2AttackableAI) mob.getAI()).startAITask(); + } + System.out.println(c+ " mobs were turned on"); + } + + } + public Boolean isActive() + { + return _active; + } + + // check if all 9 neighbors (including self) are inactive or active but with no players. + // returns true if the above condition is met. + public Boolean areNeighborsEmpty() + { + // if this region is occupied, return false. + if (isActive() && (_allPlayers.size() > 0 )) + return false; + + // if any one of the neighbors is occupied, return false + for (L2WorldRegion neighbor: _surroundingRegions) + if (neighbor.isActive() && (neighbor._allPlayers.size() > 0)) + return false; + + // in all other cases, return true. + return true; + } + /** + * this function turns this region's AI and geodata on or off + * @param value + */ + public void setActive(Boolean value) + { + if (_active == value) + return; + + _active = value; + + // turn the AI on or off to match the region's activation. + switchAI(value); + + // TODO + // turn the geodata on or off to match the region's activation. + if(value) + _log.fine("Starting Grid " + tileX + ","+ tileY); + else + _log.fine("Stoping Grid " + tileX + ","+ tileY); + } + + /** Immediately sets self as active and starts a timer to set neighbors as active + * this timer is to avoid turning on neighbors in the case when a person just + * teleported into a region and then teleported out immediately...there is no + * reason to activate all the neighbors in that case. + */ + public void startActivation() + { + // first set self to active and do self-tasks... + setActive(true); + + // if the timer to deactivate neighbors is running, cancel it. + if(_neighborsTask !=null) + { + _neighborsTask.cancel(true); + _neighborsTask = null; + } + + // then, set a timer to activate the neighbors + _neighborsTask = ThreadPoolManager.getInstance().scheduleGeneral(new NeighborsTask(true), 30000); + } + + /** starts a timer to set neighbors (including self) as inactive + * this timer is to avoid turning off neighbors in the case when a person just + * moved out of a region that he may very soon return to. There is no reason + * to turn self & neighbors off in that case. + */ + public void startDeactivation() + { + // if the timer to activate neighbors is running, cancel it. + if(_neighborsTask !=null) + { + _neighborsTask.cancel(true); + _neighborsTask = null; + } + + // start a timer to "suggest" a deactivate to self and neighbors. + // suggest means: first check if a neighbor has L2PcInstances in it. If not, deactivate. + _neighborsTask = ThreadPoolManager.getInstance().scheduleGeneral(new NeighborsTask(false), 30000); + } + + /** * Add the L2Object in the L2ObjectHashSet(L2Object) _visibleObjects containing L2Object visible in this L2WorldRegion
* If L2Object is a L2PcInstance, Add the L2PcInstance in the L2ObjectHashSet(L2PcInstance) _allPlayers * containing L2PcInstance of all player in game in this L2WorldRegion
@@ -73,6 +242,10 @@ if (object instanceof L2PcInstance) { _allPlayers.put((L2PcInstance) object); + + // if this is the first player to enter the region, activate self & neighbors + if (_allPlayers.size() == 1 ) + startActivation(); } } @@ -92,6 +265,9 @@ if (object instanceof L2PcInstance) { _allPlayers.remove((L2PcInstance) object); + + if (_allPlayers.size() == 0 ) + startDeactivation(); } } Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2World.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2World.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2World.java (working copy) @@ -46,7 +46,7 @@ * note, shifting by 15 will result in regions corresponding to map tiles * shifting by 12 divides one tile to 8x8 regions */ - private static final int SHIFT_BY = 13; + private static final int SHIFT_BY = 12; /** Map dimensions */ public static final int MAP_MIN_X = -131072; @@ -75,7 +75,6 @@ private L2WorldRegion[][] _worldRegions; - /** * Constructor of L2World.

*/ Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2Attackable.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2Attackable.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/model/L2Attackable.java (working copy) @@ -1591,7 +1591,6 @@ return true; } - @Override public void OnSpawn() { // Clear mob spoil,seed @@ -1604,6 +1603,11 @@ _absorbersList = null; setWalking(); + + // check the region where this mob is, do not activate the AI if region is inactive. + L2WorldRegion region = L2World.getInstance().getRegion(getX(),getY()); + if ((region !=null) && (!region.isActive())) + ((L2AttackableAI) getAI()).stopAITask(); } public void setSeeded(int id, int seederLvl) Index: D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/lib/Rnd.java =================================================================== --- D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/lib/Rnd.java (revision 2117) +++ D:/l2jc4/L2_GameServer_c4/java/net/sf/l2j/gameserver/lib/Rnd.java (working copy) @@ -18,7 +18,7 @@ */ package net.sf.l2j.gameserver.lib; -import java.util.Random; +import net.sf.l2j.util.MTRandom; /**$ * @@ -27,7 +27,7 @@ */ public class Rnd { - private static Random _rnd = new Random();; + private static MTRandom _rnd = new MTRandom(); public static final float get() // get random number from 0 to 1 { @@ -41,7 +41,7 @@ public static final int get(int min, int max) // get random number from min to max (not max-1 !) { - return min + _rnd.nextInt(max - min + 1); + return min + (int)Math.floor(_rnd.nextDouble()*(max - min + 1)); } public static final int nextInt(int n) {