by date
Debugging an Action Map - possibly of very little interest
Debugging an Action Map - possibly of very little interest
| Name: | Mark Dynna | ![]() |
|---|---|---|
| Date Posted: | May 12, 2008 | |
| Rating: | 5.0 out of 5 | |
| Public: | YES | |
| Comments: | YES | |
| RSS Feed: | or Subscribe with . | |
| Profile Page: | View profile page for Mark Dynna |
Blog post
I have no idea if this is actually going to be of interest to many other people, but I thought I'd blog it anyway in the off-chance it is interesting to someone out there. This is the story of a strange bug I tracked down recently that got stranger and stranger as I attempted to debug it. Perhaps someone can learn something by following the process I went through to track down this problem, or perhaps someone can give me some pointers on how to find this stuff faster and easier. Anyways, enough forward...
Our team had been happily moving along, making good progress developing our Chariot racing game when I got a bug report. Most of the keyboard controls for our lead World Builder (and general boss-lady) had suddenly stopped working. No one else was currently experiencing this problem (including myself). As with most keyboard-related bugs, I first told her to delete her custom controls, reset back to defaults, and re-map any custom ones again. She reported that the custom controls would work, but the instant she tried to re-map any one of them, they would all stop working. So, I gave it a shot on my machine. I deleted my custom config file (which was pretty much all defaults anyway) and loaded up the game. Nothing. I could not move anywhere even though all of my movement keys were the defaults and were working just a second ago. (ASIDE: Even now, knowing the cause of the problem, these symptoms still baffle me...)
So, clearly something had changed that any new control schemes created just didn't work. Bug replicated, so I moved on. One of the curious other symptoms of the problem was that the controls would work fine when the Mission Editor was activated, but not in normal "play" mode. That initially led me to believe there was something strange going on with the ActionMaps since the Mission Editor GUI does some pushing and popping when it activates or deactivates.
Now, we do have some involved code involving Action Maps, in that we are allowing the user to have different control schemes for different movement modes (on foot, riding a horse, driving a chariot). So, it seemed natural to me that something could be broken there. I explored that option for awhile with changing things and scouring our multi-action map code, but everything looked like it was working as it should. In the process I wrote a nifty (I think) little function. I wanted to make sure all of our calls to push andpop were happening correctly, but I couldn't find a easy way to tell exactly which action maps were on the stack at any given time. So, I whipped up a fuunction called dumpActionMapStack. Nothing particularly fancy about it, but it got the job done:
Anyway, the whole ActionMap avenue didn't seem to be going anywhere. Everything always seemed to be exactly as it should be. So, I started to think of other reasons why the controls worked when the Mission Editor was active. That led me to investigate the GUI. A knew a quick test could quickly confirm that theory. : I commented out all of everything but the GameTSCtrl. Lo and behold I could move, so it had to be something in the GUI! Now, for those of you who wouldn't know where to go from here let me show you. Inputs (like keystrokes) in Torque "enter" the system through the GameInterface::processInputEvent function, in main.cpp:
As you can see, there's a definite order to things. First, the Global Action Map gets a crack to see if it should handle the event. If not, the Canvas (the current GUI) sees if it needs to handle the event (by returning TRUE), and only if it does not handle the event does the current ActionMap(s) actually get to see the event. So, I knew something was happening in that Canvas::processInputEvent function. Now, at this point, I could've thrown a breakpoint in that function and ran in Debug mode, but I have found that trying to Debug input events using a breakpoint is rough stuff: you usually end up catching 50 events you don't want, so you start nailing that F5 key repeatedly and inevitable end up missing the input even you do want. So, I decided to just throw in some console output and see what I got.
I looked through all the possible places that the function could return TRUE (the event was processed/consumed) and put in a little code to see which control was responsible for consuming the event, like this:
So, with that done I fire up the game, hit my non-responsive movement key and check the console output:
What? That's a GUI control we use to show the player which races they've participated in and how they finished. It was causing my movement bug? Turns out that little critter is a GuiTextListCtrl, and those insidious little guys have a tendency to always want to be the "first responer." What's that? Basically, if a "first responder" has been set, it has the potential to consume any key input event being sent. Thus the Text Lists that were on our GUI, and not even curently visible were taking all of those lovely keystrokes that should be doing things like moving the player and saying "nah, I'll just keep this one for myself."
As with most ridiculously difficult to track down problems, this one had a simple solution. In the initialization of the PlayGui and put two lines:
Those two lines have the power to freeze the player completely in their tracks or free him. Life can be a real mysterious sometimes. The only conclusion I can draw from all of this is that GuiTextListCtrl wasn't really designed to be used as part of the PlayGui. I'm sure the whole "first responder" code works great when in a "menu" sort of environment, but on a Play GUI its kind of critical not to have it eat up those keystrokes. Sometimes the things that happen in a computer program just make me shake my head.
PS - Our project is a game about racing Chariots in the ancient world (Roman era). If you are interested in helping us, especially if you are a 3D artist, please contact me via email.
Our team had been happily moving along, making good progress developing our Chariot racing game when I got a bug report. Most of the keyboard controls for our lead World Builder (and general boss-lady) had suddenly stopped working. No one else was currently experiencing this problem (including myself). As with most keyboard-related bugs, I first told her to delete her custom controls, reset back to defaults, and re-map any custom ones again. She reported that the custom controls would work, but the instant she tried to re-map any one of them, they would all stop working. So, I gave it a shot on my machine. I deleted my custom config file (which was pretty much all defaults anyway) and loaded up the game. Nothing. I could not move anywhere even though all of my movement keys were the defaults and were working just a second ago. (ASIDE: Even now, knowing the cause of the problem, these symptoms still baffle me...)
So, clearly something had changed that any new control schemes created just didn't work. Bug replicated, so I moved on. One of the curious other symptoms of the problem was that the controls would work fine when the Mission Editor was activated, but not in normal "play" mode. That initially led me to believe there was something strange going on with the ActionMaps since the Mission Editor GUI does some pushing and popping when it activates or deactivates.
Now, we do have some involved code involving Action Maps, in that we are allowing the user to have different control schemes for different movement modes (on foot, riding a horse, driving a chariot). So, it seemed natural to me that something could be broken there. I explored that option for awhile with changing things and scouring our multi-action map code, but everything looked like it was working as it should. In the process I wrote a nifty (I think) little function. I wanted to make sure all of our calls to push andpop were happening correctly, but I couldn't find a easy way to tell exactly which action maps were on the stack at any given time. So, I whipped up a fuunction called dumpActionMapStack. Nothing particularly fancy about it, but it got the job done:
ConsoleFunction( dumpActionMapStack, void, 1, 1, "dumpActionMapStack()" )
{
SimSet* pActionMapSet = Sim::getActiveActionMapSet();
Con::printf("Action Map stack:");
for(int i = 0; i < pActionMapSet->size(); i++) {
SimObject *actionMap = pActionMapSet->at(i);
Con::printf("%s", actionMap->getName());
}
}
Anyway, the whole ActionMap avenue didn't seem to be going anywhere. Everything always seemed to be exactly as it should be. So, I started to think of other reasons why the controls worked when the Mission Editor was active. That led me to investigate the GUI. A knew a quick test could quickly confirm that theory. : I commented out all of everything but the GameTSCtrl. Lo and behold I could move, so it had to be something in the GUI! Now, for those of you who wouldn't know where to go from here let me show you. Inputs (like keystrokes) in Torque "enter" the system through the GameInterface::processInputEvent function, in main.cpp:
void DemoGame::processInputEvent(InputEvent *event)
{
if (!ActionMap::handleEventGlobal(event))
{
// Other input consumers here...
if (!(Canvas && Canvas->processInputEvent(event)))
ActionMap::handleEvent(event);
}
}
As you can see, there's a definite order to things. First, the Global Action Map gets a crack to see if it should handle the event. If not, the Canvas (the current GUI) sees if it needs to handle the event (by returning TRUE), and only if it does not handle the event does the current ActionMap(s) actually get to see the event. So, I knew something was happening in that Canvas::processInputEvent function. Now, at this point, I could've thrown a breakpoint in that function and ran in Debug mode, but I have found that trying to Debug input events using a breakpoint is rough stuff: you usually end up catching 50 events you don't want, so you start nailing that F5 key repeatedly and inevitable end up missing the input even you do want. So, I decided to just throw in some console output and see what I got.
I looked through all the possible places that the function could return TRUE (the event was processed/consumed) and put in a little code to see which control was responsible for consuming the event, like this:
if (mFirstResponder)
{
if(mFirstResponder->onKeyDown(mLastEvent)) {
Con::printf("Control %s consumed event via First Responder", mFirstResponder->getName());
return true;
}
}
So, with that done I fire up the game, hit my non-responsive movement key and check the console output:
Control HistoryRacesWonList consumed event via First Responder
What? That's a GUI control we use to show the player which races they've participated in and how they finished. It was causing my movement bug? Turns out that little critter is a GuiTextListCtrl, and those insidious little guys have a tendency to always want to be the "first responer." What's that? Basically, if a "first responder" has been set, it has the potential to consume any key input event being sent. Thus the Text Lists that were on our GUI, and not even curently visible were taking all of those lovely keystrokes that should be doing things like moving the player and saying "nah, I'll just keep this one for myself."
As with most ridiculously difficult to track down problems, this one had a simple solution. In the initialization of the PlayGui and put two lines:
HistoryPlayersList.makeFirstResponder(false);
HistoryRacesWonList.makeFirstResponder(false);
Those two lines have the power to freeze the player completely in their tracks or free him. Life can be a real mysterious sometimes. The only conclusion I can draw from all of this is that GuiTextListCtrl wasn't really designed to be used as part of the PlayGui. I'm sure the whole "first responder" code works great when in a "menu" sort of environment, but on a Play GUI its kind of critical not to have it eat up those keystrokes. Sometimes the things that happen in a computer program just make me shake my head.
PS - Our project is a game about racing Chariots in the ancient world (Roman era). If you are interested in helping us, especially if you are a 3D artist, please contact me via email.
Recent Blog Posts
| List: | 05/12/08 - Debugging an Action Map - possibly of very little interest 09/28/07 - Torque School: What is the value? 07/18/07 - Torque School Instructor 06/06/07 - Visions Update: The Importance of Cow Surfing 05/25/07 - Visions (retro-)Update: All about Terrain 05/03/07 - Visions: The MMORPG with the Bible |
|---|
Submit your own resources!| Phillip OShea (May 12, 2008 at 05:57 GMT) |
| Ross \"Boaz\" Leland (May 12, 2008 at 08:53 GMT) Resource Rating: 5 |
| Vernon Finch (May 12, 2008 at 11:27 GMT) Resource Rating: 5 |
| Sparkling (May 12, 2008 at 16:01 GMT) Resource Rating: 5 |
Thanks for sharing your findings with the community. The more people who have this knowledge, the better indie games will be!
And THANK YOU for fixing this irritating bug! So frustrating! (Yes, it was MY system that was bugging out!) It was driving me insane.
God bless you,
-Sparkling
www.chariotsgame.com
Edited on May 13, 2008 14:10 GMT
| Morrock (May 12, 2008 at 21:18 GMT) |
| David Montgomery-Blake (May 13, 2008 at 13:12 GMT) |
You must be a member and be logged in to either append comments or rate this resource.



5.0 out of 5


