Rogue: Savage Rats, a retro-themed dungeon crawler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
rogue-savage-rats/src/mightypork/rogue/App.java

382 lines
6.6 KiB

package mightypork.rogue;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import javax.swing.JOptionPane;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.display.Screen;
import mightypork.rogue.display.ScreenSplash;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.rogue.tasks.TaskTakeScreenshot;
import mightypork.rogue.util.Utils;
import mightypork.utils.logging.Log;
import mightypork.utils.logging.LogInstance;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.subscription.MessageBus;
import mightypork.utils.time.TimerDelta;
import mightypork.utils.time.TimerInterpolating;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
public class App implements Destroyable {
/** instance pointer */
private static App inst;
private InputSystem input;
private SoundSystem sounds;
private DisplaySystem display;
private MessageBus events;
/** current screen */
private Screen screen;
/** Flag that screenshot is scheduled to be taken next loop */
private boolean scheduledScreenshot = false;
/**
* Get the instance
*
* @return instance of App
*/
public static App inst()
{
return inst;
}
/**
* @param args
*/
public static void main(String[] args)
{
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler());
inst = new App();
try {
inst.start();
} catch (Throwable t) {
onCrash(t);
}
}
/**
* Show crash report dialog with error stack trace.
*
* @param error
*/
public static void onCrash(Throwable error)
{
Log.e("The game has crashed.", error);
inst.exit();
}
/**
* Quit to OS<br>
* Destroy app & exit VM
*/
public void exit()
{
destroy();
System.exit(0);
}
/**
* Get current screen
*
* @return screen
*/
public Screen getCurrentScreen()
{
return screen;
}
public void initialize()
{
Log.i("Initializing subsystems");
initLock();
initBus();
initLogger();
initDisplay();
initSound();
initInput();
}
@Override
public void destroy()
{
if (sounds != null) sounds.destroy();
if (input != null) input.destroy();
if (display != null) display.destroy();
}
private void initLock()
{
if (!Config.SINGLE_INSTANCE) return;
if (!lockInstance()) {
System.out.println("Working directory is locked.\nOnly one instance can run at a time.");
//@formatter:off
JOptionPane.showMessageDialog(
null,
"The game is already running.",
"Instance error",
JOptionPane.ERROR_MESSAGE
);
//@formatter:on
exit();
return;
}
}
private boolean lockInstance()
{
final File lockFile = new File(Paths.WORKDIR, ".lock");
try {
final RandomAccessFile randomAccessFile = new RandomAccessFile(lockFile, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run()
{
try {
fileLock.release();
randomAccessFile.close();
lockFile.delete();
} catch (Exception e) {
System.err.println("Unable to remove lock file.");
e.printStackTrace();
}
}
});
return true;
}
} catch (Exception e) {
System.err.println("Unable to create and/or lock file.");
e.printStackTrace();
}
return false;
}
/**
* initialize inputs
*/
private void initBus()
{
events = new MessageBus();
events.addSubscriber(this);
}
/**
* initialize sound system
*/
private void initSound()
{
sounds = new SoundSystem();
sounds.setMasterVolume(1);
}
/**
* initialize inputs
*/
private void initInput()
{
input = new InputSystem();
input.bindKeyStroke(new KeyStroke(Keyboard.KEY_F2), new Runnable() {
@Override
public void run()
{
Log.f3("F2, taking screenshot.");
scheduledScreenshot = true;
}
});
input.bindKeyStroke(new KeyStroke(false, Keyboard.KEY_F11), new Runnable() {
@Override
public void run()
{
Log.f3("F11, toggling fullscreen.");
display.switchFullscreen();
}
});
input.bindKeyStroke(new KeyStroke(Keyboard.KEY_LCONTROL, Keyboard.KEY_Q), new Runnable() {
@Override
public void run()
{
Log.f3("CTRL+Q, shutting down.");
exit();
}
});
}
/**
* initialize display
*/
private void initDisplay()
{
display = new DisplaySystem();
display.createMainWindow(Const.WINDOW_W, Const.WINDOW_H, true, Config.START_IN_FS, Const.TITLEBAR);
display.setTargetFps(Const.FPS_RENDER);
}
/**
* initialize main logger
*/
private void initLogger()
{
LogInstance li = Log.create("runtime", Paths.LOGS, 10);
li.enable(Config.LOGGING_ENABLED);
li.enableSysout(Config.LOG_TO_STDOUT);
}
private void start()
{
initialize();
mainLoop();
exit();
}
/** timer */
private TimerDelta timerRender;
private TimerInterpolating timerGui;
private void mainLoop()
{
screen = new ScreenSplash();
screen.setActive(true);
timerRender = new TimerDelta();
timerGui = new TimerInterpolating(Const.FPS_GUI_UPDATE);
while (!display.isCloseRequested()) {
display.beginFrame();
// gui update
timerGui.sync();
int ticks = timerGui.getSkipped();
if (ticks >= 1) {
input.poll();
timerGui.startNewFrame();
}
double delta = timerRender.getDelta();
sounds.update(delta);
// Screen
screen.update(delta);
if (scheduledScreenshot) {
takeScreenshot();
scheduledScreenshot = false;
}
display.endFrame();
}
}
/**
* Do take a screenshot
*/
public void takeScreenshot()
{
sounds.getEffect("gui.shutter").play(1);
Utils.runAsThread(new TaskTakeScreenshot());
}
//
// static accessors
//
/**
* @return sound system of the running instance
*/
public static SoundSystem soundsys()
{
return inst.sounds;
}
/**
* @return input system of the running instance
*/
public static InputSystem input()
{
return inst.input;
}
/**
* @return display system of the running instance
*/
public static DisplaySystem disp()
{
return inst.display;
}
/**
* @return event bus of the running instance
*/
public static MessageBus msgbus()
{
return inst.events;
}
/**
* @return screen of the running instance
*/
public static Screen screen()
{
return inst.getCurrentScreen();
}
public static boolean broadcast(Object message)
{
boolean was = msgbus().broadcast(message);
if (!was) Log.w("Message not accepted by any channel: " + message);
return was;
}
}