removing now unused classes

This commit is contained in:
yugecin 2017-01-21 01:17:47 +01:00
parent f730935622
commit 95a466f92f
4 changed files with 0 additions and 1642 deletions

View File

@ -1,184 +0,0 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014, 2015 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapGroup;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSortOrder;
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.render.CurveRenderState;
import itdelatrisu.opsu.ui.UI;
import org.lwjgl.opengl.Display;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.Game;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.opengl.InternalTextureLoader;
/**
* AppGameContainer extension that sends critical errors to ErrorHandler.
*/
public class Container extends AppGameContainer {
/** Exception causing game failure. */
protected Exception e = null;
public static Container instance;
/**
* Create a new container wrapping a game
*
* @param game The game to be wrapped
* @throws SlickException Indicates a failure to initialise the display
*/
public Container(Game game) throws SlickException {
super(game);
instance = this;
}
/**
* Create a new container wrapping a game
*
* @param game The game to be wrapped
* @param width The width of the display required
* @param height The height of the display required
* @param fullscreen True if we want fullscreen mode
* @throws SlickException Indicates a failure to initialise the display
*/
public Container(Game game, int width, int height, boolean fullscreen) throws SlickException {
super(game, width, height, fullscreen);
}
@Override
public void start() throws SlickException {
try {
setup();
ErrorHandler.setGlString();
getDelta();
while (running())
gameLoop();
} catch (Exception e) {
this.e = e;
}
// destroy the game container
try {
close_sub();
} catch (Exception e) {
if (this.e == null) // suppress if caused by a previous exception
this.e = e;
}
destroy();
// report any critical errors
if (e != null) {
ErrorHandler.error(null, e, true);
e = null;
forceExit = true;
}
if (forceExit) {
Opsu.close();
System.exit(0);
}
}
@Override
protected void gameLoop() throws SlickException {
int delta = getDelta();
if (!Display.isVisible() && updateOnlyOnVisible) {
try { Thread.sleep(100); } catch (Exception e) {}
} else {
try {
updateAndRender(delta);
} catch (SlickException e) {
this.e = e; // store exception to display later
running = false;
return;
}
}
updateFPS();
Display.update();
if (Display.isCloseRequested()) {
if (game.closeRequested())
running = false;
}
}
/**
* Actions to perform before destroying the game container.
*/
private void close_sub() {
// save user options
Options.saveOptions();
// reset cursor
UI.getCursor().reset();
// destroy images
InternalTextureLoader.get().clear();
// reset image references
GameImage.clearReferences();
GameData.Grade.clearReferences();
Beatmap.clearBackgroundImageCache();
// prevent loading tracks from re-initializing OpenAL
MusicController.reset();
// stop any playing track
SoundController.stopTrack();
// reset BeatmapSetList data
BeatmapGroup.set(BeatmapGroup.ALL);
BeatmapSortOrder.set(BeatmapSortOrder.TITLE);
if (BeatmapSetList.get() != null)
BeatmapSetList.get().reset();
// delete OpenGL objects involved in the Curve rendering
CurveRenderState.shutdown();
// destroy watch service
if (!Options.isWatchServiceEnabled())
BeatmapWatchService.destroy();
BeatmapWatchService.removeListeners();
// delete temporary directory
Utils.deleteDirectory(Options.TEMP_DIR);
}
@Override
public void exit() {
// show confirmation dialog if any downloads are active
if (forceExit) {
if (DownloadList.get().hasActiveDownloads() &&
UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION))
return;
if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING &&
UI.showExitConfirmation(Updater.EXIT_CONFIRMATION))
return;
}
super.exit();
}
}

View File

