package rts.core; import java.io.IOException; import java.util.ArrayList; import org.gjt.sp.jedit.jEdit; import org.luawars.Log; import org.lwjgl.LWJGLException; import org.lwjgl.opengl.GL11; import org.newdawn.slick.*; import de.matthiasmann.twl.GUI; import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer; import de.matthiasmann.twl.theme.ThemeManager; import org.newdawn.slick.state.GameState; import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.util.InputAdapter; import rts.core.engine.Engine; import rts.core.engine.GameMusic; import rts.core.network.NetworkManager; import rts.utils.Configuration; import rts.utils.ResourceManager; import rts.views.CreateView; import rts.views.CreditsView; import rts.views.MainMenuView; import rts.views.NetworkView; import rts.views.OptionsView; import rts.views.ResourcesView; import rts.views.View; import javax.swing.*; import rts.views.TutorialView; import rts.views.ProfileView; import static org.gjt.sp.jedit.jEdit.jEdit_init; /** * The main game class, contain the view lists and the launch process. * * @author Vincent PIRAULT * */ public class Game extends StateBasedGame { // State IDS public static final int PRESENTATION_STATE_ID = 0; public static final int RESOURCES_STATE_ID = 1; public static final int MAIN_MENU_VIEW_ID = 2; public static final int NETWORK_VIEW_ID = 3; public static final int OPTIONS_VIEW_ID = 4; public static final int CREDITS_VIEW_ID = 5; public static final int ENGINE_VIEW_ID = 6; public static final int CREATE_VIEW_ID = 7; public static final int TUTORIAL_VIEW_ID = 8; public static final int PROFILE_VIEW_ID = 9; /** * The current name of the project. */ public static final String NAME = "LUA WARS"; /** * The current version of the project. */ public static final String VERSION = "Version 1.0 Beta"; private ArrayList<View> states; /** * The network manager */ private NetworkManager networkManager; // TWL private static final String THEME_PATH = "resources/themes/guiTheme.xml"; private LWJGLRenderer lwjglRenderer; private ThemeManager theme; private GUI gui; private TWLInputAdapter twlWrapper; /** * The game class constructor, initialize the game from the resources and * configuration files. * * @param resourceJarLocation * @param configFileLocation * @throws IOException * @throws SlickException */ public Game(String resourceJarLocation, String configFileLocation) throws IOException, SlickException { super(NAME); // Initialize resources ResourceManager.init(resourceJarLocation); // Initialize configuration Configuration.init(configFileLocation); states = new ArrayList<View>(); networkManager = new NetworkManager(); } @Override public void initStatesList(GameContainer container) throws SlickException { Log.logEnterMethod(Log.DEBUG); addState(new ResourcesView(container)); addState(new MainMenuView()); addState(new NetworkView()); addState(new OptionsView()); addState(new CreditsView()); addState(new Engine()); addState(new CreateView()); addState(new TutorialView()); addState(new ProfileView()); Log.debug(Log.me() + " createTWLRenderer()..."); createTWLRenderer(); Log.logExitMethod(Log.DEBUG); } @Override public void addState(GameState state) { super.addState(state); states.add((View) state); } public View getStateByIndex(int index) { return (View) states.get(index); } /** * Entry point to launch the game. * * @throws SlickException * @throws IOException */ public void launch() throws SlickException, IOException { // AppGameContainer container = new AppGameContainer(this); final CanvasGameContainer can = new CanvasGameContainer(this); AppGameContainer container = (AppGameContainer)can.getContainer(); // Mandatory container.setMinimumLogicUpdateInterval(10); container.setMaximumLogicUpdateInterval(10); container.setUpdateOnlyWhenVisible(false); container.setAlwaysRender(true); // Apply Configuration applyCurrentConfiguration(container); // set size (greg added this) SwingUtilities.invokeLater(new Runnable() { public void run() { // JFrame frame = new JFrame("Lua Wars"); // frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // MainPanel panel = new MainPanel(); // // TODO: make it so that container.getWidth() is used instead and works Log.debug("Setting container size: "+Configuration.getWidth()+"w "+Configuration.getHeight()+"h"); can.setSize(Configuration.getWidth(), Configuration.getHeight()); //panel.splitPane.setRightComponent(can); JPanel pan = new JPanel(); pan.add(can); jEdit_init(pan); // frame.setContentPane(panel.panel); // frame.pack(); // frame.setVisible(true); } }); while (!jEdit.STARTUPISDONE) try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } // Start the game Log.debug("!!!!!!!!!! jEdit done!"); can.start(); // TODO: fix this exception when clicking 'Exit' /* AL lib: FreeDevice: (0x10fc30000) Deleting 31 Buffer(s) Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Mouse must be created before you can read events at org.lwjgl.input.Mouse.next(Mouse.java:444) at org.newdawn.slick.Input.poll(Input.java:1205) at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:656) at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:456) at org.newdawn.slick.CanvasGameContainer$2.run(CanvasGameContainer.java:100) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:702) at java.awt.EventQueue.access$400(EventQueue.java:82) at java.awt.EventQueue$2.run(EventQueue.java:663) at java.awt.EventQueue$2.run(EventQueue.java:661) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87) at java.awt.EventQueue.dispatchEvent(EventQueue.java:672) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) */ } private void applyCurrentConfiguration(AppGameContainer container) throws IOException, SlickException { Configuration.updateConfigFile(); container.setDisplayMode(Configuration.getWidth(), Configuration.getHeight(), Configuration.isFullScreen()); container.setTargetFrameRate(Configuration.getTargetFPS()); container.setSmoothDeltas(Configuration.isSmoothDeltas()); container.setVSync(Configuration.isVSynch()); container.setMusicVolume(Configuration.getMusicVolume()); container.setSoundVolume(Configuration.getSoundVolume()); container.setShowFPS(Configuration.isDebug()); container.setVerbose(Configuration.isDebug()); GameMusic.ENABLE_MUSIC = Configuration.enableMusic(); } /** * Apply the current configuration to the game container of the game * context. * * @throws IOException * If the configuration loading failed. * @throws SlickException * If the configuration loading failed. */ public void applyCurrentConfiguration() throws IOException, SlickException { applyCurrentConfiguration((AppGameContainer)this.getContainer()); } /** * A cut to get the engine instance directly. * * @return The engine instance or null if the engine was not instantiated. */ public Engine getEngine() { return (Engine) this.getState(ENGINE_VIEW_ID); } public NetworkManager getNetworkManager() { return networkManager; } // TWL private void createTWLRenderer() { // save Slick's GL state while loading the theme GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); try { lwjglRenderer = new LWJGLRenderer(); lwjglRenderer.setUseSWMouseCursors(true); theme = ThemeManager.createThemeManager(Thread.currentThread().getContextClassLoader().getResource(THEME_PATH), lwjglRenderer); gui = new GUI(lwjglRenderer); gui.applyTheme(theme); } catch (LWJGLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // restore Slick's GL state GL11.glPopAttrib(); } // connect input twlWrapper = new TWLInputAdapter(gui, getContainer().getInput()); getContainer().getInput().addPrimaryListener(twlWrapper); } public void updateTWL() { twlWrapper.update(); } public void renderTWL() { // gui.setRootPane(((View) getCurrentState()).getTwlRootWidget()); twlWrapper.render(); } public void reloadTWL() { gui.destroy(); lwjglRenderer.getActiveCacheContext().destroy(); gui = null; lwjglRenderer = null; createTWLRenderer(); getContainer().setMouseGrabbed(false); } public void initAllTWLComponents() { Log.logEnterMethod(Log.DEBUG); // We didn't init the resource view for (int i = 1; i < states.size(); i++) { states.get(i).initTwl(); } Log.logExitMethod(Log.DEBUG); } public class TWLInputAdapter extends InputAdapter { private final Input input; private final GUI gui; private int mouseDown; private boolean ignoreMouse; private boolean lastPressConsumed; public TWLInputAdapter(GUI gui, Input input) { if (gui == null) { throw new NullPointerException("gui"); } if (input == null) { throw new NullPointerException("input"); } this.gui = gui; this.input = input; } @Override public void mouseWheelMoved(int change) { if (!ignoreMouse) { if (gui.handleMouseWheel(change)) { consume(); } } } @Override public void mousePressed(int button, int x, int y) { if (mouseDown == 0) { // only the first button down counts lastPressConsumed = false; } mouseDown |= 1 << button; if (!ignoreMouse) { if (gui.handleMouse(x, y, button, true)) { consume(); lastPressConsumed = true; } } } @Override public void mouseReleased(int button, int x, int y) { mouseDown &= ~(1 << button); if (!ignoreMouse) { if (gui.handleMouse(x, y, button, false)) { consume(); } } else if (mouseDown == 0) { ignoreMouse = false; } } @Override public void mouseMoved(int oldX, int oldY, int newX, int newY) { if (mouseDown != 0 && !lastPressConsumed) { ignoreMouse = true; gui.clearMouseState(); } else if (!ignoreMouse) { if (gui.handleMouse(newX, newY, -1, false)) { consume(); } } } @Override public void mouseDragged(int oldx, int oldy, int newX, int newY) { mouseMoved(oldx, oldy, newX, newY); } @Override public void keyPressed(int key, char c) { if (gui.handleKey(key, c, true)) { consume(); } } @Override public void keyReleased(int key, char c) { if (gui.handleKey(key, c, false)) { consume(); } } @Override public void mouseClicked(int button, int x, int y, int clickCount) { if (!ignoreMouse && lastPressConsumed) { consume(); } } private void consume() { input.consumeEvent(); } @Override public void inputStarted() { gui.updateTime(); } @Override public void inputEnded() { gui.handleKeyRepeat(); } /** * Call this method from {@code BasicGame.update} * * @see StateBasedGame#update(org.newdawn.slick.GameContainer, int) */ public void update() { gui.setSize(); gui.handleTooltips(); gui.updateTimers(); gui.invokeRunables(); gui.validateLayout(); gui.setCursor(); } /** * Call this method from {@code BasicGame.render} * * @see StateBasedGame#render(org.newdawn.slick.GameContainer, * org.newdawn.slick.Graphics) */ public void render() { gui.draw(); } } public void setRootPane(int id) { gui.setRootPane(((View) getState(id)).getTwlRootWidget()); } }