Browse Source

mob AI new thread

master
FatBoy-DOTC 1 year ago
parent
commit
140a9bd084
  1. 4
      src/engine/InterestManagement/InterestManager.java
  2. 120
      src/engine/ai/MobileFSMManager.java
  3. 14
      src/engine/ai/utilities/PowerUtilities.java
  4. 1
      src/engine/db/handlers/dbMobBaseHandler.java
  5. 46
      src/engine/devcmd/cmds/HeartbeatCmd.java
  6. 1
      src/engine/gameManager/DevCmdManager.java
  7. 19
      src/engine/mobileAI/MobAI.java
  8. 46
      src/engine/mobileAI/Threads/MobAIThread.java
  9. 11
      src/engine/mobileAI/Threads/MobRespawnThread.java
  10. 2
      src/engine/mobileAI/utilities/CombatUtilities.java
  11. 8
      src/engine/mobileAI/utilities/MovementUtilities.java
  12. 4
      src/engine/objects/AbstractIntelligenceAgent.java
  13. 4
      src/engine/objects/Mob.java
  14. 1
      src/engine/powers/poweractions/CreateMobPowerAction.java
  15. 2
      src/engine/powers/poweractions/MobRecallPowerAction.java
  16. 10
      src/engine/server/world/WorldServer.java

4
src/engine/InterestManagement/InterestManager.java

