Really Use StandardGame?

I'm working with StandardGame (slightly modified to remove the existing audio code) to create my apps, but I'm curious as to how it would work with things like animated textures.  Right now when I have textures I need to set, I do it in the very beginning using a task that gets passed to the OpenGL queue, but if I wanted to do animated textures etc would somehow creating a task to pass to my StandardGame (which I'm not quite sure how to do inside of my GameStates) end up being too much overhead?  Maybe there's something I'm completely missing…seems to happen frequently…



With StandardGame, I have issues starting up the app frequently; it'll accept my display configuration and then give me a black screen (a thread locks up somewhere, and the last message I see is a timing message with the number 1000 in it…can't quite remember right now).



I understand the performance improvements possible with OpenGL running in its own thread, however do you think it be more efficient for me to create a thread simply for the use of the main game loop, dealing with anything that could draw, and then one that does all the non-drawing-related updates (like sound, loading/preloading, etc)?



In short, I'm wondering whether it's better to switch back to the single-threaded (or my own threaded) style of doing everything.  Thoughts?  Thanks in advance!

If you're getting consistency issues in your app it is probably because you're doing something multithreaded that isn't thread-safe.



I would say for StandardGame startup is your biggest concern because other than AI, Networking, etc interjecting into the running game the majority of work done from there is typically called from a GameState's update or render method, so is already in the OpenGL thread in the first place.

I'll double check when I get back in a few hours to see where I'm getting the hanging issue, and I see what you mean regarding the update and render methods.



I'm not sure when it hangs I'm even getting past the initialization of StandardGame, which is something I'll check.  I doubt I'm doing anything non-threadsafe (mm…"threadsafe"…like how the term is used in Java - will detect+throw and exception, or sometimes detect, when a thread is concurrently stomping in another's playground), as my states are nice and decoupled (except the camera that's passed around like a cheap…umm…Kodak disposable), but I'll double check, and double-post.



Thanks!

It seems like it does deal with threading issues, in my main setup method where I set all the states up, I add the ones that deal with textures to the GameTaskQueueManager, and there may be a dependency in there.  I seem to have stupidly forgotten that I'm running those in separate threads.

Or so I thought…until I remembered that the .get() method will make it block so it's performed sequentially…



However, when I stop doing that and simply do game.lock() to perform those texture setups, I get a NullPointerException on glHint (where I was in my previous issues regarding StandardGame).



When I was println debugging (I know, very advanced), I found that the constructor for my "ThirdWorldGameState" is never called…or the constructor of any of its parents (I added println statements into the beginning of constructors all the way up to BasicGameState).


ThirdWorldGameState state = GameTaskQueueManager.getManager().update(
      new Callable<ThirdWorldGameState>(){
         public ThirdWorldGameState call() throws Exception
         {
            return new ThirdWorldGameState();
         }
      }).get();
System.out.println("GOT PAST THIRDWORLDSTATE!");



I would assume that something's going on in the update() method of the GameTaskQueueManager, but I have yet to look at it.  Any ideas?

Update:  The invoke() method in GameTask isn't even being called when the issue happens.  Looking more into it...
It's added to the queue, but something happens between being added and being called that makes it never call.

You're not calling game.lock() before invoking at are you?  If you do it will cause the current thread to lock the game thread and the game thread to lock the current thread. :-p



The reason you can't always use game.lock() instead of GameTaskQueue is that thread-safety in OpenGL has two parts.  The first is making sure that something doesn't change something that the OpenGL thread is currently using at the wrong time (which game.lock() resolves).  The second is that certain things break horribly if they are run in the OpenGL thread.  This second part is very unfortunate since game.lock() is a really clean approach, but there's no way it can handle this problem.

Correct, I'm not using game.lock() at all when it's freezing.  That was simply an attempt to try that instead of the GameTaskQueueManager…



When it's freezing (which seems to happen about half the time when I start up the app- maybe a bit less), it just doesn't get to invoking the method in the queue.  It gets added, but something in the OpenGL thread locks up before executing it, or removes it without executing, which causes my .get() method to block until I kill the application manually.

you might consider trying to add your entire initialization block into a GameTask to see if that fixes it.  At least then you'll know for sure that's the problem.

I'll try that…but I would assume it'd simply do the same thing, if the execute() method isn't being called anyway.

or you could also add the code to attach your GameState inside the GameTask and then you could just pass it in without having to call get()

Here's the whole of my code, and I still get the issue: it doesn't get past the .get() command some of the time.  In this case, I was "lucky" and it happened on the first execution, and not on the second (so I didn't have to keep executing)  This is as simple as it gets…



   // Instantiate StandardGame
   StandardGame game = new StandardGame("Simple GUI Test");
   // Show settings screen
   GameSettingsPanel.prompt(game.getSettings());
   
   // Start StandardGame, it will block until it has initialized successfully, then return
   game.start();
      
   System.out.println("GOT PAST GAME.START()!");
   String state = GameTaskQueueManager.getManager().update(
         new Callable<String>(){
            public String call() throws Exception
            {
               return new String("MEOW");
            }
         }).get();
   System.out.println(state);
   System.out.println("GOT PAST THIRDWORLDSTATE!");

Sorry for double posting…and twice in the same forum…but this issue is causing hell.



I stepped through the code line-by-line in the Eclipse debugger, and I saw no error, so I guess it’s probably a timing issue dealing with GameTaskQueueManager, but I can’t quite figure it out.



Update:  I added a Thread.sleep(200) before my code is called, and this seems to fix the issue (for all times I’ve executed).  There’s a race condition with game.start() and the GameTaskQueueManager.getManager().update call.  I’m looking more into pinpointing it.



UPDATE!  Ok, I pinpointed it.  The issue is in the GameTaskQueueManager getInstance() call.  I added a simple print statement, as shown below, and found, indeed, that when the error occured, the statement was printed twice.  The issue arises because my main thread creates an instance of the gametaskqueuemanager and adds the GameTask right AFTER the StandardGame thread checks for null.  So in short: GameTaskQueueManager is initialized twice, the second time wiping out my Tasks.



        public static GameTaskQueueManager getManager() {
        if (MANAGER_INSTANCE == null)
        {
            MANAGER_INSTANCE = new GameTaskQueueManager();
            System.out.println("WANGANGANGANGANGANGANGANG");
        }
        return MANAGER_INSTANCE ;
    }


I assume this wasn't seem before possibly because either of different system speeds/configurations, or JRE scheduling differences (or both).  I'm not sure how many others are running Linux...

So, the fix is to ensure GameTaskQueueManager has been initialized before you start your StandardGame thread by calling GameTaskQueueManager.getManager(); first.

Actually the way this should be resolved is by simply adding a "synchronized" in that method declaration for getManager().  I don't remember whether I wrote that or Renanse did.  I'm sure I'm more likely to blame. :wink:



If you modify that method in your code to say:


public static synchronized GameTaskQueueManager getManager() { ... }



I bet that fixes your troubles.  A getter on a singleton should always be synchronized.