Discourse-Frotz

You can send in that SAVE input and then (immediately) send a specialinput containing the filename. However, this will never be reliable. You don’t know how the game will respond to the input text SAVE. The game could have disabled SAVE, it could be in Russian, it could be in the middle of keystroke input.

“The VM initiates save” means a setup where the interpreter runs a turn, gets back to the point of awaiting input (glk_select), and – as part of that code path – saves its state somewhere. This can be made to work reliably, but it requires extra integration work between the interpreter and VM, as Dannii said.

(I apologize for leading you down a bit of a garden path by recommending RemGlk! Autosave really is a big headache.)

2 Likes

The concept here is great. I love how the responses are in a useful format that can be processed easily without a load of rubbish string processing.

It has the potential to vastly improve upon the Dumb Frotz implementation.

However, until there’s a reliable way to remotely load and save state quickly and easily at the beginning and end of a move whilst having discretion over the filename I think this will be too limited for this use case.

What is the technical blocker for implementing a simple single command to explicitly save or load state to a specified path and filename in Remglk in one step? ie include the filepath with the save or load command in the json passed to execute this? Why do we need more than a single command to achieve this?

Is it simply that the work to implement that hasn’t been done yet or that there is some architectural impediment that prevents that feature being added?

I’d love to be able to spend the time to learn the library and PR to facilitate that but I don’t think I will have the bandwidth to do that for some time. It would be enough to cover the Discourse plugin side which will be significant in itself.

For now, I suspect, the Frotz implementation will have to suffice. Delighted to revisit if the situation changes.

1 Like

The problem is that RemGlk doesn’t know that passing “SAVE” in as line input will trigger a glk_fileref_create_by_prompt() call. Ultimately, only the game knows what player input will start the save process.

You need a completely separate path to trigger an out-of-band save. It shouldn’t be triggered by an input at all – you want it to run every turn, so it should be automatic! However, for technical reasons, it has to do extra work beyond the currently-implemented interpreter save mechanism.

So it’s easier in some ways and harder in other ways.

I’ve set this up in Quixe and in the iOS Glk library, because those are the interpreters that I’ve reworked seriously since 2010-ish. RemGlk is behind the times.

Since we’re all stuck at home for a while, I might have time to look at RemGlk this week.

2 Likes

I started a Rust port of RemGlk, figuring it would be easier to add autosaving etc because of its built in JSON serialising functions. But I didn’t get very far, learning new languages is tricky! If you do get to add it to RemGlk Zarf that would be great though.

I will also try to add it to my glkote-term. That will be much less work because most of it is already done, I just have to expose it.

1 Like

I’d be glad to entertain additions to Dumb Frotz to help with what you’re trying to do. Would a save after ever move do? The saves already are named numerically and increase after every save. This coupled with the fact you can restrict an instance of Frotz to a specific directory you can therefore handle multiple players at once. Each player can have a directory where saves, transcripts, and so on are stored and then deleted when the desire or need arises. When someone makes a move, start Dumb Frotz in restricted mode on that user’s directory, restore the latest save, and you’re good. There are probably some minor nits to this, like removing the ability of the player to name their saves and shove this onto the bot wrapper, but on the whole, I think this is doable without much hassle.

The invocation would look something like this:

