Index: C:/workspace/L2_GameServer_c4/java/net/sf/l2j/gameserver/GameTimeController.java =================================================================== --- C:/workspace/L2_GameServer_c4/java/net/sf/l2j/gameserver/GameTimeController.java (revision 1694) +++ C:/workspace/L2_GameServer_c4/java/net/sf/l2j/gameserver/GameTimeController.java (working copy) @@ -42,20 +42,20 @@ public class GameTimeController { static final Logger _log = Logger.getLogger(GameTimeController.class.getName()); - + public static final int TICKS_PER_SECOND = 10; public static final int MILLIS_IN_TICK = 1000 / TICKS_PER_SECOND; - + private static GameTimeController _instance = new GameTimeController(); - - protected static int _gameTicks; + + protected static int _gameTicks; protected static long _gameStartTime; protected static boolean _isNight; - - private static List movingObjects = new FastList(); - - protected static TimerThread _timer; + private static List movingObjects = new FastList(); + + protected static TimerThread _timer; + /** * one ingame day is 240 real minutes */ @@ -63,36 +63,34 @@ { return _instance; } - + private GameTimeController() { - _gameStartTime = System.currentTimeMillis()- 3600000; // offset so that the server starts a day begin - _gameTicks = 3600000/MILLIS_IN_TICK; // offset so that the server starts a day begin + _gameStartTime = System.currentTimeMillis() - 3600000; // offset so that the server starts a day begin + _gameTicks = 3600000 / MILLIS_IN_TICK; // offset so that the server starts a day begin _timer = new TimerThread(); _timer.start(); - ClientScheduler.getInstance().scheduleLowAtFixedRate( - new TimerWatcher(), 0, 1000); - ClientScheduler.getInstance().scheduleLowAtFixedRate( - new BroadcastSunState(), 0, 60*60*1000 - ); + ClientScheduler.getInstance().scheduleLowAtFixedRate(new TimerWatcher(), 0, 1000); + ClientScheduler.getInstance().scheduleLowAtFixedRate(new BroadcastSunState(), 0, 60 * 60 * 1000); } - - public boolean isNowNight() { + + public boolean isNowNight() + { return _isNight; } - + public int getGameTime() { - return (_gameTicks / (TICKS_PER_SECOND*10)); + return (_gameTicks / (TICKS_PER_SECOND * 10)); } - + public static int getGameTicks() { return _gameTicks; } - + /** * Add a L2Character to movingObjects of GameTimeController.

* @@ -102,12 +100,11 @@ * @param cha The L2Character to add to movingObjects of GameTimeController * */ - public synchronized void registerMovingObject(L2Character cha) + public synchronized void registerMovingObject(L2Character cha) { - if (!movingObjects.contains(cha)) - movingObjects.add(cha); + if (!movingObjects.contains(cha)) movingObjects.add(cha); } - + /** * Move all L2Characters contained in movingObjects of GameTimeController.

* @@ -120,54 +117,53 @@ *
  • Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with EVT_ARRIVED


  • * */ - protected synchronized void moveObjects() + protected synchronized void moveObjects() { // Get all L2Character from the ArrayList movingObjects and put them into a table L2Character[] chars = movingObjects.toArray(new L2Character[movingObjects.size()]); - + // Create an ArrayList to contain all L2Character that are arrived to destination List ended = null; - + // Go throw the table containing L2Character in movement - for (int i=0; i < chars.length; i++) + for (int i = 0; i < chars.length; i++) { - + L2Character cha = chars[i]; - + // Update the position of the L2Character and return True if the movement is finished boolean end = cha.updatePosition(_gameTicks); - + // If movement is finished, the L2Character is removed from movingObjects and added to the ArrayList ended if (end) { movingObjects.remove(cha); - if (ended == null) - ended = new FastList(); - + if (ended == null) ended = new FastList(); + ended.add(cha); } } - + // Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object // then notify AI with EVT_ARRIVED if (ended != null) ClientScheduler.getInstance().scheduleLow(new MovingObjectArrived(ended), 10); - + } - + public void stopTimer() { _timer._stop = true; } - + class TimerThread extends Thread { protected boolean _stop; - protected Exception _error; - + protected Exception _error; + public TimerThread() { - super("GameTimeController"); + super("GameTimeController"); setDaemon(true); setPriority(MAX_PRIORITY); _stop = false; @@ -176,28 +172,39 @@ public void run() { - try { - int _oldTicks; + try + { for (;;) { - long runtime = System.currentTimeMillis() - _gameStartTime; - _oldTicks=_gameTicks; - _gameTicks = (int)(runtime / MILLIS_IN_TICK); - if(_oldTicks!=_gameTicks) moveObjects(); - else yield(); - - runtime = System.currentTimeMillis() - _gameStartTime; - int sleepTime = 1 + MILLIS_IN_TICK - ((int)runtime) % MILLIS_IN_TICK; - sleep( sleepTime ); - if (_stop) - throw new Exception("stopTimer() was called"); + int _oldTicks=_gameTicks; // save old ticks value to avoid moving objects 2x in same tick + long runtime = System.currentTimeMillis() - _gameStartTime; // from server boot to now + + _gameTicks = (int) (runtime / MILLIS_IN_TICK); // new ticks value (ticks now) + + if (_oldTicks != _gameTicks) moveObjects(); // XXX: if this makes objects go slower, remove it + // but I think it can't make that effect. is it better to call moveObjects() twice in same + // tick to make-up for missed tick ? or is it better to ignore missed tick ? + // (will happen very rarely but it will happen ... on garbage collection definitely) + + runtime = (System.currentTimeMillis() - _gameStartTime) - runtime; + + // calculate sleep time... time needed to next tick minus time it takes to call moveObjects() + int sleepTime = 1 + MILLIS_IN_TICK - ((int) runtime) % MILLIS_IN_TICK; + + //_log.finest("TICK: "+_gameTicks); + + sleep(sleepTime); // hope other threads will have much more cpu time available now + // SelectorThread most of all + if (_stop) throw new Exception("stopTimer() was called"); } - } catch (Exception e) { + } + catch (Exception e) + { _error = e; } } } - + class TimerWatcher implements Runnable { public void run() @@ -205,38 +212,37 @@ if (!_timer.isAlive()) { String time = (new SimpleDateFormat("HH:mm:ss")).format(new Date()); - _log.warning(time+" TimerThread stop with following error. restart it."); - if (_timer._error != null) - _timer._error.printStackTrace(); - + _log.warning(time + " TimerThread stop with following error. restart it."); + if (_timer._error != null) _timer._error.printStackTrace(); + _timer = new TimerThread(); _timer.start(); } } } - + /** * Update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with EVT_ARRIVED.

    */ class MovingObjectArrived implements Runnable { final List ended; - - MovingObjectArrived(List ended) + + MovingObjectArrived(List ended) { this.ended = ended; } - - public void run() + + public void run() { - for (L2Character cha : ended) + for (L2Character cha : ended) { cha.getKnownList().updateKnownObjects(); cha.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); } } } - + /** * @param rise */ @@ -244,35 +250,34 @@ { public void run() { - int h = (getGameTime() / 60) % 24; // Time in hour - boolean tempIsNight = (h < Config.DAY_STATUS_SUN_RISE_AT || h >= Config.DAY_STATUS_SUN_SET_AT); - - if (tempIsNight != isNowNight()) // If diff day/night state - _isNight = tempIsNight; // Set current day/night varible to value of temp varible - else - return; // Do nothing if same state + int h = (getGameTime() / 60) % 24; // Time in hour + boolean tempIsNight = (h < Config.DAY_STATUS_SUN_RISE_AT || h >= Config.DAY_STATUS_SUN_SET_AT); - if (!Config.DAY_STATUS_FORCE_CLIENT_UPDATE) // Do not force client to update their day/night status - return; + if (tempIsNight != isNowNight()) // If diff day/night state + _isNight = tempIsNight; // Set current day/night varible to value of temp varible + else return; // Do nothing if same state - if (SevenSigns.getInstance().isSealValidationPeriod()) // Do nothing if in Seal validation period - return; - - // Force client day/night cycle to sync everyone's day/night state - ServerBasePacket packet; - if (isNowNight()) // If is now night - { - packet = new SunSet(); // Set client day/night state to night - if (Config.DEBUG) _log.fine("SunSet"); - } - else - { - packet = new SunRise(); // Set client day/night state to day - if (Config.DEBUG) _log.fine("SunRise"); - } - - for (L2PcInstance player : L2World.getInstance().getAllPlayers()) - player.sendPacket(packet); + if (!Config.DAY_STATUS_FORCE_CLIENT_UPDATE) // Do not force client to update their day/night status + return; + + if (SevenSigns.getInstance().isSealValidationPeriod()) // Do nothing if in Seal validation period + return; + + // Force client day/night cycle to sync everyone's day/night state + ServerBasePacket packet; + if (isNowNight()) // If is now night + { + packet = new SunSet(); // Set client day/night state to night + if (Config.DEBUG) _log.fine("SunSet"); + } + else + { + packet = new SunRise(); // Set client day/night state to day + if (Config.DEBUG) _log.fine("SunRise"); + } + + for (L2PcInstance player : L2World.getInstance().getAllPlayers()) + player.sendPacket(packet); } } }