/* * (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved. * Licencia en license/bsd.txt / License in license/bsd.txt */ package eu.irreality.age; import javax.swing.*; import eu.irreality.age.debug.Debug; import eu.irreality.age.debug.ExceptionPrinter; import eu.irreality.age.i18n.UIMessages; import eu.irreality.age.messages.Messages; import eu.irreality.age.observer.GameThreadObserver; import eu.irreality.age.scripting.ScriptException; import eu.irreality.age.swing.applet.SwingSDIApplet; import eu.irreality.age.swing.sdi.SwingSDIInterface; import eu.irreality.age.windowing.AGEClientWindow; import eu.irreality.age.windowing.AGELoggingWindow; import eu.irreality.age.windowing.MenuMnemonicOnTheFly; import java.awt.event.*; import java.util.List; import java.util.Vector; public class GameEngineThread extends Thread { public static String getVersion() { return "Aetheria Game Engine v " + getVersionNumber(); } public static String getVersionNumber() { return UIMessages.getInstance().getMessage("age.version"); } public static long DEFAULT_REAL_TIME_QUANTUM = 1500; //LA M�QUINA DE ESTADOS /** * El contador de tiempo. */ protected long timeCount; /** * Si salimos del juego. */ protected boolean exitFlag; World theWorld; /*�Tiempo real?*/ boolean realTimeEnabled; long realTimeQuantum = DEFAULT_REAL_TIME_QUANTUM; public GameEngineThread ( World theWorld , boolean realTimeEnabled ) { setName(getName()+": AGE Game Engine Thread"); this.theWorld = theWorld; this.realTimeEnabled = realTimeEnabled; //now done from the outside by attaching a ServerMenuHandler observer: //if ( ventana != null ) //{ // initServerMenu(ventana); // ventana.repaint(); //} } public void setRealTimeQuantum ( long quantum ) { realTimeQuantum = quantum; } public long getRealTimeQuantum ( ) { return realTimeQuantum; } public boolean isRealTimeEnabled ( ) { return realTimeEnabled; } public void setRealTimeEnabled ( boolean b ) { realTimeEnabled = b; } public void run ( ) { int timeCount=0; exitFlag = false; //exec general server intro try { //System.err.println("Execcan serverintro for world " + theWorld); theWorld.execCode("serverintro",""); //EVA //System.err.println("Just singing in the rain..."); theWorld.execCode("serverintro",new Object[0]); //bsh //System.err.println("BSH script code should have been exec'd just before THIS LINE"); } catch (EVASemanticException esm) //EVA { theWorld.write("EVASemanticException found at serverintro routine" ); } catch (ScriptException bshte) { theWorld.write("bsh.TargetError found at serverintro routine" ); theWorld.write ( bshte.printTargetError(bshte) + bshte.inNativeCode() ); Debug.println ( bshte.printTargetError(bshte.getTarget()) ); theWorld.write ( bshte.printTargetError(bshte.getTarget()) ); //bshte.printStackTrace(); //System.err.println("BINGO!!1"); } catch ( Exception e ) { //theWorld.write("The followan has been thrown: " + e); theWorld.writeError("Exception thrown by serverIntro routine:"); theWorld.writeError(ExceptionPrinter.getExceptionReport(e)); } finally { Debug.println("Gonna notify."); synchronized(theWorld.serverIntroSyncObject) { theWorld.serverIntroExeccedFlag=true; theWorld.serverIntroSyncObject.notifyAll(); } Debug.println("Notified."); } //exec player intro foreach player //try //{ Debug.println("Gonna exec player intros."); java.util.List l = theWorld.getPlayerList(); Debug.println("List gotten: " + l); if ( l != null ) { for ( int i = 0 ; i < l.size() ; i++ ) { Debug.println("Intro " + i); Player p = (Player)l.get(i); /* theWorld.execCode("intro",""); //EVA (obsolete) theWorld.execCode("intro", new Object[] {p}); */ theWorld.executePlayerIntro(p); } } Debug.println("Player intros execced."); //} /* catch (EVASemanticException esm) //EVA { theWorld.write("EVASemanticException found at intro routine" ); } catch (bsh.TargetError bshte) { theWorld.write("bsh.TargetError found at intro routine" ); bshte.printStackTrace(); } */ while ( !exitFlag ) { timeCount++; Debug.println("A world cycle."); try { //System.err.println("Going to update."); theWorld.update(); } catch ( Exception e ) { //the world creator messed something up, probably! if ( theWorld != null ) theWorld.writeError(""+e); System.err.println("Exception during world update:"); e.printStackTrace(); theWorld.writeError(ExceptionPrinter.getExceptionReport(e)); } if ( exitFlag ) { //System.err.println("breakin'"); break; } if ( realTimeEnabled && !theWorld.isLoadingLog() ) { esperarCuanto(); } if ( exitFlag ) break; //delete this? if ( theWorld.getNumberOfConnectedPlayers() <= 0 ) { try { sleep(2000); } catch ( InterruptedException ie ) { ; } } Debug.println("Flag = " + exitFlag); } //exitNow(); } public synchronized void esperarCuanto() { try { wait ( realTimeQuantum ); } catch ( InterruptedException intex ) { System.err.println(intex); } } public void exitNow ( ) { Debug.println("Gonna x-it."); //now this is done when detaching the observers /* if ( ventana instanceof SwingAetheriaGameLoader ) { ((SwingAetheriaGameLoader)ventana).unlinkWorld(); //we are client and server so we can do this ((SwingAetheriaGameLoader)ventana).saveAndFreeResources(); } if ( ventana instanceof SwingSDIInterface ) { ((SwingSDIInterface)ventana).unlinkWorld(); //we are client and server so we can do this ((SwingSDIInterface)ventana).saveAndFreeResources(); } if ( ventana instanceof SwingSDIApplet ) { ((SwingSDIApplet)ventana).unlinkWorld(); //we are client and server so we can do this ((SwingSDIApplet)ventana).saveAndFreeResources(); } */ detachAllObservers(); exitFlag = true; //if there are more deadlock problems with this, we could always create a "world end thread" with the following code (including join and all), and run it here, //rather than keep running in the event dispatching thread: //this thread waits for the game engine thread to end, and then clears things like the message cache //which cannot be cleared before the game engine thread ends (since the game engine thread would replace //the Messages instance in the cache). Thread worldEndThread = new Thread("World End Thread") { public void run() { try { //wait for the world to end GameEngineThread.this.join(); } catch (InterruptedException e) { e.printStackTrace(); } Messages.clearCache(theWorld); theWorld = null; //serverConfigurationMenu = null; //the equivalent to this now done by detachAllObservers() above. Debug.println("World ended."); } }; worldEndThread.start(); //wait for the game engine thread to end, then clean up /* try { //wait for the world to end this.join(); } catch (InterruptedException e) { e.printStackTrace(); } //System.err.println("BEFORE"); //Messages.printReport(); Messages.clearCache(theWorld); //System.err.println("Cache cleared for world " + theWorld + ".\n"); //System.err.println("AFTER"); //Messages.printReport(); theWorld = null; ventana = null; serverConfigurationMenu = null; Debug.println("Flag set."); */ } public void exitForReinit() { Debug.println("Gonna x-it."); exitFlag = true; Debug.println("Flag set."); } private List observers = new Vector(); public void attachObserver ( GameThreadObserver obs ) { observers.add(obs); obs.onAttach(this); } public boolean hasObserver ( GameThreadObserver obs ) { return observers.contains(this); } public void detachObserver ( GameThreadObserver obs ) { observers.remove(obs); obs.onDetach(this); } public void detachAllObservers() { while ( !observers.isEmpty() ) { detachObserver((GameThreadObserver)observers.get(0)); } } }