Passing variables from Parchment/i7 to JavaScript and back

I have very little familiarity with Parchment or Inform 7, but I have coded in Inform 6 extensively (I wrote a DM’s assistant in it for roleplaying back in the day, along with some unfinished IF projects).

I’m trying to figure out whether the final stage of a mixed media project I’ve been developing can be ported to Parchment/Inform 7. (Currently, the IF portion of the project has been roughed out in LambdaMOO, and I’m willing to finish it and release it in that form, if need be, but for reasons of scalability, it would be nice to have it in Inform as an option.)

The trouble is, in order for it to work as planned, there needs to be extensive crosstalk between the text adventure environment and the JavaScript on the surrounding page. I need to pass all sorts of variables (even very long strings) from inside the game, constructed out of the state of the game, from Parchment to my own website’s source code, and back. (Well, I could possibly make it work without passing any variables back into the game, but getting as much data as possible out of the game into the surrounding website in which it’s embedded, is essential to the concept and can’t be avoided.)

My questions:

(1) Are there any standard functions in either i7 or in Parchment to export the states of variables or objects out into the surrounding codebase?

(1a) If there are, are there strict limits to the size and types of variables that can be exported? Can I export a string of any size?

(1b) If there aren’t standard functions that allow this, is it possible to dig into the Parchment source code to create one and how difficult do you think this would be? The z-machine is a black box to me.

(2) If Parchment isn’t the way, is there another web-playable z-machine interpreter that will give me access to the internal state of the game in mid-play?

and

(3) Can any of this be done with Inform 6 instead of Inform 7? I’m willing to give i7 a chance and do plan to learn it, but as an old codemonkey my brain is quite used to formulas and braces and I’m more comfortable with that syntax than a more natural language approach. AppleScript, for example, drives me a bit nuts with its ambiguities. Also, I have custom libraries for Inform 6 that I’d rather not have to rewrite.

Thanks much for any insight you could provide, however small.

Paul.

I have plans for this kind of thing for Glulx/Quixe. No code yet, however.

Hacking Parchment (or Quixe) to do it wouldn’t be very difficult, but you’d have to spend some time learning how the interpreter works.

If you did it, it would be an I6-level hack. (Basically you’d add a new custom opcode.) Making it available in I7 would be a little extra work.

This thread:

groups.google.com/group/parchmen … f997702dd/

includes a kind of stop-gap measure (i.e., in lieu of an opcode or other vm-level solution). The code provided is javascript (Parchment side) and I7, but you could probably adapt the idea to I6–basically, it involves including tagged instructions in the strings printed by your game file. The javascript preparses all output and, when it finds the special instructions, strips them from the output and acts upon them to display images, etc.

I’m not sure if either the javascript or the I7 still work, as both Parchment and I7 have seen some revisions since then, but it’s probably at least worth a look.

–Erik

The way I did this for Guncho (when it was running on the Z-machine) was to repurpose the extended @save/@restore opcodes. The game read and wrote sections of RAM to specially named fake files, and the interpreter would use those requests to provide things like the system time.

Pro: didn’t need to extend the instruction set, didn’t need to modify the core of the interpreter (only the I/O section, which is a separate module in the terp I used), easily adapted to large data blocks like strings.

Con: the I6 code to make it work was somewhat baroque.

While I have plans for this, I haven’t written the code yet.

As Erik was saying the easiest way is to simply print the data you want and then to catch it before it and strip it out before printing it. If you’re using a customised version of Parchment it’s easy. The formal extension I’m planning will be a bit trickier as you’ll need to check for version 1.2 and then use @gestalt etc.

The time to strip out the special instructions is in onPrint() in zui.js. I suggest choosing some rare characters as delimiters, perhaps <# #> for example. Then you just use a regex to extra the data and cut it out.

Passing it back in is trickier. I guess you could do the same thing and put stuff in the input buffer, which you’d then have to cut out very early in the inform parser.

And yes you’ll need to use I6 for this. Even if you were using I7 you’d need to embed some I6.

A while back I modified Parchment to evaluate JavaScript that’s embedded in the game’s text. It’s a very quick hack with some drawbacks: Parchment wraps every word inside a span tag to preserve whitespace, so I had to remove those to get the JavaScript evaluated correctly, but that means you lose extra spaces if there are more than one in a row, which might break something in games that rely on spaces for formatting. Another drawback is that you can’t use the same story file for offline play as it would show the embedded scripts in a non-modified interpreter.

If you think this would be useful to you, I could send you the modifications I made (although it’s an out of date version of Parchment with possibly some bugs that have been later fixed.)

(Looks like ‘zhengwei’ is a spam account.)

So, thanks so much, guys/gals, this is way more and greater variety of solutions than I anticipated. I’ll try to address them all in one post.

Thanks for the tip! I think it’d be a lot easier to transcode from LambdaMOO to i6. But I’m thinking of writing an automatic transcoder to move code repeatedly between MOO & Inform – it can’t be perfect but it can save me grunt work. Just a little worried that targeting i6 might be targeting the past and maybe I’d feel forced to write a whole new i7 transcoder, later, to access modern features.

I get that. All I’d have to is learn to parse the contents of RAM as represented in a save file. It sounds though like I might end up having to repeatedly move more data than I actually need; And I’d be worried about performance of the save process, as compared to printing. Thanks, vape – I’ll keep it in reserve; great to know there are multiple possible solutions, it makes Inform that much more attractive for this purpose.

Thank you: it sounds interesting, but possibly a roundabout way to achieve what I want, which is not to enhance the display of Parchment in any way (I like that the way it is), but rather to change the contents of surrounding DIV tags. I bet your solution would work for that purpose but it doesn’t seem to me like the shortest route, considering I don’t need to change the appearance or click behaviour of anything within the actual text window.

Dannii’s and Erik’s suggestion and accompanying link sound optimal to me, especially once I realised that I can still have it affect any part of the web page rather then remaining inline. Thanks dudes, this idea looks like a go! Though I’m still not entirely sure whether I need to learn i7, first. But maybe I have time to learn it, anyway; as there is still lots of graphics work to be done, so I can postpone the conversion. Then I can make a more informed (NPI) decision, regarding i6/i7.

Did not even know that was possible — interesting. 8)

Thanks again everyone, this was an amazing set of responses that orients me pretty well for my purpose.

Paul.

Not quite - the extended save/restore opcodes save arbitrary blocks of memory with no processing. You specify the starting address and number of bytes you want to save, and the data is just copied instead of going through the whole differencing/compression process.

I’d forgotten about that functionality.

I wonder why I7 doesn’t use it to support file writing/reading in zcode.

You have to read and write the entire file at once – there’s no seek or append – so you’re limited to amounts of data that can fit into a single array in RAM. It could be used for some sort of file access functionality, but not the same functionality that’s supported on Glulx.

Perhaps your solution is faster and leaner than I thought. Seems like it might work pretty well. Right now the way it’s set up is that I can pass all the game state information I need in a single long string, which gets maintained by the game and then unpacked in JavaScript, so that is actually pretty well suited to just being plucked out of RAM.

I really doubt that it would be easier for sending data out of zcode, to use the print method it would literally just take print "<#", state, "#>"; and then a fairly simple regex to extract it.

Using @restore might however be simpler for returning data back to zcode…

I’ll consider both methods, I’m thinking after I have learned i7 and familiarised myself with the Parchment source. Having too many good solutions is not a problem I mind having! 8) Also, I just recalled: I definitely do need to feed data back into the game, because I need to load the ‘game state essentials’ of chapter 1, as represented in my packed long string, into chapter 2 of the story, when the next web page is loaded and a different blorb file is run in the next Parchment window. As you say, I might end up using both methods. Or one side might end up dictating the other. The most important thing for now is that I now know it’s doable, so I know what to put my time into learning, and it won’t be a dead-end tangent.

Paul.

In case any of the lovely people working on solutions to this have made progress, please keep us posted. I’m in the midst of a project that could benefit from this functionality, too, but I haven’t had much luck poking at the Parchment source myself. (Tustin’s solution on raif looked promising, but I couldn’t figure out where to put it.) Really any of these proposed solutions would be lovely if they would let me hand off a string from Parchment to Javascript. Would anyone with some working code mind posting it or sending it to me?

For my part, I’ll certainly post my hack, Aaron, when it’s in front of me, but as I mentioned I was more surveying the suitability of the territory for my project before stepping a toe back into Inform (which I’ve since done, with both feet) and likely won’t be tackling Parchment for some months yet. I have a lot of stuff to port from LambdaMOO before I can effectively test an Inform-based expression of my particular idea (which is pretty idiosyncratic) of how a text adventure could interoperate with a surrounding web page.

It would be cool to be able to help you out — I’m just not there, yet.

Paul.

Can you wait till next week? My thesis is due on Friday but after that I should be able to put aside some time on this. I’m assuming you’re happy to do it with I6 assembly? Do you want to be able to send data in the reverse as well? It also wouldn’t take much to add it to Quixe if you want to use Glulx instead.

In order of priority, the things I would personally like to see finished are:

Dannii’s thesis (and mine for that matter… wow, is it already almost November?!?)
Data from Parchment to Javascript. (For ideal laziness, preferably in form of code I can copy and paste into my I7 project file and code I can copy and paste into one of the parchment js files.)
Glulx support for the above (current project will probably fit in the z-machine)
Data from JavaScript to Parchment/Quixe (current project doesn’t need this, but quite probably the next one will)
The glorious return of the text adventure to the critical and commercial spotlight. Zarf is on the cover of Newsweek, Emily wins a Nobel Peace Prize, and vaporware gets a Porsche.

On the I6 assembly front, I’m fine with writing my own I7 wrappers and integrating them into my project and all that-- it’s just the writing the I6 assembly part myself I’d like to avoid.

What kind of data? Would it work if the zcode just sent a string of code to execute directly?

Yeah, that’d work just fine… then if I’m remembering my Javascript correctly you could just go like

function getTheThingieFromParchmentAndProcess() {
   var codeFromParchment = '';   
   // magic
   exec(codeFromParchment);
}

eval() rather than exec(), but yeah that’s what I’m planning to do!