$latest_save = get_latest_save($playerdir)
run (shell dfrotz -R $playerdir -L $latest_save $game`)
...

plus an option to turn on autosave, whatever that turns out to be. The -R option restricts all reads and writes from the Z-machine to that directory. The -L option tells the Z-machine to immediately load the provided save file after starting the game.

1 Like

Hi David! State management is already good in Frotz and suitable for the way you need to handle move ‘transactions’ in a single call and response.

The only challenge is that it prints to the same console so you have to ignore those characters in the response and hide them from the user as this housekeeping is irrelevant to the users experience and supposed to be seamless. They don’t need to know the system is loading or saving.

If you could have a mode where you could load a particular file and with a switch request it was saved at the end of the move to the same file whilst hiding all the housekeeping text that might suffice for improving the state persistence.

Remember we are starting cold on every move:

We want to:

  1. Load the latest state from gamefilename_userid.sav (Which maintains a unique file per game and userid)
  2. Send the move
  3. Save the state.
  4. Print the response to the Discourse bots post without any housekeeping info

Step 1 and 4 currently involves masking by ignoring a set number of lines for the status updates of loading and saving. It would be good to have a mode to defeat those outputs (useful for many circumstances but not when you want to suspend disbelief and certainly not when you are repeating both of those steps on every move)

The other way in which things might be improved is in formatting of the story output.

  • Having a “Jason Frotz” (Dumb’s Bro?) that returns the response in formatted data in Json format similar to Remglk or
  • “Mark Frotz” that sends it in Markdown or
  • “Bob Frotz” that uses BBCode

would be interesting options. A version could send the story in BBCode would be the ultimate for a Discourse implementation. Not sure BBCode has a baseline standard though unlike Markdown?

I would propose “Henrietta (HTML) Frotz” but HTML may be going further than you need and might introduce security concerns.

Perhaps there are more options already available to handle formatting that I’m not aware of?

It would be good to have an option that like Remglk focussed on a computer end point rather than a human but dealing with inline control chars is also an option. Perhaps Dumb Frotz already has the ability to push out formatting codes?

I don’t mind doing some of the formatting work at my end so long as I can rely on consistency of input regime across all games as much as possible.

These two things seem fairly easy. The second one already has an avenue for support. The -f option is for picking a scheme for marking up the output. It currently has ansi and irc modes. Adding more is very straightforward.

1 Like

So I can look at what is currently possible with existing formatting support but a nice first improvement on the Frotz side would be to provide option on command line to accept a load file and a next move string and return just the story text response whilst silently saving state back to the specified file aka ‘autosave’

The command then won’t vary time after time except for the user move text.

There will be no need to send any additional characters to perform load or save as that will be taken care of by the command line options.

And the silent option would hide the housekeeping status reporting.

In this mode the command can return to the command prompt as there is no need for session continuity beyond that provided by the save file. That might be behaviour also controlled by a switch.

So boiling this down:

  1. provide a switch to load the specified file and save it back immediately after the first move
  2. provide a switch to provide the first move ‘text’
  3. provide a switch to perform the load and save silently so it’s not included in any response
  4. provide switch to cause the command to end after one move if not already implemented by 1.

That should be fairly easy to unit test too?

I think only one new switch would be required to run Dumb Frotz like this. Testing would require a dummy wrapper script to present output and collect input at a terminal.

1 Like

That would clean up the code tremendously and could be leveraged by the restful-Frotz project too.

I will try to look at formatting over the next few days.

It isn’t very hard. Here is the merge request for the ansi mode: https://gitlab.com/DavidGriffith/frotz/-/merge_requests/148/diffs

2 Likes

Thanks. This may not need to be touched. I’m looking at processing ansi ascii text in the plugin.

OK

I’ve pushed some improvements to a feature branch:

This does away with the silly suppression settings, introduces translation to BBCode to support formatting and colour, leverages the Dumb Frotz command line options better, obviates the need to write to a text stream and squashes a vulnerability.

This branch requires the official Discourse BBCode plugin to be installed.

I’m still experimenting with it.

I’ll probably merge after some significant trials.

2 Likes

Did you end up needing to alter Dumb Frotz itself?

Specifying an autosave, silencing the housekeeping, providing a first move and returning to the command prompt after one move all from command line would still be great.

I’ve only tested so far on two games and what I fear is supporting more variety. The way I’m suppressing the housekeeping feedback whilst not inadvertently deleting the content may get more tricky.

Doing as much of the housekeeping from the command line instead of the within a session avoids unnecessary output and streaming commands. Lack of streaming improves security too.

I’ll post an example.

Also FYI converting ANSI to BBCode isn’t as trivial as you might think but so far so good.

ANSI, not ASCII. :wink:

Actually is that true? ANSI should be a standard, right? But the codes coming from the terminal are actually for lower bit rate screens and a smaller set of colours.

I tried a Ruby library called ansi to handle the codes but it kept falling over. On inspection this because neither the output nor the library followed fully the same convention. Hence why I’m referring to the terminal output as something different. Is the terminal really true ANSI?

As a result of this I’m having to convert those codes to the higher bit version and making a judgement eg turning grey into white.

ASCII has some control characters but it’s extremely unlikely any of them are being used other than \n or \r, and ^[ or ESC. ANSI escape codes start with ^[. There is a formal standard and most of it is probably supported by most terminals, though some have limitations.

1 Like

Ok we can call it ANSI but it’s not a very good standard imho. The codes from terminal are not universal it appears and doesn’t seem to be much standard software library support to upscale. That said the terminal makers are clearly coping. Are they reinventing the wheel every time?

Worse BBCode isn’t really a standard at all.

We’ll have to see how well we can achieve a generalised scheme that works nicely across a broad range of games.

You see here’s another problem. I’m interpreting \e

A quote from your link:

“There are several encoding schemes, and unfortunately most terminals mix sequences from different schemes, so host software has to be able to deal with input sequences using any scheme”

Not the best.