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.<BR><BR>
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<L2WorldRegion> _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 <BR>
* If L2Object is a L2PcInstance, Add the L2PcInstance in the L2ObjectHashSet(L2PcInstance) _allPlayers
* containing L2PcInstance of all player in game in this L2WorldRegion <BR>
@@ -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.<BR><BR>
*/
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)
{