@ -1,242 +0,0 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014, 2015 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu;
import java.awt.Cursor;
import java.awt.Desktop;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Properties;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
/**
* Error handler to log and display errors.
*/
public class ErrorHandler {
/** Error popup title. */
private static final String title = "Error";
/** Error popup description text. */
private static final String
desc = "opsu! has encountered an error.",
descReport = "opsu! has encountered an error. Please report this!";
/** Error popup button options. */
private static final String[]
optionsLog = {"View Error Log", "Close"},
optionsReport = {"Send Report", "Close"},
optionsLogReport = {"Send Report", "View Error Log", "Close"};
/** Text area for Exception. */
private static final JTextArea textArea = new JTextArea(15, 100);
static {
textArea.setEditable(false);
textArea.setBackground(UIManager.getColor("Panel.background"));
textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
textArea.setTabSize(2);
textArea.setLineWrap(false);
textArea.setWrapStyleWord(true);
}
/** Scroll pane holding JTextArea. */
private static final JScrollPane scroll = new JScrollPane(textArea);
/** Error popup objects. */
private static final Object[]
message = { desc, scroll },
messageReport = { descReport, scroll };
/** OpenGL string (if any). */
private static String glString = null;
// This class should not be instantiated.
private ErrorHandler() {}
/**
* Sets the OpenGL version string.
*/
public static void setGlString() {
try {
String glVersion = GL11.glGetString(GL11.GL_VERSION);
String glVendor = GL11.glGetString(GL11.GL_VENDOR);
glString = String.format("%s (%s)", glVersion, glVendor);
} catch (Exception e) {}
}
/**
* Displays an error popup and logs the given error.
* @param error a description of the error
* @param e the exception causing the error
* @param report whether to ask to report the error
*/
public static void error(String error, Throwable e, boolean report) {
if (error == null && e == null)
return;
// log the error
if (error == null)
Log.error(e);
else if (e == null)
Log.error(error);
else
Log.error(error, e);
// set the textArea to the error message
textArea.setText(null);
if (error != null) {
textArea.append(error);
textArea.append("\n");
}
String trace = null;
if (e != null) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
trace = sw.toString();
textArea.append(trace);
}
// display popup
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Desktop desktop = null;
boolean isBrowseSupported = false, isOpenSupported = false;
if (Desktop.isDesktopSupported()) {
desktop = Desktop.getDesktop();
isBrowseSupported = desktop.isSupported(Desktop.Action.BROWSE);
isOpenSupported = desktop.isSupported(Desktop.Action.OPEN);
}
if (desktop != null && (isOpenSupported || (report && isBrowseSupported))) { // try to open the log file and/or issues webpage
if (report && isBrowseSupported) { // ask to report the error
if (isOpenSupported) { // also ask to open the log
int n = JOptionPane.showOptionDialog(null, messageReport, title,
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
null, optionsLogReport, optionsLogReport[2]);
if (n == 0)
desktop.browse(getIssueURI(error, e, trace));
else if (n == 1)
desktop.open(Options.LOG_FILE);
} else { // only ask to report the error
int n = JOptionPane.showOptionDialog(null, message, title,
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
null, optionsReport, optionsReport[1]);
if (n == 0)
desktop.browse(getIssueURI(error, e, trace));
}
} else { // don't report the error
int n = JOptionPane.showOptionDialog(null, message, title,
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
null, optionsLog, optionsLog[1]);
if (n == 0)
desktop.open(Options.LOG_FILE);
}
} else { // display error only
JOptionPane.showMessageDialog(null, report ? messageReport : message,
title, JOptionPane.ERROR_MESSAGE);
}
} catch (Exception e1) {
Log.error("An error occurred in the crash popup.", e1);
}
}
/**
* Returns the issue reporting URI.
* This will auto-fill the report with the relevant information if possible.
* @param error a description of the error
* @param e the exception causing the error
* @param trace the stack trace
* @return the created URI
*/
private static URI getIssueURI(String error, Throwable e, String trace) {
// generate report information
String issueTitle = (error != null) ? error : e.getMessage();
StringBuilder sb = new StringBuilder();
try {
// read version and build date from version file, if possible
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
String version = props.getProperty("version");
if (version != null && !version.equals("${pom.version}")) {
sb.append("**Version:** ");
sb.append(version);
String hash = Utils.getGitHash();
if (hash != null) {
sb.append(" (");
sb.append(hash.substring(0, 12));
sb.append(')');
}
sb.append('\n');
}
String timestamp = props.getProperty("build.date");
if (timestamp != null &&
!timestamp.equals("${maven.build.timestamp}") && !timestamp.equals("${timestamp}")) {
sb.append("**Build date:** ");
sb.append(timestamp);
sb.append('\n');
}
} catch (IOException e1) {
Log.warn("Could not read version file.", e1);
}
sb.append("**OS:** ");
sb.append(System.getProperty("os.name"));
sb.append(" (");
sb.append(System.getProperty("os.arch"));
sb.append(")\n");
sb.append("**JRE:** ");
sb.append(System.getProperty("java.version"));
sb.append('\n');
if (glString != null) {
sb.append("**OpenGL Version:** ");
sb.append(glString);
sb.append('\n');
}
if (error != null) {
sb.append("**Error:** `");
sb.append(error);
sb.append("`\n");
}
if (trace != null) {
sb.append("**Stack trace:**");
sb.append("\n```\n");
sb.append(trace);
sb.append("```");
}
// return auto-filled URI
try {
return URI.create(String.format(Options.ISSUES_URL,
URLEncoder.encode(issueTitle, "UTF-8"),
URLEncoder.encode(sb.toString(), "UTF-8")));
} catch (UnsupportedEncodingException e1) {
Log.warn("URLEncoder failed to encode the auto-filled issue report URL.");
return URI.create(String.format(Options.ISSUES_URL, "", ""));
}
}
}

