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<L2Character> movingObjects = new FastList<L2Character>();
-
- protected static TimerThread _timer;
+ private static List<L2Character> movingObjects = new FastList<L2Character>();
+
+ 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.<BR><BR>
*
@@ -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.<BR><BR>
*
@@ -120,54 +117,53 @@
* <li>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 </li><BR><BR>
*
*/
- 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<L2Character> 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<L2Character>();
-
+ if (ended == null) ended = new FastList<L2Character>();
+
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.<BR><BR>
*/
class MovingObjectArrived implements Runnable
{
final List<L2Character> ended;
-
- MovingObjectArrived(List<L2Character> ended)
+
+ MovingObjectArrived(List<L2Character> 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);
}
}
}