@ -458,7 +458,7 @@ public enum InterestManager implements Runnable { @@ -458,7 +458,7 @@ public enum InterestManager implements Runnable {
continue;
awonpc.playerAgroMap.put(player.getObjectUUID(), false);
//MobileFSM.setAwake(awonpc, false);
//MobAI.setAwake(awonpc, false);
((Mob) awonpc).setCombatTarget(null);
// IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000));
// awonpc.enableIntelligence();
@ -475,7 +475,7 @@ public enum InterestManager implements Runnable { @@ -475,7 +475,7 @@ public enum InterestManager implements Runnable {
awonpc.playerAgroMap.put(player.getObjectUUID(), false);
if (awonpc.isMob())
//MobileFSM.setAwake(awonpc, false);
//MobAI.setAwake(awonpc, false);
((Mob) awonpc).setCombatTarget(null);
// IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000));
// awonpc.enableIntelligence();

120
src/engine/ai/MobileFSMManager.java

@ -1,120 +0,0 @@ @@ -1,120 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.ai;
import engine.gameManager.ConfigManager;
import engine.gameManager.ZoneManager;
import engine.objects.Mob;
import engine.objects.Zone;
import engine.util.ThreadUtils;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.time.Duration;
import java.time.Instant;
public class MobileFSMManager {
private static final MobileFSMManager INSTANCE = new MobileFSMManager();
public static Duration executionTime = Duration.ofNanos(1);
public static Duration executionMax = Duration.ofNanos(1);
//AI variables moved form mb_server_statics
public static int AI_BASE_AGGRO_RANGE = 60;
public static int AI_DROP_AGGRO_RANGE = 60;
public static int AI_PULSE_MOB_THRESHOLD = 200;
public static int AI_PATROL_DIVISOR = 15;
public static int AI_POWER_DIVISOR = 20;
private volatile boolean alive;
private long timeOfKill = -1;
private MobileFSMManager() {
Runnable worker = new Runnable() {
@Override
public void run() {
execution();
}
};
alive = true;
//assign the AI varibales base don difficulty scaling from config file:
float difficulty = Float.parseFloat(ConfigManager.MB_AI_AGGRO_RANGE.getValue());
AI_BASE_AGGRO_RANGE = (int) (100 * difficulty); // range at which aggressive mobs will attack you
difficulty = Float.parseFloat(ConfigManager.MB_AI_CAST_FREQUENCY.getValue());
AI_POWER_DIVISOR = (int) (20 * (1.5f - difficulty)); //duration between mob casts
Thread t = new Thread(worker, "MobileFSMManager");
t.start();
}
public static MobileFSMManager getInstance() {
return INSTANCE;
}
/**
* Stops the MobileFSMManager
*/
public void shutdown() {
if (alive) {
alive = false;
timeOfKill = System.currentTimeMillis();
}
}
public boolean isAlive() {
return this.alive;
}
private void execution() {
//Load zone threshold once.
long mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD;
Instant startTime;
while (alive) {
ThreadUtils.sleep(1);
if (System.currentTimeMillis() > mobPulse) {
startTime = Instant.now();
for (Zone zone : ZoneManager.getAllZones()) {
for (Mob mob : zone.zoneMobSet) {
try {
if (mob != null)
MobileFSM.DetermineAction(mob);
} catch (Exception e) {
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
e.printStackTrace();
}
}
}
executionTime = Duration.between(startTime, Instant.now());
if (executionTime.compareTo(executionMax) > 0)
executionMax = executionTime;
mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD;
Logger.info("MobileFSM cycle completed: " + DateTime.now());
}
}
}
}

14
src/engine/ai/utilities/PowerUtilities.java

@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.ai.utilities;
public class PowerUtilities {
}

1
src/engine/db/handlers/dbMobBaseHandler.java

@ -10,7 +10,6 @@ @@ -10,7 +10,6 @@
package engine.db.handlers;
import engine.Enum.GameObjectType;
import engine.ai.MobileFSMManager;
import engine.gameManager.DbManager;
import engine.objects.MobBase;
import engine.objects.MobBaseEffects;

46
src/engine/devcmd/cmds/HeartbeatCmd.java

@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.devcmd.cmds;
import engine.ai.MobileFSMManager;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.SimulationManager;
import engine.objects.AbstractGameObject;
import engine.objects.PlayerCharacter;
public class HeartbeatCmd extends AbstractDevCmd {
public HeartbeatCmd() {
super("heartbeat");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
this.throwbackInfo(pc, "Heartbeat : " + SimulationManager.executionTime.toMillis() + "ms");
this.throwbackInfo(pc, "Heartbeat Max: " + SimulationManager.executionMax.toMillis() + "ms");
this.throwbackInfo(pc, "FSM: " + MobileFSMManager.executionTime.toMillis() + "ms");
this.throwbackInfo(pc, "FSM max: " + MobileFSMManager.executionMax.toMillis() + "ms");
}
@Override
protected String _getHelpString() {
return "Displays simulation metrics";
}
@Override
protected String _getUsageString() {
return "' ./heartbeat";
}
}

1
src/engine/gameManager/DevCmdManager.java

@ -135,7 +135,6 @@ public enum DevCmdManager { @@ -135,7 +135,6 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new SetNpcEquipSetCmd());
DevCmdManager.registerDevCmd(new SetBuildingAltitudeCmd());
DevCmdManager.registerDevCmd(new ResetLevelCmd());
DevCmdManager.registerDevCmd(new HeartbeatCmd());
DevCmdManager.registerDevCmd(new SetNpcNameCmd());
DevCmdManager.registerDevCmd(new SetNpcMobbaseCmd());
DevCmdManager.registerDevCmd(new DespawnCmd());

19
src/engine/ai/MobileFSM.java → src/engine/mobileAI/MobAI.java

@ -5,13 +5,14 @@ @@ -5,13 +5,14 @@
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.ai;
package engine.mobileAI;
import engine.Enum;
import engine.Enum.DispatchChannel;
import engine.InterestManagement.WorldGrid;
import engine.ai.utilities.CombatUtilities;
import engine.ai.utilities.MovementUtilities;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.utilities.CombatUtilities;
import engine.mobileAI.utilities.MovementUtilities;
import engine.gameManager.*;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
@ -33,7 +34,7 @@ import java.util.concurrent.ThreadLocalRandom; @@ -33,7 +34,7 @@ import java.util.concurrent.ThreadLocalRandom;
import static engine.math.FastMath.sqr;
public class MobileFSM {
public class MobAI {
private static void AttackTarget(Mob mob, AbstractWorldObject target) {
@ -212,7 +213,7 @@ public class MobileFSM { @@ -212,7 +213,7 @@ public class MobileFSM {
rwss.setPlayer(mob);
DispatchMessage.sendToAllInRange(mob, rwss);
}
int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobileFSMManager.AI_PATROL_DIVISOR * 0.5f), MobileFSMManager.AI_PATROL_DIVISOR) + MobileFSMManager.AI_PATROL_DIVISOR;
int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobAIThread.AI_PATROL_DIVISOR * 0.5f), MobAIThread.AI_PATROL_DIVISOR) + MobAIThread.AI_PATROL_DIVISOR;
if (mob.stopPatrolTime + (patrolDelay * 1000) > System.currentTimeMillis())
//early exit while waiting to patrol again
return;
@ -269,7 +270,7 @@ public class MobileFSM { @@ -269,7 +270,7 @@ public class MobileFSM {
return false;
}
int castRoll = ThreadLocalRandom.current().nextInt(101);
if(castRoll <= MobileFSMManager.AI_POWER_DIVISOR){
if(castRoll <= MobAIThread.AI_POWER_DIVISOR){
return false;
}
if (mob.nextCastTime == 0)
@ -341,7 +342,7 @@ public class MobileFSM { @@ -341,7 +342,7 @@ public class MobileFSM {
PowersManager.finishUseMobPower(msg, mob, 0, 0);
// Default minimum seconds between cast = 10
float randomCooldown = (ThreadLocalRandom.current().nextInt(150) + 100) * 0.01f;
mob.nextCastTime = System.currentTimeMillis() + (long)((mobPower.getCooldown() + (MobileFSMManager.AI_POWER_DIVISOR * 1000)) * randomCooldown);
mob.nextCastTime = System.currentTimeMillis() + (long)((mobPower.getCooldown() + (MobAIThread.AI_POWER_DIVISOR * 1000)) * randomCooldown);
return true;
}
} catch(Exception e){
@ -504,7 +505,7 @@ public class MobileFSM { @@ -504,7 +505,7 @@ public class MobileFSM {
}
if(aiAgent.combatTarget == null) {
//look for pets to aggro if no players found to aggro
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(aiAgent, MobileFSMManager.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_PET);
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(aiAgent, MobAIThread.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_PET);
for (AbstractWorldObject awoMob : awoList) {
//dont scan self.
if (aiAgent.equals(awoMob))
@ -655,7 +656,7 @@ public class MobileFSM { @@ -655,7 +656,7 @@ public class MobileFSM {
CheckForAggro(mob);
}
}
if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobileFSMManager.AI_BASE_AGGRO_RANGE * 0.5f)) {
if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f)) {
return;
}
if (mob.isPlayerGuard() && !mob.despawned) {

46
src/engine/mobileAI/Threads/MobAIThread.java

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
package engine.mobileAI.Threads;
import engine.mobileAI.MobAI;
import engine.gameManager.ZoneManager;
import engine.objects.Mob;
import engine.objects.Zone;
import org.pmw.tinylog.Logger;
public class MobAIThread implements Runnable{
public static int AI_BASE_AGGRO_RANGE = 60;
public static int AI_DROP_AGGRO_RANGE = 60;
public static int AI_PULSE_MOB_THRESHOLD = 200;
public static int AI_PATROL_DIVISOR = 15;
public static int AI_POWER_DIVISOR = 20;
// Thread constructor
public MobAIThread() {
Logger.info(" MobAIThread thread has started!");
}
@Override
public void run() {
while (true) {
for (Zone zone : ZoneManager.getAllZones()) {
for (Mob mob : zone.zoneMobSet) {
try {
if (mob != null)
MobAI.DetermineAction(mob);
} catch (Exception e) {
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
e.printStackTrace();
}
}
}
}
}
public static void startAIThread() {
Thread aiThread;
aiThread = new Thread(new MobAIThread());
aiThread.setName("aiThread");
aiThread.start();
}
}

11
src/engine/workthreads/MobRespawnThread.java → src/engine/mobileAI/Threads/MobRespawnThread.java

@ -16,18 +16,12 @@ @@ -16,18 +16,12 @@
// www.magicbane.com
package engine.workthreads;
import engine.Enum.DispatchChannel;
package engine.mobileAI.Threads;
import engine.gameManager.ZoneManager;
import engine.net.Dispatch;
import engine.objects.Mob;
import engine.objects.Zone;
import org.pmw.tinylog.Logger;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.LongAdder;
/**
* Thread blocks until MagicBane dispatch messages are
* enqueued then processes them in FIFO order. The collection
@ -45,7 +39,6 @@ public class MobRespawnThread implements Runnable { @@ -45,7 +39,6 @@ public class MobRespawnThread implements Runnable {
// Thread constructor
public MobRespawnThread() {
Boolean isAlive = false;
Logger.info(" MobRespawnThread thread has started!");
}
@ -66,10 +59,8 @@ public class MobRespawnThread implements Runnable { @@ -66,10 +59,8 @@ public class MobRespawnThread implements Runnable {
}
}
public static void startRespawnThread() {
Thread respawnThread;
respawnThread = new Thread(new MobRespawnThread());
respawnThread.setName("respawnThread");
respawnThread.start();
}

2
src/engine/ai/utilities/CombatUtilities.java → src/engine/mobileAI/utilities/CombatUtilities.java

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
// www.magicbane.com
package engine.ai.utilities;
package engine.mobileAI.utilities;
import engine.Enum.*;
import engine.gameManager.ChatManager;

8
src/engine/ai/utilities/MovementUtilities.java → src/engine/mobileAI/utilities/MovementUtilities.java

@ -7,13 +7,13 @@ @@ -7,13 +7,13 @@
// www.magicbane.com
package engine.ai.utilities;
package engine.mobileAI.utilities;
import engine.Enum;
import engine.Enum.GameObjectType;
import engine.Enum.ModType;
import engine.Enum.SourceType;
import engine.ai.MobileFSMManager;
import engine.mobileAI.Threads.MobAIThread;
import engine.exception.MsgSendException;
import engine.gameManager.MovementManager;
import engine.math.Vector3fImmutable;
@ -79,7 +79,7 @@ public class MovementUtilities { @@ -79,7 +79,7 @@ public class MovementUtilities {
zoneRange = agent.getSpawnRadius();
return distanceSquaredToTarget < sqr(MobileFSMManager.AI_DROP_AGGRO_RANGE + zoneRange);
return distanceSquaredToTarget < sqr(MobAIThread.AI_DROP_AGGRO_RANGE + zoneRange);
}
@ -89,7 +89,7 @@ public class MovementUtilities { @@ -89,7 +89,7 @@ public class MovementUtilities {
Vector3fImmutable tl = target.getLoc();
float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target
float range = MobileFSMManager.AI_BASE_AGGRO_RANGE;
float range = MobAIThread.AI_BASE_AGGRO_RANGE;
if (agent.isPlayerGuard())
range = 150;

4
src/engine/objects/AbstractIntelligenceAgent.java

@ -14,7 +14,7 @@ import engine.Enum.GameObjectType; @@ -14,7 +14,7 @@ import engine.Enum.GameObjectType;
import engine.Enum.ModType;
import engine.Enum.SourceType;
import engine.InterestManagement.WorldGrid;
import engine.ai.MobileFSMManager;
import engine.mobileAI.Threads.MobAIThread;
import engine.gameManager.ZoneManager;
import engine.math.Vector3fImmutable;
import engine.net.Dispatch;
@ -190,7 +190,7 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter { @@ -190,7 +190,7 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
public abstract AbstractWorldObject getFearedObject();
public float getAggroRange() {
float ret = MobileFSMManager.AI_BASE_AGGRO_RANGE;
float ret = MobAIThread.AI_BASE_AGGRO_RANGE;
if (this.bonuses != null)
ret *= (1 + this.bonuses.getFloatPercentAll(ModType.ScanRange, SourceType.None));
return ret;

4
src/engine/objects/Mob.java

@ -13,7 +13,7 @@ import ch.claude_martin.enumbitset.EnumBitSet; @@ -13,7 +13,7 @@ import ch.claude_martin.enumbitset.EnumBitSet;
import engine.Enum;
import engine.Enum.*;
import engine.InterestManagement.WorldGrid;
import engine.ai.MobileFSMManager;
import engine.mobileAI.Threads.MobAIThread;
import engine.exception.SerializationException;
import engine.gameManager.*;
import engine.job.JobScheduler;
@ -630,7 +630,7 @@ public class Mob extends AbstractIntelligenceAgent { @@ -630,7 +630,7 @@ public class Mob extends AbstractIntelligenceAgent {
public static void HandleAssistedAggro(PlayerCharacter source, PlayerCharacter target) {
HashSet<AbstractWorldObject> mobsInRange = WorldGrid.getObjectsInRangePartial(source, MobileFSMManager.AI_DROP_AGGRO_RANGE, MBServerStatics.MASK_MOB);
HashSet<AbstractWorldObject> mobsInRange = WorldGrid.getObjectsInRangePartial(source, MobAIThread.AI_DROP_AGGRO_RANGE, MBServerStatics.MASK_MOB);
for (AbstractWorldObject awo : mobsInRange) {
Mob mob = (Mob) awo;

1
src/engine/powers/poweractions/CreateMobPowerAction.java

@ -11,7 +11,6 @@ package engine.powers.poweractions; @@ -11,7 +11,6 @@ package engine.powers.poweractions;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.ai.utilities.MovementUtilities;
import engine.gameManager.DbManager;
import engine.gameManager.MovementManager;
import engine.gameManager.NPCManager;

2
src/engine/powers/poweractions/MobRecallPowerAction.java

@ -40,7 +40,7 @@ public class MobRecallPowerAction extends AbstractPowerAction { @@ -40,7 +40,7 @@ public class MobRecallPowerAction extends AbstractPowerAction {
MovementManager.translocate(awoac, awoac.getBindLoc(), null);
if (awoac.getObjectType() == GameObjectType.Mob) {
//MobileFSM.setAwake((Mob)awoac,true);
//MobAI.setAwake((Mob)awoac,true);
((Mob) awoac).setCombatTarget(null);
}

10
src/engine/server/world/WorldServer.java

@ -17,8 +17,8 @@ import engine.Enum.SupportMsgType; @@ -17,8 +17,8 @@ import engine.Enum.SupportMsgType;
import engine.InterestManagement.HeightMap;
import engine.InterestManagement.RealmMap;
import engine.InterestManagement.WorldGrid;
import engine.ai.MobileFSMManager;
import engine.workthreads.MobRespawnThread;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.Threads.MobRespawnThread;
import engine.db.archive.DataWarehouse;
import engine.exception.MsgSendException;
import engine.gameManager.*;
@ -459,8 +459,9 @@ public class WorldServer { @@ -459,8 +459,9 @@ public class WorldServer {
Logger.info("Running Heraldry Audit for Deleted Players");
Heraldry.AuditHeraldry();
Logger.info("Starting Mobile AI FSM");
MobileFSMManager.getInstance();
//intiate mob ai thread
Logger.info("Starting Mob AI Thread");
MobAIThread.startAIThread();
for (Zone zone : ZoneManager.getAllZones()) {
if (zone.getHeightMap() != null) {
@ -485,6 +486,7 @@ public class WorldServer { @@ -485,6 +486,7 @@ public class WorldServer {
//intiate mob respawn thread
Logger.info("Starting Mob Respawn Thread");
MobRespawnThread.startRespawnThread();
// Run maintenance
MaintenanceManager.dailyMaintenance();

Loading…
Cancel
Save