View File

@ -1,309 +0,0 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014, 2015 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.DBController;
import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.states.ButtonMenu;
import itdelatrisu.opsu.states.DownloadsMenu;
import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.states.GamePauseMenu;
import itdelatrisu.opsu.states.GameRanking;
import itdelatrisu.opsu.states.MainMenu;
import itdelatrisu.opsu.states.OptionsMenu;
import itdelatrisu.opsu.states.SongMenu;
import itdelatrisu.opsu.states.Splash;
import itdelatrisu.opsu.ui.UI;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.state.transition.FadeInTransition;
import org.newdawn.slick.state.transition.EasedFadeOutTransition;
import org.newdawn.slick.util.DefaultLogSystem;
import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
/**
* Main class.
* <p>
* Creates game container, adds all other states, and initializes song data.
*/
public class Opsu extends StateBasedGame {
/** Game states. */
public static final int
STATE_SPLASH = 0,
STATE_MAINMENU = 1,
STATE_BUTTONMENU = 2,
STATE_SONGMENU = 3,
STATE_GAME = 4,
STATE_GAMEPAUSEMENU = 5,
STATE_GAMERANKING = 6,
STATE_OPTIONSMENU = 7,
STATE_DOWNLOADSMENU = 8;
/** Server socket for restricting the program to a single instance. */
private static ServerSocket SERVER_SOCKET;
/**
* Constructor.
* @param name the program name
*/
public Opsu(String name) {
super(name);
}
@Override
public void initStatesList(GameContainer container) throws SlickException {
//addState(new Splash(STATE_SPLASH));
//addState(new MainMenu(STATE_MAINMENU));
//addState(new ButtonMenu(STATE_BUTTONMENU));
//addState(new SongMenu(STATE_SONGMENU));
//addState(new Game(STATE_GAME));
//addState(new GamePauseMenu(STATE_GAMEPAUSEMENU));
//addState(new GameRanking(STATE_GAMERANKING));
//addState(new OptionsMenu(STATE_OPTIONSMENU));
//addState(new DownloadsMenu(STATE_DOWNLOADSMENU));
}
/**
* Launches opsu!.
*/
public static void main(String[] args) {
// log all errors to a file
Log.setVerbose(false);
try {
DefaultLogSystem.out = new PrintStream(new FileOutputStream(Options.LOG_FILE, true));
} catch (FileNotFoundException e) {
Log.error(e);
}
// set default exception handler
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
ErrorHandler.error("** Uncaught Exception! **", e, true);
System.exit(1);
}
});
// parse configuration file
Options.parseOptions();
// only allow a single instance
if (!Options.noSingleInstance()) {
try {
SERVER_SOCKET = new ServerSocket(Options.getPort(), 1, InetAddress.getLocalHost());
} catch (UnknownHostException e) {
// shouldn't happen
} catch (IOException e) {
errorAndExit(
null,
String.format(
"opsu! could not be launched for one of these reasons:\n" +
"- An instance of opsu! is already running.\n" +
"- Another program is bound to port %d. " +
"You can change the port opsu! uses by editing the \"Port\" field in the configuration file.",
Options.getPort()
),
false
);
}
}
// load natives
File nativeDir;
if (!Utils.isJarRunning() && (
(nativeDir = new File("./target/natives/")).isDirectory() ||
(nativeDir = new File("./build/natives/")).isDirectory()))
;
else {
nativeDir = Options.NATIVE_DIR;
try {
new NativeLoader(nativeDir).loadNatives();
} catch (IOException e) {
Log.error("Error loading natives.", e);
}
}
System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
System.setProperty("java.library.path", nativeDir.getAbsolutePath());
try {
// Workaround for "java.library.path" property being read-only.
// http://stackoverflow.com/a/24988095
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
Log.warn("Failed to set 'sys_paths' field.", e);
}
// set the resource paths
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
// initialize databases
try {
DBController.init();
} catch (UnsatisfiedLinkError e) {
errorAndExit(e, "The databases could not be initialized.", true);
}
// check if just updated
if (args.length >= 2)
Updater.get().setUpdateInfo(args[0], args[1]);
// check for updates
if (!Options.isUpdaterDisabled()) {
new Thread() {
@Override
public void run() {
try {
Updater.get().checkForUpdates();
} catch (IOException e) {
Log.warn("Check for updates failed.", e);
}
}
}.start();
}
// disable jinput
Input.disableControllers();
// start the game
try {
// loop until force exit
while (true) {
Opsu opsu = new Opsu("opsu!");
Container app = new Container(opsu);
// basic game settings
//Options.setDisplayMode(app);
String[] icons = { "icon16.png", "icon32.png" };
try {
app.setIcons(icons);
} catch (Exception e) {
Log.error("could not set icon");
}
app.setForceExit(true);
app.start();
// run update if available
if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) {
close();
Updater.get().runUpdate();
break;
}
}
} catch (SlickException e) {
errorAndExit(e, "An error occurred while creating the game container.", true);
}
}
@Override
public boolean closeRequested() {
int id = this.getCurrentStateID();
// intercept close requests in game-related states and return to song menu
if (id == STATE_GAME || id == STATE_GAMEPAUSEMENU || id == STATE_GAMERANKING) {
// start playing track at preview position
SongMenu songMenu = (SongMenu) this.getState(Opsu.STATE_SONGMENU);
if (id == STATE_GAMERANKING) {
GameData data = ((GameRanking) this.getState(Opsu.STATE_GAMERANKING)).getGameData();
if (data != null && data.isGameplay())
songMenu.resetTrackOnLoad();
} else {
if (id == STATE_GAME) {
MusicController.pause();
MusicController.setPitch(1.0f);
MusicController.resume();
} else
songMenu.resetTrackOnLoad();
}
// reset game data
if (UI.getCursor().isBeatmapSkinned())
UI.getCursor().reset();
songMenu.resetGameDataOnLoad();
this.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition());
return false;
}
// show confirmation dialog if any downloads are active
if (DownloadList.get().hasActiveDownloads() &&
UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION))
return false;
if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING &&
UI.showExitConfirmation(Updater.EXIT_CONFIRMATION))
return false;
return true;
}
/**
* Closes all resources.
*/
public static void close() {
// close databases
DBController.closeConnections();
// cancel all downloads
DownloadList.get().cancelAllDownloads();
// close server socket
if (SERVER_SOCKET != null) {
try {
SERVER_SOCKET.close();
} catch (IOException e) {
ErrorHandler.error("Failed to close server socket.", e, false);
}
}
}
/**
* Throws an error and exits the application with the given message.
* @param e the exception that caused the crash
* @param message the message to display
* @param report whether to ask to report the error
*/
private static void errorAndExit(Throwable e, String message, boolean report) {
// JARs will not run properly inside directories containing '!'
// http://bugs.java.com/view_bug.do?bug_id=4523159
if (Utils.isJarRunning() && Utils.getRunningDirectory() != null &&
Utils.getRunningDirectory().getAbsolutePath().indexOf('!') != -1)
ErrorHandler.error("JARs cannot be run from some paths containing '!'. Please move or rename the file and try again.", null, false);
else
ErrorHandler.error(message, e, report);
System.exit(1);
}
}

