@hasundo, @discardundo opcodes in Glulx

So, back in, what was in, 2015, I proposed a couple of new Glulx opcodes to make UNDO handling just a little bit cleaner.

Forum thread: Adding a @discardundo opcode

The opcodes look like this:

@hasundo S1

Test whether a VM state is available in temporary storage. S1 is set to 0 if a state is available, 1 if not. If this returns 0, then @restoreundo is expected to succeed.

@discardundo

Discard a VM state (the most recently saved) from temporary storage. If none is available, this does nothing.

The simplest way to make use of this would be to add a @discardundo opcode to the “I didn’t recognize that command” parser error. Then muffed command inputs wouldn’t take up an UNDO slot.

(You’d do a @gestalt feature test before calling the opcode, so it wouldn’t crash on older interpreters. They just wouldn’t get the benefit. They’d behave the way all games do today, where unrecognized verbs do take an UNDO slot.)

You could do this for other parser errors as well. Although this might start to cause problems for games that convert parser errors into real game actions. (Some games certainly do this.)

You could go deeper with this – make UNDO less of a hack in the whole parser loop. But I’d definitely want to start with a conservative change.

Anyhow, the first step is to get the opcodes into interpreters (and the I6 compiler). It turns out I did the implementation back in 2015, and then… um… never got around to pushing it out? I really can’t remember what the stumbling block was.

If you remember – too late! I’ve already merged the change into the Glulxe and Quixe interpreter source. And posted pull requests for Inform 6 and the Git interpreter.

Once those are in circulation, I’ll figure out an I7 parser patch (the “didn’t recognize that command” change).

3 Likes

Note that the double-precision math feature is also in progress: Double-precision math in Glulx

hmm… I’m basing this on generic .asm programming & debugging, but:
if the undo is fully handled like a multiple stacks, perhaps this can really help the I7 ide’s skein; I feel that is feasible adding a “stack pointer” increased and/or decreased by restore/discard undo and a “stack register” pointing to the bottom of the stack, this can allow both horizontal and vertical traversing of the skein; the main issue is having potentially multiple undo stacks, needed only during debugging.

it’s a good idea or an absurdity ?

Best regards from Italy,
dott. Piergiorgio.

The IDE’s Skein feature really is a different use case. It has to store an unlimited number of states, and it has to be able to store them in the project on disk (not just in memory).

It’s risky anyway to mix up gameplay features with testing features. Consider the original suggestion above. If a parser error throws away the undo state, and the Skein relies on undo states, then the Skein wouldn’t be able to test parser errors! That would be a problem.

Got the point, sorry for my stupid suggestion…

Best regards from Italy,
dott. Piergiorgio.

I have to ask, would a simpler fix not be to only @saveundo right before delegating to the action-handling routines? This seems like it would ensure that only valid actions (i.e. ones that the parser understood well enough for the world model to try to process) take up space in the undo stack. It’s been a while since I tried to mess with the Inform parser, but I thought the last stage of parsing was looking up the returned action value (##Take or whatever) in a table to figure out which routines to call.

I’m assuming there’s a reason why this wouldn’t work (or would be a lot more complicated than it sounds), but I’m curious what it is.

Ah, I see it’s mentioned in the other thread:

One way to fix this would be to delay saving an undo point until the parser has parsed out a valid command. That’s okay in theory but it’s risky. The parser does a lot of work, potentially extended by the game author. We don’t want to run that work before the undo point, because it could affect future commands. Then UNDO becomes unreliable and players become sad. It’s cleanest to save the undo point as soon as possible after the input event.

I was thinking a jump back to before taking input would ensure all the parsing buffers and registers get overwritten (so what’s been left in them doesn’t matter), but of course the author could have done arbitrary calculations during the parsing process that we can’t account for.

Yeah. There’s quite a few forum posts where authors are like “So, this is gross, but I put a whole dialogue system in the parser error handler or the ‘mistake’ handler or somewhere, you know, it works though.”

1 Like