I have three GameStates: a "normal" BackgroundGameState (derived from BasicGameState), and MenuGameSate and VideoMenuGameState (both derived from JMEDesktopState). Every state on it's own is working. I try to do the following:
public static void main(String[] args) throws Exception {
preferences = ...
gameSettings = new PreferencesGameSettings(preferences);
game = new StandardGame("KanjiTori", StandardGame.GameType.GRAPHICAL, gameSettings);
game.setBackgroundColor(new ColorRGBA(0.1f, 0.5f, 0.4f, 0f));
game.start();
setMenuGameState();
}
When I call setVideoGameState, the VideoMenuGameState "freezes". If I comment out that call, BackgroundGameState works fine. The problem must be in JMEDesktopState, because I can't even call System.out.println() in the constructor of VideoMenuGameState, and if I replace that line with setState(new JMEDesktopState()); I get the same behavior: I don't get an error, the app is just frozen.
First I thought that the things I do in clearState() could be the reason, but commenting it out had no effect.
Then I thought, maybe I'm in thread-trouble because that method is called by an ActionListener, so I tried to wrap the call with GameTaskQueueManager.getInstance().update(), also without success.
Everything was working fine as long as I created all my gameStates at the beginning, and only activated and deactivated it. However the current change is required, because I want to be able to change the resolution in-game, and that create-everything-from-scratch-design would save me from all kinds of crazy reinitializations. Any ideas to save the noob?
I tried everything: GameTaskQueueManager, SwingUtilities, a simple Thread.start, nothing works. I can choose between a deadlock, or this error message:
java.lang.IllegalStateException: not in swing thread!
at com.jmex.awt.swingui.JMEDesktop.dispatchEvent(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.setFocusOwner(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.setup(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.<init>(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.<init>(Unknown Source)
at com.jmex.awt.swingui.JMEDesktopState$1.call(Unknown Source)
at com.jmex.awt.swingui.JMEDesktopState$1.call(Unknown Source)
at com.jme.util.GameTask.invoke(Unknown Source)
at com.jme.util.GameTaskQueue.execute(Unknown Source)
at com.jmex.game.StandardGame.update(Unknown Source)
at com.jmex.game.StandardGame.run(Unknown Source)
at java.lang.Thread.run(Thread.java:595)
java.util.concurrent.ExecutionException: java.lang.IllegalStateException: not in swing thread!
at com.jme.util.GameTask.invoke(Unknown Source)
at com.jme.util.GameTaskQueue.execute(Unknown Source)
at com.jmex.game.StandardGame.update(Unknown Source)
at com.jmex.game.StandardGame.run(Unknown Source)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.lang.IllegalStateException: not in swing thread!
at com.jmex.awt.swingui.JMEDesktop.dispatchEvent(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.setFocusOwner(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.setup(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.<init>(Unknown Source)
at com.jmex.awt.swingui.JMEDesktop.<init>(Unknown Source)
at com.jmex.awt.swingui.JMEDesktopState$1.call(Unknown Source)
at com.jmex.awt.swingui.JMEDesktopState$1.call(Unknown Source)
... 5 more
Note that I've removed all GUI code from my state, the problem is in JMEDesktopState...
Here is a minimal example reproducing the problem. If you press the button (because it says so), you see the output "start", but then everything is frozen.
Similar to GameTaskQueue I believe Irrisor wrote some functionality to inject code into the Swing thread…I can't remember what that is off the top of my head though. Perhaps that would help.
I realise that the last post on this was back in July, but I've just encountered the same deadlock problem with JMEDesktop… and there was no solution posted… arrrrrgh!!!
So having hacked about I've found a solution to the deadlock and thought I'd post it for future prosperity.
For me the deadlock was caused by waiting on the OpenGL queue,
Future<JMEDesktop> future = GameTaskQueueManager.getManager ().update (new Callable<JMEDesktop>()
{
public JMEDesktop call () throws Exception
{
return new JMEDesktop ("Desktop", width, height , input);
}
});
desktop = future.get(); // Deadlock here - process hangs
That COMPLETELY defeats the purpose of injecting into the GameTaskQueueManager if you're going to immediately invoke the execute you may as not put it in there in the first place. Further, you're potentially causing other issues if something else got injected into the GameTaskQueueManager that would then be invoked in whatever thread that is.
Darkfrog your completely right, both are fair and valid points (it was a hack of a solution).
Admittedly I now feel a bit noobish, as I went back and tried it without using the concurrency classes (no insertion into OpenGL thread) and it worked, very strange because it did not before and I have absolutely no idea why.
I believe my misunderstanding came from an idea that JMEDesktop needed to be created being inserted into the OpenGL thread, this simply seems not to be the case.
I think I know what causes the problem: JMEDesktopState waits on the result of constructing an JMEDesktop.
That means JMEDesktopState only works in conjunction with Multithreadiness right ?
If i use a single threaded App, i need to create my own copy of JMEDesktopState without the GameTaskQueueManager stuff in it?
I ask, because at the moment i play around with GameStates and VariableTimestepGame (which is single threaded).
Maybe a 2nd constructor with a boolean multiThreaded would be nice to have.
if multiThreaded == false, don't make use of GameTaskQueueManager.
Or alternatively a constructor where i could give a reference to JMEDesktop as a parameter, then it wouldn't need to be created in the init() function.
This situation is very similar to the one observed in ModelLoader, and I am suggesting a workaround (not extremely clean, I know, but if you use GameQueues then it cannot be very clean). See this thread for reference: http://www.jmonkeyengine.com/jmeforum/index.php?topic=4735.0