View File

@ -1,907 +0,0 @@
/*
* Copyright (c) 2013, Slick2D
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Slick2D nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.newdawn.slick;
import java.io.IOException;
import java.util.Properties;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Cursor;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.Drawable;
import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.newdawn.slick.gui.GUIContext;
import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.opengl.CursorLoader;
import org.newdawn.slick.opengl.ImageData;
import org.newdawn.slick.opengl.renderer.Renderer;
import org.newdawn.slick.opengl.renderer.SGL;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
/**
* A generic game container that handles the game loop, fps recording and
* managing the input system
*
* @author kevin
*/
public abstract class GameContainer implements GUIContext {
/** The renderer to use for all GL operations */
protected static SGL GL = Renderer.get();
/** The shared drawable if any */
protected static Drawable SHARED_DRAWABLE;
/** The time the last frame was rendered */
protected long lastFrame;
/** The last time the FPS recorded */
protected long lastFPS;
/** The last recorded FPS */
protected int recordedFPS;
/** The current count of FPS */
protected int fps;
/** True if we're currently running the game loop */
protected boolean running = true;
/** The width of the display */
protected int width;
/** The height of the display */
protected int height;
/** The game being managed */
protected Game game;
/** The default font to use in the graphics context */
private Font defaultFont;
/** The graphics context to be passed to the game */
private Graphics graphics;
/** The input system to pass to the game */
protected Input input;
/** The FPS we want to lock to */
protected int targetFPS = -1;
/** True if we should show the fps */
private boolean showFPS = true;
/** The minimum logic update interval */
protected long minimumLogicInterval = 1;
/** The stored delta */
protected long storedDelta;
/** The maximum logic update interval */
protected long maximumLogicInterval = 0;
/** The last game started */
protected Game lastGame;
/** True if we should clear the screen each frame */
protected boolean clearEachFrame = true;
/** True if the game is paused */
protected boolean paused;
/** True if we should force exit */
protected boolean forceExit = true;
/** True if vsync has been requested */
protected boolean vsync;
/** Smoothed deltas requested */
protected boolean smoothDeltas;
/** The number of samples we'll attempt through hardware */
protected int samples;
/** True if this context supports multisample */
protected boolean supportsMultiSample;
/** True if we should render when not focused */
protected boolean alwaysRender;
/** True if we require stencil bits */
protected static boolean stencil;
/**
* Create a new game container wrapping a given game
*
* @param game The game to be wrapped
*/
protected GameContainer(Game game) {
this.game = game;
lastFrame = getTime();
getBuildVersion();
Log.checkVerboseLogSetting();
}
public static void enableStencil() {
stencil = true;
}
/**
* Set the default font that will be intialised in the graphics held in this container
*
* @param font The font to use as default
*/
public void setDefaultFont(Font font) {
if (font != null) {
this.defaultFont = font;
} else {
Log.warn("Please provide a non null font");
}
}
/**
* Indicate whether we want to try to use fullscreen multisampling. This will
* give antialiasing across the whole scene using a hardware feature.
*
* @param samples The number of samples to attempt (2 is safe)
*/
public void setMultiSample(int samples) {
this.samples = samples;
}
/**
* Check if this hardware can support multi-sampling
*
* @return True if the hardware supports multi-sampling
*/
public boolean supportsMultiSample() {
return supportsMultiSample;
}
/**
* The number of samples we're attempting to performing using
* hardware multisampling
*
* @return The number of samples requested
*/
public int getSamples() {
return samples;
}
/**
* Indicate if we should force exitting the VM at the end
* of the game (default = true)
*
* @param forceExit True if we should force the VM exit
*/
public void setForceExit(boolean forceExit) {
this.forceExit = forceExit;
}
/**
* Indicate if we want to smooth deltas. This feature will report
* a delta based on the FPS not the time passed. This works well with
* vsync.
*
* @param smoothDeltas True if we should report smooth deltas
*/
public void setSmoothDeltas(boolean smoothDeltas) {
this.smoothDeltas = smoothDeltas;
}
/**
* Check if the display is in fullscreen mode
*
* @return True if the display is in fullscreen mode
*/
public boolean isFullscreen() {
return false;
}
/**
* Get the aspect ratio of the screen
*
* @return The aspect ratio of the display
*/
public float getAspectRatio() {
return getWidth() / getHeight();
}
/**
* Indicate whether we want to be in fullscreen mode. Note that the current
* display mode must be valid as a fullscreen mode for this to work
*
* @param fullscreen True if we want to be in fullscreen mode
* @throws SlickException Indicates we failed to change the display mode
*/
public void setFullscreen(boolean fullscreen) throws SlickException {
}
/**
* Enable shared OpenGL context. After calling this all containers created
* will shared a single parent context
*
* @throws SlickException Indicates a failure to create the shared drawable
*/
public static void enableSharedContext() throws SlickException {
try {
SHARED_DRAWABLE = new Pbuffer(64, 64, new PixelFormat(8, 0, 0), null);
} catch (LWJGLException e) {
throw new SlickException("Unable to create the pbuffer used for shard context, buffers not supported", e);
}
}
/**
* Get the context shared by all containers
*
* @return The context shared by all the containers or null if shared context isn't enabled
*/
public static Drawable getSharedContext() {
return SHARED_DRAWABLE;
}
/**
* Indicate if we should clear the screen at the beginning of each frame. If you're
* rendering to the whole screen each frame then setting this to false can give
* some performance improvements
*
* @param clear True if the the screen should be cleared each frame
*/
public void setClearEachFrame(boolean clear) {
this.clearEachFrame = clear;
}
/**
* Renitialise the game and the context in which it's being rendered
*
* @throws SlickException Indicates a failure rerun initialisation routines
*/
public void reinit() throws SlickException {
}
/**
* Pause the game - i.e. suspend updates
*/
public void pause()
{
setPaused(true);
}
/**
* Resumt the game - i.e. continue updates
*/
public void resume()
{
setPaused(false);
}
/**
* Check if the container is currently paused.
*
* @return True if the container is paused
*/
public boolean isPaused() {
return paused;
}
/**
* Indicates if the game should be paused, i.e. if updates
* should be propogated through to the game.
*
* @param paused True if the game should be paused
*/
public void setPaused(boolean paused)
{
this.paused = paused;
}
/**
* True if this container should render when it has focus
*
* @return True if this container should render when it has focus
*/
public boolean getAlwaysRender () {
return alwaysRender;
}
/**
* Indicate whether we want this container to render when it has focus
*
* @param alwaysRender True if this container should render when it has focus
*/
public void setAlwaysRender (boolean alwaysRender) {
this.alwaysRender = alwaysRender;
}
/**
* Get the build number of slick
*
* @return The build number of slick
*/
public static int getBuildVersion() {
try {
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream("version"));
int build = Integer.parseInt(props.getProperty("build"));
Log.info("Slick Build #"+build);
return build;
} catch (Exception e) {
Log.info("Unable to determine Slick build number");
return -1;
}
}
/**
* Get the default system font
*
* @return The default system font
*/
@Override
public Font getDefaultFont() {
return defaultFont;
}
/**
* Check if sound effects are enabled
*
* @return True if sound effects are enabled
*/
public boolean isSoundOn() {
return SoundStore.get().soundsOn();
}
/**
* Check if music is enabled
*
* @return True if music is enabled
*/
public boolean isMusicOn() {
return SoundStore.get().musicOn();
}
/**
* Indicate whether music should be enabled
*
* @param on True if music should be enabled
*/
public void setMusicOn(boolean on) {
SoundStore.get().setMusicOn(on);
}
/**
* Indicate whether sound effects should be enabled
*
* @param on True if sound effects should be enabled
*/
public void setSoundOn(boolean on) {
SoundStore.get().setSoundsOn(on);
}
/**
* Retrieve the current default volume for music
* @return the current default volume for music
*/
public float getMusicVolume() {
return SoundStore.get().getMusicVolume();
}
/**
* Retrieve the current default volume for sound fx
* @return the current default volume for sound fx
*/
public float getSoundVolume() {
return SoundStore.get().getSoundVolume();
}
/**
* Set the default volume for sound fx
* @param volume the new default value for sound fx volume
*/
public void setSoundVolume(float volume) {
SoundStore.get().setSoundVolume(volume);
}
/**
* Set the default volume for music
* @param volume the new default value for music volume
*/
public void setMusicVolume(float volume) {
SoundStore.get().setMusicVolume(volume);
}
/**
* Get the width of the standard screen resolution
*
* @return The screen width
*/
@Override
public abstract int getScreenWidth();
/**
* Get the height of the standard screen resolution
*
* @return The screen height
*/
@Override
public abstract int getScreenHeight();
/**
* Get the width of the game canvas
*
* @return The width of the game canvas
*/
@Override
public int getWidth() {
return width;
}
/**
* Get the height of the game canvas
*
* @return The height of the game canvas
*/
@Override
public int getHeight() {
return height;
}
/**
* Set the icon to be displayed if possible in this type of
* container
*
* @param ref The reference to the icon to be displayed
* @throws SlickException Indicates a failure to load the icon
*/
public abstract void setIcon(String ref) throws SlickException;
/**
* Set the icons to be used for this application. Note that the size of the icon
* defines how it will be used. Important ones to note
*
* Windows window icon must be 16x16
* Windows alt-tab icon must be 24x24 or 32x32 depending on Windows version (XP=32)
*
* @param refs The reference to the icon to be displayed
* @throws SlickException Indicates a failure to load the icon
*/
public abstract void setIcons(String[] refs) throws SlickException;
/**
* Get the accurate system time
*
* @return The system time in milliseconds
*/
@Override
public long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
/**
* Sleep for a given period
*
* @param milliseconds The period to sleep for in milliseconds
*/
public void sleep(int milliseconds) {
long target = getTime()+milliseconds;
while (getTime() < target) {
try { Thread.sleep(1); } catch (Exception e) {}
}
}
/**
* Set the mouse cursor to be displayed - this is a hardware cursor and hence
* shouldn't have any impact on FPS.
*
* @param ref The location of the image to be loaded for the cursor
* @param hotSpotX The x coordinate of the hotspot within the cursor image
* @param hotSpotY The y coordinate of the hotspot within the cursor image
* @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
*/
@Override
public abstract void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException;
/**
* Set the mouse cursor to be displayed - this is a hardware cursor and hence
* shouldn't have any impact on FPS.
*
* @param data The image data from which the cursor can be construted
* @param hotSpotX The x coordinate of the hotspot within the cursor image
* @param hotSpotY The y coordinate of the hotspot within the cursor image
* @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
*/
@Override
public abstract void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException;
/**
* Set the mouse cursor based on the contents of the image. Note that this will not take
* account of render state type changes to images (rotation and such). If these effects
* are required it is recommended that an offscreen buffer be used to produce an appropriate
* image. An offscreen buffer will always be used to produce the new cursor and as such
* this operation an be very expensive
*
* @param image The image to use as the cursor
* @param hotSpotX The x coordinate of the hotspot within the cursor image
* @param hotSpotY The y coordinate of the hotspot within the cursor image
* @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
*/
public abstract void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException;
/**
* Set the mouse cursor to be displayed - this is a hardware cursor and hence
* shouldn't have any impact on FPS.
*
* @param cursor The cursor to use
* @param hotSpotX The x coordinate of the hotspot within the cursor image
* @param hotSpotY The y coordinate of the hotspot within the cursor image
* @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
*/
@Override
public abstract void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException;
/**
* Get a cursor based on a image reference on the classpath. The image
* is assumed to be a set/strip of cursor animation frames running from top to
* bottom.
*
* @param ref The reference to the image to be loaded
* @param x The x-coordinate of the cursor hotspot (left {@literal ->} right)
* @param y The y-coordinate of the cursor hotspot (bottom {@literal ->} top)
* @param width The x width of the cursor
* @param height The y height of the cursor
* @param cursorDelays image delays between changing frames in animation
*
* @throws SlickException Indicates a failure to load the image or a failure to create the hardware cursor
*/
public void setAnimatedMouseCursor(String ref, int x, int y, int width, int height, int[] cursorDelays) throws SlickException
{
try {
Cursor cursor;
cursor = CursorLoader.get().getAnimatedCursor(ref, x, y, width, height, cursorDelays);
setMouseCursor(cursor, x, y);
} catch (IOException e) {
throw new SlickException("Failed to set mouse cursor", e);
} catch (LWJGLException e) {
throw new SlickException("Failed to set mouse cursor", e);
}
}
/**
* Set the default mouse cursor - i.e. the original cursor before any native
* cursor was set
*/
@Override
public abstract void setDefaultMouseCursor();
/**
* Get the input system
*
* @return The input system available to this game container
*/
@Override
public Input getInput() {
return input;
}
/**
* Get the current recorded FPS (frames per second)
*
* @return The current FPS
*/
public int getFPS() {
return recordedFPS;
}
/**
* Indicate whether mouse cursor should be grabbed or not
*
* @param grabbed True if mouse cursor should be grabbed
*/
public abstract void setMouseGrabbed(boolean grabbed);
/**
* Check if the mouse cursor is current grabbed. This will cause it not
* to be seen.
*
* @return True if the mouse is currently grabbed
*/
public abstract boolean isMouseGrabbed();
/**
* Retrieve the time taken to render the last frame, i.e. the change in time - delta.
*
* @return The time taken to render the last frame
*/
protected int getDelta() {
long time = getTime();
int delta = (int) (time - lastFrame);
lastFrame = time;
return delta;
}
/**
* Updated the FPS counter
*/
protected void updateFPS() {
if (getTime() - lastFPS > 1000) {
lastFPS = getTime();
recordedFPS = fps;
fps = 0;
}
fps++;
}
/**
* Set the minimum amount of time in milliseonds that has to
* pass before update() is called on the container game. This gives
* a way to limit logic updates compared to renders.
*
* @param interval The minimum interval between logic updates
*/
public void setMinimumLogicUpdateInterval(int interval) {
minimumLogicInterval = interval;
}
/**
* Set the maximum amount of time in milliseconds that can passed
* into the update method. Useful for collision detection without
* sweeping.
*
* @param interval The maximum interval between logic updates
*/
public void setMaximumLogicUpdateInterval(int interval) {
maximumLogicInterval = interval;
}
/**
* Update and render the game
*
* @param delta The change in time since last update and render
* @throws SlickException Indicates an internal fault to the game.
*/
protected void updateAndRender(int delta) throws SlickException {
if (smoothDeltas) {
if (getFPS() != 0) {
delta = 1000 / getFPS();
}
}
input.poll(width, height);
Music.poll(delta);
if (!paused) {
storedDelta += delta;
if (storedDelta >= minimumLogicInterval) {
try {
if (maximumLogicInterval != 0) {
long cycles = storedDelta / maximumLogicInterval;
for (int i=0;i<cycles;i++) {
game.update(this, (int) maximumLogicInterval);
}
int remainder = (int) (storedDelta % maximumLogicInterval);
if (remainder > minimumLogicInterval) {
game.update(this, (int) (remainder % maximumLogicInterval));
storedDelta = 0;
} else {
storedDelta = remainder;
}
} else {
game.update(this, (int) storedDelta);
storedDelta = 0;
}
} catch (Throwable e) {
// Log.error(e);
throw new SlickException("Game.update() failure.", e);
}
}
} else {
game.update(this, 0);
}
if (hasFocus() || getAlwaysRender()) {
if (clearEachFrame) {
GL.glClear(SGL.GL_COLOR_BUFFER_BIT | SGL.GL_DEPTH_BUFFER_BIT);
}
GL.glLoadIdentity();
graphics.resetTransform();
graphics.resetFont();
graphics.resetLineWidth();
graphics.setAntiAlias(false);
try {
game.render(this, graphics);
} catch (Throwable e) {
// Log.error(e);
throw new SlickException("Game.render() failure.", e);
}
graphics.resetTransform();
if (showFPS) {
defaultFont.drawString(10, 10, "FPS: "+recordedFPS);
}
GL.flush();
}
if (targetFPS != -1) {
Display.sync(targetFPS);
}
}
/**
* Indicate if the display should update only when the game is visible
* (the default is true)
*
* @param updateOnlyWhenVisible True if we should updated only when the display is visible
*/
public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) {
}
/**
* Check if this game is only updating when visible to the user (default = true)
*
* @return True if the game is only updated when the display is visible
*/
public boolean isUpdatingOnlyWhenVisible() {
return true;
}
/**
* Initialise the GL context
*/
protected void initGL() {
Log.info("Starting display "+width+"x"+height);
GL.initDisplay(width, height);
if (input == null) {
input = new Input(height);
}
input.init(height);
// no need to remove listeners?
//input.removeAllListeners();
if (game instanceof InputListener) {
input.removeListener((InputListener) game);
input.addListener((InputListener) game);
}
if (graphics != null) {
graphics.setDimensions(getWidth(), getHeight());
}
lastGame = game;
}
/**
* Initialise the system components, OpenGL and OpenAL.
*
* @throws SlickException Indicates a failure to create a native handler
*/
protected void initSystem() throws SlickException {
initGL();
setMusicVolume(1.0f);
setSoundVolume(1.0f);
graphics = new Graphics(width, height);
defaultFont = graphics.getFont();
}
/**
* Enter the orthographic mode
*/
protected void enterOrtho() {
enterOrtho(width, height);
}
/**
* Indicate whether the container should show the FPS
*
* @param show True if the container should show the FPS
*/
public void setShowFPS(boolean show) {
showFPS = show;
}
/**
* Check if the FPS is currently showing
*
* @return True if the FPS is showing
*/
public boolean isShowingFPS() {
return showFPS;
}
/**
* Set the target fps we're hoping to get
*
* @param fps The target fps we're hoping to get
*/
public void setTargetFrameRate(int fps) {
targetFPS = fps;
}
/**
* Indicate whether the display should be synced to the
* vertical refresh (stops tearing)
*
* @param vsync True if we want to sync to vertical refresh
*/
public void setVSync(boolean vsync) {
this.vsync = vsync;
Display.setVSyncEnabled(vsync);
}
/**
* True if vsync is requested
*
* @return True if vsync is requested
*/
public boolean isVSyncRequested() {
return vsync;
}
/**
* True if the game is running
*
* @return True if the game is running
*/
protected boolean running() {
return running;
}
/**
* Inidcate we want verbose logging
*
* @param verbose True if we want verbose logging (INFO and DEBUG)
*/
public void setVerbose(boolean verbose) {
Log.setVerbose(verbose);
}
/**
* Cause the game to exit and shutdown cleanly
*/
public void exit() {
running = false;
}
/**
* Check if the game currently has focus
*
* @return True if the game currently has focus
*/
public abstract boolean hasFocus();
/**
* Get the graphics context used by this container. Note that this
* value may vary over the life time of the game.
*
* @return The graphics context used by this container
*/
public Graphics getGraphics() {
return graphics;
}
/**
* Enter the orthographic mode
*
* @param xsize The size of the panel being used
* @param ysize The size of the panel being used
*/
protected void enterOrtho(int xsize, int ysize) {
GL.enterOrtho(xsize, ysize);
}
}