All pastes #756490 Raw Edit

Unnamed

public text v1 · immutable
#756490 ·published 2007-10-31 15:13 UTC
rendered paste body
Index: net/sf/l2j/gameserver/GameTimeController.java
===================================================================
--- net/sf/l2j/gameserver/GameTimeController.java	(revision 1283)
+++ net/sf/l2j/gameserver/GameTimeController.java	(working copy)
@@ -20,7 +20,6 @@
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.List;
 import java.util.concurrent.ScheduledFuture;
 import java.util.logging.Logger;
 
@@ -28,6 +27,7 @@
 import net.sf.l2j.gameserver.ai.CtrlEvent;
 import net.sf.l2j.gameserver.instancemanager.DayNightSpawnManager;
 import net.sf.l2j.gameserver.model.L2Character;
+import java.util.concurrent.locks.*;
 
 /**
  * This class ...
@@ -47,11 +47,15 @@
 	protected static long _gameStartTime;
 	protected static boolean _isNight = false;
 
-	private static List<L2Character> _movingObjects = new FastList<L2Character>();
+	private static FastList<L2Character> _movingObjects = new FastList<L2Character>();
 
 	protected static TimerThread _timer;
+	protected static MoveObjectsThread _mover;
 	private ScheduledFuture _timerWatcher;
 
+	public final Lock lock = new ReentrantLock();
+	public final Condition tickCondition  = lock.newCondition(); 
+
 	/**
 	 * one ingame day is 240 real minutes
 	 */
@@ -68,6 +72,9 @@
 		_timer = new TimerThread();
 		_timer.start();
 
+		_mover = new MoveObjectsThread(_movingObjects);
+		_mover.start();
+		
 		_timerWatcher = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new TimerWatcher(), 0, 1000);
         ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new BroadcastSunState(), 0, 600000);
 
@@ -97,10 +104,12 @@
 	 * @param cha The L2Character to add to movingObjects of GameTimeController
 	 * 
 	 */
-	public synchronized void registerMovingObject(L2Character cha)
+	public void registerMovingObject(L2Character cha)
 	{
 		if(cha == null) return;
-		if (!_movingObjects.contains(cha)) _movingObjects.add(cha);
+		synchronized(_movingObjects) {
+			if (!_movingObjects.contains(cha)) _movingObjects.add(cha);
+		}
 	}
 
 	/**
@@ -115,45 +124,49 @@
 	 * <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()
-	{
-		// 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++)
+	   
+	class MoveObjectsThread extends Thread {
+		private final FastList<L2Character> chars;
+		private int oldticks;
+		public MoveObjectsThread(FastList<L2Character> _chars)
 		{
-
-			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>();
-
-				ended.add(cha);
+			chars = _chars;
+		}
+		public void run()
+		{
+			L2Character cha;
+			for (;;) {
+				
+				lock.lock();
+				try
+				{
+					while (oldticks == _gameTicks || chars.isEmpty()) 
+					{
+						if (oldticks != _gameTicks) oldticks = _gameTicks;
+						tickCondition.await();
+					}
+				} catch (InterruptedException e) { return; }
+				finally {lock.unlock();}
+					
+				for (FastList.Node<L2Character> e = chars.head(), end = chars.tail(); e!=end; e = e.getNext())
+				{
+					cha = e.getValue();
+					if (cha.updatePosition(_gameTicks))
+					{
+						synchronized (chars) { chars.remove(cha); }
+						ThreadPoolManager.getInstance().executeTask(new MovingObjectArrived(cha));
+					}
+				}
+				oldticks = _gameTicks;
 			}
 		}
-
-		// 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
-		// TODO: maybe a general TP is needed for that kinda stuff (all knownlist updates should be done in a TP anyway).
-		if (ended != null)
-			ThreadPoolManager.getInstance().executeTask(new MovingObjectArrived(ended));
-
 	}
-
+	
 	public void stopTimer()
 	{
 		_timerWatcher.cancel(true);
 		_timer.interrupt();
+		_mover.interrupt();
 	}
 
 	class TimerThread extends Thread
@@ -175,29 +188,26 @@
 			{				
 				for (;;)
 				{
+					lock.lock();
 					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)
+					if (_oldTicks != _gameTicks) tickCondition.signalAll();
 
 					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
+					lock.unlock();
+					sleep(sleepTime);
 				}
 			}
 			catch (Exception e)
 			{
+				lock.unlock();
 				_error = e;
 			}
 		}
@@ -224,20 +234,18 @@
 	 */
 	class MovingObjectArrived implements Runnable
 	{
-		private final List<L2Character> _ended;
+		private final L2Character _ended;
 
-		MovingObjectArrived(List<L2Character> ended)
+		MovingObjectArrived(L2Character ended)
 		{
 			_ended = ended;
 		}
 
 		public void run()
 		{
-			for (L2Character cha : _ended)
-			{
-				cha.getKnownList().updateKnownObjects();
-				cha.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED);
-			}
+			_ended.getKnownList().updateKnownObjects();
+			if (_ended.hasAI())
+				_ended.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED);
 		}
 	}