parent
e4e7aa7eb3
commit
e03d547fab
@ -0,0 +1,276 @@ |
||||
package mightypork.gamecore.control; |
||||
|
||||
|
||||
import java.io.File; |
||||
|
||||
import javax.swing.JOptionPane; |
||||
|
||||
import mightypork.gamecore.audio.SoundSystem; |
||||
import mightypork.gamecore.control.bus.EventBus; |
||||
import mightypork.gamecore.control.bus.events.*; |
||||
import mightypork.gamecore.control.interf.Destroyable; |
||||
import mightypork.gamecore.control.interf.NoImpl; |
||||
import mightypork.gamecore.control.interf.Updateable; |
||||
import mightypork.gamecore.gui.screens.ScreenRegistry; |
||||
import mightypork.gamecore.input.InputSystem; |
||||
import mightypork.gamecore.loading.AsyncResourceLoader; |
||||
import mightypork.gamecore.render.DisplaySystem; |
||||
import mightypork.rogue.util.SlickLogRedirector; |
||||
import mightypork.utils.files.InstanceLock; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.logging.LogInstance; |
||||
|
||||
|
||||
/** |
||||
* Basic screen-based game with subsystems.<br> |
||||
* This class takes care of the initialization sequence. |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public abstract class BaseApp implements AppAccess { |
||||
|
||||
// modules
|
||||
private InputSystem inputSystem; |
||||
private DisplaySystem displaySystem; |
||||
private SoundSystem soundSystem; |
||||
private EventBus eventBus; |
||||
private GameLoop gameLoop; |
||||
private ScreenRegistry screenRegistry; |
||||
|
||||
|
||||
/** |
||||
* Start the application |
||||
*/ |
||||
public void start() |
||||
{ |
||||
Log.i("Commencing initialization sequence..."); |
||||
|
||||
initialize(); |
||||
|
||||
Log.i("Starting main loop..."); |
||||
|
||||
// open first screen
|
||||
gameLoop.start(); |
||||
} |
||||
|
||||
|
||||
protected void initialize() |
||||
{ |
||||
preInit(); |
||||
|
||||
/* |
||||
* Lock working directory |
||||
*/ |
||||
initLock(); |
||||
|
||||
/* |
||||
* Setup logging |
||||
*/ |
||||
final LogInstance log = createLog(); |
||||
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log)); |
||||
|
||||
// only here it makes sense to log.
|
||||
Log.f1("Initializing subsystems..."); |
||||
|
||||
/* |
||||
* Event bus |
||||
*/ |
||||
Log.f2("Starting Event Bus..."); |
||||
eventBus = new EventBus(); |
||||
|
||||
Log.f3("Registering channels..."); |
||||
initChannels(eventBus); |
||||
|
||||
/* |
||||
* Display |
||||
*/ |
||||
Log.f2("Initializing Display System..."); |
||||
displaySystem = new DisplaySystem(this); |
||||
initDisplay(displaySystem); |
||||
|
||||
/* |
||||
* Audio |
||||
*/ |
||||
Log.f2("Initializing Sound System..."); |
||||
soundSystem = new SoundSystem(this); |
||||
initSoundSystem(soundSystem); |
||||
|
||||
/* |
||||
* Input |
||||
*/ |
||||
Log.f2("Initializing Input System..."); |
||||
inputSystem = new InputSystem(this); |
||||
initKeystrokes(inputSystem); |
||||
|
||||
/* |
||||
* Prepare main loop |
||||
*/ |
||||
Log.f1("Creating Screen Registry and Game Loop..."); |
||||
screenRegistry = new ScreenRegistry(this); |
||||
gameLoop = createLoop(); |
||||
gameLoop.setRootRenderable(screenRegistry); |
||||
|
||||
/* |
||||
* Load resources |
||||
* |
||||
* Resources should be registered to banks, and AsyncResourceLoader will load them. |
||||
*/ |
||||
Log.f1("Loading resources..."); |
||||
AsyncResourceLoader.launch(this); |
||||
initResources(); |
||||
|
||||
/* |
||||
* Screen registry |
||||
* |
||||
* Must be after resources, because screens can request them during instantiation. |
||||
*/ |
||||
Log.f2("Registering screens..."); |
||||
initScreens(screenRegistry); |
||||
|
||||
postInit(); |
||||
Log.i("Initialized sequence completed."); |
||||
} |
||||
|
||||
|
||||
@NoImpl |
||||
protected void preInit() |
||||
{ |
||||
} |
||||
|
||||
|
||||
@NoImpl |
||||
protected void postInit() |
||||
{ |
||||
} |
||||
|
||||
|
||||
protected abstract LogInstance createLog(); |
||||
|
||||
|
||||
protected abstract void initDisplay(DisplaySystem display); |
||||
|
||||
|
||||
protected abstract void initSoundSystem(SoundSystem audio); |
||||
|
||||
|
||||
protected abstract void initKeystrokes(InputSystem input); |
||||
|
||||
|
||||
protected abstract void initResources(); |
||||
|
||||
|
||||
protected abstract void initScreens(ScreenRegistry screens); |
||||
|
||||
|
||||
protected abstract GameLoop createLoop(); |
||||
|
||||
|
||||
protected void initChannels(EventBus bus) |
||||
{ |
||||
// framework events
|
||||
bus.addChannel(DestroyEvent.class, Destroyable.class); |
||||
bus.addChannel(UpdateEvent.class, Updateable.class); |
||||
|
||||
// input events
|
||||
bus.addChannel(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class); |
||||
bus.addChannel(KeyEvent.class, KeyEvent.Listener.class); |
||||
bus.addChannel(MouseMotionEvent.class, MouseMotionEvent.Listener.class); |
||||
bus.addChannel(MouseButtonEvent.class, MouseButtonEvent.Listener.class); |
||||
|
||||
// control events
|
||||
bus.addChannel(ScreenRequestEvent.class, ScreenRequestEvent.Listener.class); |
||||
bus.addChannel(ResourceLoadRequest.class, ResourceLoadRequest.Listener.class); |
||||
bus.addChannel(MainLoopTaskRequest.class, MainLoopTaskRequest.Listener.class); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Try to obtain lock. |
||||
*/ |
||||
private void initLock() |
||||
{ |
||||
final File lockFile = getLockFile(); |
||||
|
||||
if (lockFile == null) { |
||||
// lock off
|
||||
return; |
||||
} |
||||
|
||||
if (!InstanceLock.onFile(lockFile)) { |
||||
onLockError(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Triggered when lock cannot be obtained.<br> |
||||
* App should terminate gracefully. |
||||
*/ |
||||
protected void onLockError() |
||||
{ |
||||
System.err.println("Could not obtain lock file.\nOnly one instance can run at a time."); |
||||
|
||||
//@formatter:off
|
||||
JOptionPane.showMessageDialog( |
||||
null, |
||||
"Another instance is already running.", |
||||
"Lock Error", |
||||
JOptionPane.ERROR_MESSAGE |
||||
); |
||||
//@formatter:on
|
||||
|
||||
shutdown(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get lock file path; Used to enforce single-instance policy. |
||||
* |
||||
* @return lock file, or null to disable lock. |
||||
*/ |
||||
protected abstract File getLockFile(); |
||||
|
||||
|
||||
@Override |
||||
public final SoundSystem getSoundSystem() |
||||
{ |
||||
return soundSystem; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public final InputSystem getInput() |
||||
{ |
||||
return inputSystem; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public final DisplaySystem getDisplay() |
||||
{ |
||||
return displaySystem; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public final EventBus getEventBus() |
||||
{ |
||||
return eventBus; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void shutdown() |
||||
{ |
||||
Log.i("Shutting down subsystems..."); |
||||
|
||||
if (getEventBus() != null) { |
||||
getEventBus().send(new DestroyEvent()); |
||||
getEventBus().destroy(); |
||||
} |
||||
|
||||
Log.i("Terminating..."); |
||||
System.exit(0); |
||||
} |
||||
} |
@ -1,4 +1,4 @@ |
||||
package mightypork.gamecore; |
||||
package mightypork.rogue.util; |
||||
|
||||
|
||||
import mightypork.utils.logging.LogInstance; |
Loading…
Reference in new issue