Factored out BaseApp.
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
package mightypork.gamecore;
|
||||
|
||||
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
|
||||
import org.newdawn.slick.util.LogSystem;
|
||||
|
||||
|
||||
public class SlickLogRedirector implements LogSystem {
|
||||
|
||||
LogInstance l;
|
||||
|
||||
|
||||
public SlickLogRedirector(LogInstance log) {
|
||||
this.l = log;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(Throwable e)
|
||||
{
|
||||
l.e(e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String msg)
|
||||
{
|
||||
l.e(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg)
|
||||
{
|
||||
l.w(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void info(String msg)
|
||||
{
|
||||
l.i(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void debug(String msg)
|
||||
{
|
||||
l.f3(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -21,23 +21,27 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest.
|
||||
|
||||
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();
|
||||
private TimerDelta timer;
|
||||
private final Renderable mainRenderable;
|
||||
private Renderable rootRenderable;
|
||||
private boolean running = true;
|
||||
|
||||
|
||||
/**
|
||||
* @param app {@link AppAccess} instance
|
||||
*/
|
||||
public GameLoop(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set primary renderable
|
||||
*
|
||||
* @param rootRenderable main {@link Renderable}, typically a
|
||||
* {@link ScreenRegistry}
|
||||
*/
|
||||
public GameLoop(AppAccess app, Renderable rootRenderable) {
|
||||
super(app);
|
||||
|
||||
if (rootRenderable == null) {
|
||||
throw new NullPointerException("Master renderable must not be null.");
|
||||
}
|
||||
|
||||
mainRenderable = rootRenderable;
|
||||
public void setRootRenderable(Renderable rootRenderable)
|
||||
{
|
||||
this.rootRenderable = rootRenderable;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +61,7 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest.
|
||||
|
||||
beforeRender();
|
||||
|
||||
mainRenderable.render();
|
||||
if (rootRenderable != null) rootRenderable.render();
|
||||
|
||||
afterRender();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user