// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.gameManager; import engine.Enum; import engine.Enum.GameObjectType; import engine.objects.AbstractGameObject; import engine.objects.City; import engine.objects.PlayerCharacter; import engine.objects.Runegate; import org.pmw.tinylog.Logger; import java.util.Collection; /* * This class contains all methods necessary to drive periodic * updates of the game simulation from the main _exec loop. */ public enum SimulationManager { SERVERHEARTBEAT; private static SimulationManager instance = null; private static final long CITY_PULSE = 2000; private static final long RUNEGATE_PULSE = 3000; private static final long UPDATE_PULSE = 1000; private static final long FlIGHT_PULSE = 100; private long _cityPulseTime = System.currentTimeMillis() + CITY_PULSE; private long _runegatePulseTime = System.currentTimeMillis() + RUNEGATE_PULSE; private long _updatePulseTime = System.currentTimeMillis() + UPDATE_PULSE; private long _flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE; public static long HeartbeatDelta = 0; public static long currentHeartBeatDelta = 0; private SimulationManager() { // don't allow instantiation. } public static String getPopulationString() { String outString; String newLine = System.getProperty("line.separator"); outString = "[LUA_POPULATION()]" + newLine; outString += DbManager.CSSessionQueries.GET_POPULATION_STRING(); return outString; } /* * Update the simulation. *** Important: Whatever you do in here, do it damn * quick! */ public void tick() { /* * As we're on the main thread we must be sure to catch any possible * errors. * * IF something does occur, disable that particular heartbeat. Better * runegates stop working than the game itself! */ long start = System.currentTimeMillis(); try { if ((_flightPulseTime != 0) && (System.currentTimeMillis() > _flightPulseTime)) pulseFlight(); } catch (Exception e) { Logger.error( "Fatal error in City Pulse: DISABLED. Error Message : " + e.getMessage()); } try { if ((_updatePulseTime != 0) && (System.currentTimeMillis() > _updatePulseTime)) pulseUpdate(); } catch (Exception e) { Logger.error( "Fatal error in Update Pulse: DISABLED"); // _runegatePulseTime = 0; } try { if ((_runegatePulseTime != 0) && (System.currentTimeMillis() > _runegatePulseTime)) pulseRunegates(); } catch (Exception e) { Logger.error( "Fatal error in Runegate Pulse: DISABLED"); _runegatePulseTime = 0; } try { if ((_cityPulseTime != 0) && (System.currentTimeMillis() > _cityPulseTime)) pulseCities(); } catch (Exception e) { Logger.error( "Fatal error in City Pulse: DISABLED. Error Message : " + e.getMessage()); e.printStackTrace(); } long end = System.currentTimeMillis(); long delta = end - start; if (delta > SimulationManager.HeartbeatDelta) SimulationManager.HeartbeatDelta = delta; SimulationManager.currentHeartBeatDelta = delta; } /* * Mainline simulation update method: handles movement and regen for all * player characters */ private void pulseUpdate() { Collection playerList; playerList = DbManager.getList(GameObjectType.PlayerCharacter); // Call update() on each player in game if (playerList == null) return; for (AbstractGameObject ago : playerList) { PlayerCharacter player = (PlayerCharacter)ago; if (player == null) continue; player.update(); } _updatePulseTime = System.currentTimeMillis() + 500; } private void pulseFlight() { Collection playerList; playerList = DbManager.getList(GameObjectType.PlayerCharacter); // Call update() on each player in game if (playerList == null) return; for (AbstractGameObject ago : playerList) { PlayerCharacter player = (PlayerCharacter)ago; if (player == null) continue; player.updateFlight(); } _flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE; } private void pulseCities() { City city; // *** Refactor: Need a list cached somewhere as it doesn't change very // often at all. Have a cityListIsDirty boolean that gets set if it // needs an update. Will speed up this method a great deal. Collection cityList = DbManager.getList(Enum.GameObjectType.City); if (cityList == null) { Logger.info( "City List null"); return; } for (AbstractGameObject cityObject : cityList) { city = (City) cityObject; city.onEnter(); } _cityPulseTime = System.currentTimeMillis() + CITY_PULSE; } /* * Method runs proximity collision detection for all active portals on the * game's Runegates */ private void pulseRunegates() { for (Runegate runegate : Runegate._runegates.values()) { runegate.collidePortals(); } _runegatePulseTime = System.currentTimeMillis() + RUNEGATE_PULSE; } }