April 5, 2008

expert at making things more complicated

Oh Me Oh My.

For whatever reason, Wherigo is designed in a way that perfectly maps to J2ME's gui handling. Commands, actions, dialog boxes, it all looks like somebody designed it to work in a midlet.

Except for one thing.

To quote Wherigo Advanced Concepts on the subject of MessageBoxes and Dialogs:
The Wherigo Player automatically cancels any message box that is buried by another user interface element. This means that the message box will not remain on the screen even after all other UI elements have been closed. However, the message box script (if one exists) will still execute. The author can override this by creating a condition to specify what should happen if the 'Cancel' button is pressed. These conditions will work regardless of whether the player intentionally presses 'Cancel' or the message box is automatically canceled by the application.
Funny, I thought, this is going to be rather tough. You have to keep a return value from the message box, but anything can close it anytime. Hello and welcome aboard, race conditions. And what's even better, Lua VM is thread-unsafe. And it would be dumb to lock the whole VM for as long as the dialog is on, because that can be quite a long time.

On the other hand, it's quite a dumb idea to automatically cancel the dialogs when another comes. What if the user doesn't have time to read it? But ... who am I to judge :P

So let's restate the problem.
  1. Midlet UI works in non-blocking, fire-and-forget mode. Which is basically a good thing for an UI to do, but...
  2. ...we need to keep return values. Therefore we must block on the dialog.
  3. Anything can close the dialog anytime. I.e., another thread must tell the first one to continue.
  4. Lua VM is thread-unsafe, therefore the two must somehow arrange locking. Plus locking of the dialog threads, because a third dialog can come at any time and kill the two.
I devised a clever scheme, where the VM is locked by a mutex (did you know Java doesn't have mutexes?), but the dialog unlocks it, and after it's canceled, reacquires the lock. Plus some regular java synchronization stuff to display the dialog properly, make it block etcetera.

Strangely enough, it worked, and it worked really well.

Too well, actually.

I apparently missed some of the Advanced Concepts.
in Wherigo, a message box does not pause the cartridge. Instead, the game continues to run while the message box is still displayed on the screen.
Just like midlets do. Fire-and-forget, anyone?

It actually does work like that. Dialog is put on screen and the script continues happily on its way. Return values? No sire. There are callbacks instead. Who could have thought?
(anyone who would try it in the builder ... oh well)
In fact, the very Wherigo Level Two cartridge I use for testing is relying on this "feature". Instead of if/elseif conditional blocks, it just displays messages over one another, stopping at the right time.
I was very surprised that OpenWIG showed more messages than the emulator. I even thought that it's a bug in the emulator, or some kind of unspecified if/elseif handling - which would be very, very bad.

Nope, none of that. Once again, I made the problem more difficult for me. If I didn't want to do it "properly", it would have been easier, and correct at the same time. Folks at GroundSpeak apparently don't do things the "proper" way, but the "practical" (easy for the programmer) way. I'll have to get used to it.

But auto canceling the dialogs? Come on. That is dumb. Really.

No comments: