Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IE-0012: Glk foundations #12

Merged
merged 4 commits into from
Jun 9, 2023
Merged

IE-0012: Glk foundations #12

merged 4 commits into from
Jun 9, 2023

Conversation

curiousdannii
Copy link
Collaborator

@curiousdannii curiousdannii commented Sep 23, 2022

  • Proposal: IE-0012
  • Authors: Dannii Willis
  • Language feature name: None
  • Status: In progress
  • Related proposals: None
  • Implementation: None

Summary

Incorporate code from the Glulx Entry Points and other extensions.

Motivation

The extension Glulx Entry Points by Emily Short has become an almost essential part of the Inform ecosystem. Almost, but not fully, and there are some extensions which are not compatible with it, most notably Unified Glulx Input by Andrew Plotkin. Many extensions depend on GEP, which means that you can't use them if you need to use UGI, even though nothing may directly conflict between those extensions and UGI itself.

It is proposed that most of GEP be incorporated into the core Inform project, that is, the parts of GEP that are foundational and universally applicable. The parts of GEP that provide just one possible way to implement a feature will be split off into new extensions. This should allow more mixing and matching between formerly GEP-based extensions and UGI-based extensions.

Contents of Glulx Entry Points

GEP includes the following features:

  1. A kind for Glk events
  2. Phrases for checking interpreter features (gestalts)
  3. Glk object recovery: to fix memory references after restarting/restoring
  4. Exposing a few I6 variables
  5. Event handling rulebook
  6. Command replacement support
  7. Miscellaneous:
    1. Redraw the status line
    2. Print the prompt

Components affected

  • Minor changes to the natural-language syntax (see point 4 above.)
  • Major changes to inbuild.
  • Change to inform7.
  • No change to inter.
  • No change to the Inter specification.
  • Change to runtime kits.
  • Changes to the Standard Rules and Basic Inform.
  • Minor changes to documentation.
  • No change to the GUI apps, when downloading or installing extensions.

Impact on existing projects

Glulx Entry Points was removed from Inform 10.1 to minimise disruption, but anyone who has installed it manually or any extensions that depend on it may have issues until those extensions are updated.

Proposal

It is proposed that Inform incorporate the following extensions (which were previously split out of Glulx Entry Points):

Glulx Definitions

The Glulx Definitions extension extracted out the phrases that checked for Glk interpreter features, and added Glulx phrases too. It also contains the definition of the glk event kind.

Glk Object Recovery

This extension replaces the convoluted multiple phase-based GGRecoverObjects/IdentifyGlkObject API that dates back to I6 with a simpler process that directly calls rulebooks for each phase of GGRecoverObjects. The logic is the same, it just does things in a more natural way for Inform 7.

Glk Events

This extension is an alternative to the original I6 HandleGlkEvent API inherited by I7 and GEP. One of the main flaws with that API is that the HandleGlkEvent hook is only called by the three standard input functions: VM_KeyChar, VM_KeyDelay, and VM_ReadKeyboard. If something else (usually an extension) ever calls glk_select by itself then the hook won't be called. So what this extension does instead is intercept calls to glk_select. This means the author (or extension authors) has a single place to handle all events, including converting events from one type to another, cancelling the event (convert it to a null event), etc.

GEP leftovers

  1. Command replacement support

Command replacement should be made into a new extension.

  1. Miscellaneous:
    1. Redraw the status line
    2. Print the prompt

These could be brought into the Standard Rules, or perhaps into Basic Screen Effects?

@curiousdannii
Copy link
Collaborator Author

curiousdannii commented Sep 23, 2022

This wasn't part of the original proposal, but I wonder if we should also add minimal support for Glk windows into GlkKit? Most extensions aren't currently multi-window aware, and so if you use Flexible Window, it can require more work to do things in other windows. For example, Flexible Windows basically reimplements most of Glulx Text Effects to make it multi-window aware.

GlkKit could include FW's "g-window" kind, and basic support for identifying the standard built-in windows in Glk Object Recovery. Other extensions could then depend on that kind to be ready for multiple windows, whether or not FW is used. If we did this then perhaps only including the basic "g-window" kind and "g-window types" should be in GlkKit. The various placement properties should be left for FW.

Glk Events would benefit then from being able to set "glk event window" to an actual g-window, rather than just "glk event window ref" to the ref number, requiring anyone writing event rules to find the corresponding g-window themselves.

Or alternatively we could just incorporate FW wholesale into GlkKit. It's a little bit opinionated, but it doesn't really have any competitors. I'm sure a lot of authors would appreciate that.

@curiousdannii
Copy link
Collaborator Author

I've started implementing this, and decided yes: rename everything! (Not quite. Just a lot of things.)

I am including at least a little bit of the windows system. We can decide to incorporate FW at a later time.

@curiousdannii
Copy link
Collaborator Author

curiousdannii commented Sep 25, 2022

Should GlkKit include phrases for requesting each of the types of events? They're mostly very simple phrases, so it might be better to include them here than have each extension make their own.

Could also have a glk_select wrapping "wait for X event" phrase too.

@curiousdannii
Copy link
Collaborator Author

So glk windows need a spawning relation. Previously I've reused the containment relation, but that means windows have to be containers. I've realised that I can use the incorporation relation, and they only need to be things. But the ideal would be for them to be objects. Unfortunately it doesn't seem like there's any existing relation that we could piggy back on, and using a new relation doesn't have working indirect verbs.

So this is what I've got currently:

A glk window is a kind of thing.
The verb to spawn implies the incorporation relation.
The verb to be ancestral to implies the enclosure relation.
The verb to be descended from implies the reversed enclosure relation.

Which allows for code like this:

The main window is a glk window.
The status window is a glk window.
The compass window is a glk window.
The main window spawns the status window.
The status window spawns the compass window.

When play begins:
	say "The main window spawns [the list of glk windows spawned by the main window][line break]";
	say "The main window is ancestral to [the list of glk windows descended from the main window][line break]";

With output

The main window spawns the status window
The main window is ancestral to the status window and the compass window

If I change to

Spawning relates one glk window (called the parent) to various glk windows.
The verb to spawn means the spawning relation.
The verb to be ancestral to implies the spawning relation.
The verb to be descended from implies the reversed spawning relation.

Then the output changes to

The main window spawns the status window
The main window is ancestral to the status window

I'm not sure if there is a way that would allow us to fix the relations just using I7 code, or whether it would require a new low level object-tree based relation to be defined in https://ganelson.github.io/inform/if-module/3-sr.html

@ganelson
Copy link
Owner

Incorporation is really not intended for this sort of thing.

It seems that what you're asking for is the ability to make one relation as the transitive closure of another one? You don't actually want the spawning relation for the meaning of ancestral or descended from, you want its closure. So e.g. something along these lines?

Indirect spawning relates a glk window (called W1) to a glk window (called W2) when W1 indirectly spawns W2.

To decide if (W1 - glk window) indirectly spawns (W2 - glk window):
while W2 is not W1:
if W2 is spawned by a glk window (called W3), now W2 is W3;
otherwise decide no;
decide yes.

(That could be done more efficiently by a kit function in Inter, of course, but it gives the idea.) And then define ancestral using the indirect spawning relation, not the spawning relation.

@curiousdannii
Copy link
Collaborator Author

curiousdannii commented Sep 27, 2022

Ah yep, that would work. I just hadn't seen that described in the docs, or I wasn't thinking well enough to put 2 and 2 together...

Zed and I have been discussing this a little bit on twitter: https://twitter.com/inform7tips/status/1574479165801103360
I've just realised one potential advantage of doing it through the object model: avoiding circular relationships. If we use a new object-tree based relation, am I right in thinking that it would prevent circular references, whereas if we used a non object-tree based relation we'd have to check for that ourselves? It's a minor thing, but could save some work.

It's not a question that needs to be answered now though. Even if GlkKit has a glk window kind, the spawning relationship doesn't need to be included, it can be left for Flexible Windows.

@2lindell
Copy link

2lindell commented Oct 6, 2022

Hi,
I just saw this after I posted on #10, but it seems this is a better place. There should be support for glk windows but not as "things" because they are not part of the model world. There needs to be another class for them - more like a value. Also, they should be directly associated with the dynamic objects which are created and there should be commands to open and close these windows directly and change their properties. I started working on this and have some code I could attach if your interested. I got stuck with opening windows above and below because it conflicts with up and down directions which are hard-wired into the compiler.

@curiousdannii
Copy link
Collaborator Author

Are you familiar with the Flexible Windows extension? The extension will be updated for compatibility with this kit once it has been implemented.

@2lindell
Copy link

2lindell commented Oct 6, 2022

I am familiar, but it does not use good natural language nor integrate well with the model world (it makes windows containers!) It's very complicated and you have to set so many parameters and keep track of everything. I was suggesting a more basic approach. For example:

A glk window is a kind of value.
The main window, status window, quote window, and side window are some glk windows.
A glk window has a number called window ID. The window ID of a glk window is always 0.

To set default window IDs:
	(-
		WriteGProperty((+ Kind ID of glk window +), (+ main window +), (+ window ID +), gg_mainwin);
		WriteGProperty((+ Kind ID of glk window +), (+ status window +), (+ window ID +), gg_statuswin);
		WriteGProperty((+ Kind ID of glk window +), (+ quote window +), (+ window ID +), gg_quotewin);
	-)

Definition: A glk window is inactive rather than active if its window ID is 0.

To close (win - a glk window):
	(- 
		glk_window_close(GProperty((+ Kind ID of glk window +), {win}, (+ window ID +)), 0);
		WriteGProperty((+ Kind ID of glk window +), {win}, (+ window ID +), 0);
	-)

To open a (typ - a window type) window to/-- the/-- (side - a directional method) of/the (pwin - an active glk window) called (win - an inactive glk window) with (fp - a sizing method) size of/-- (num - a number):
	(-
		WriteGProperty((+ Kind ID of glk window +), {win}, (+ window ID +), glk_window_open(GProperty((+ Kind ID of glk window +), {pwin}, (+ window ID +)), GProperty((+ Kind ID of method +), {side}, (+ reference number +)) | GProperty((+ Kind ID of method +), {fp}, (+ reference number +)), {num}, GProperty((+ Kind ID of window type +), {typ}, (+ reference number +)), 210));
		WriteGProperty((+ Kind ID of glk window +), {win}, (+ placement +), {side});
		WriteGProperty((+ Kind ID of glk window +), {win}, (+ sizing +), {fp});
		WriteGProperty((+ Kind ID of glk window +), {win}, (+ window type +), {typ});
	-)

@2lindell
Copy link

2lindell commented Oct 6, 2022

obviously, types and methods have to be defined as well. The goal would be to mirror existing system as simply as possible, but still open it up to inform7

@curiousdannii
Copy link
Collaborator Author

There are no doubt some improvements that could be made, but that has to be balanced with how much backwards compatibility we can maintain.

But that discussion is probably out of scope for this proposal, unless Graham decides he does want to incorporate FW wholesale into GlkKit.

@ganelson
Copy link
Owner

ganelson commented Oct 6, 2022

I don't feel that I know enough about the issues to judge this, but Flexible Windows strikes me as a bit beyond the scope of our aim of making a solid foundation for Glk-dependent code. I don't think the idea of GlkKit is to turn into a full-scale windowed environment - only to make it possible for somebody else to do that by building on top of it.

Behind all of these queries, I have the impression that what's being asked for is: the ability to have a kind of object which, though not a subkind of either thing or room, nevertheless allows itself to have containment trees which can be set up with assertions and whose well-foundedness is checked by the compiler. Is that right? Something so that you could say something like this -

An abstract container is a kind of object. A Glk window is a kind of abstract container. The status bar and the text portal are Glk windows. The status bar is in the text portal.

Is that what we're getting at here?

@curiousdannii
Copy link
Collaborator Author

curiousdannii commented Oct 6, 2022

Oh, I hadn't thought of the idea of a more general abstract kind, but yes that would make sense. Maybe just "abstract object" with support for a generic kind of containment, which could then be customised for each kind by using new verbs? ("The verb to spawn means the containment relation.")

The new "concept" kind (#10) might even make sense to be a sub-kind of abstract object? Similarly in a mystery game, authors could make a subkind for clues, a philosophy game could have theorems, and so on. While most of these uses of abstract objects probably would need many-to-many relations, there might be some (other than glk windows) which just need a one-to-many and could piggy-back on the containment relation by use of a verb alias.

@2lindell
Copy link

2lindell commented Oct 7, 2022

Maybe we could have "object out-of-world" like an action out-of-world. But that would not include "concepts" which are in-world.

@curiousdannii curiousdannii changed the title IE-0012: A new GlkKit IE-0012: Glk foundations Jun 9, 2023
@curiousdannii curiousdannii merged commit 99e3f0c into main Jun 9, 2023
@curiousdannii
Copy link
Collaborator Author

I've brought the proposal up to date (most notably that it won't be a kit any more), and merged it as we're beginning to implement it.

@curiousdannii curiousdannii deleted the ie-0012-glkkit branch July 19, 2023 22:29
@curiousdannii curiousdannii added the formal-proposal A formal proposal that has been accepted for consideration by the core Inform team label Jul 20, 2023
curiousdannii added a commit that referenced this pull request Jul 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formal-proposal A formal proposal that has been accepted for consideration by the core Inform team
Projects
None yet
3 participants