Closed Noiredd closed 3 years ago
Sketch of the solution.
Addons are separate .ks
files placed in a separate folder within the repository (e.g. kOS\addons
). Each addon implements one or more functions as delegates, requesting PEGAS to register them internally, associating them with a given point when they should be called. PEGAS, in its main module, calls each of the registered delegates at their respective moments. No parameters are exchanged, instead the delegates can access all of the global variables and functions.
pegas_addons.ks
:
SET addonHookRegistry TO LEXICON(
"init", LIST(), // call these when the system is ready, just before the GUI is first drawn
"passivePre", LIST(), // call these at the beginning of the passive guidance loop
"passivePost", LIST(), // similarly, at the end of the passive loop
"activeInit", LIST(), // call these on the transition from passive to active guidance
"activePre", LIST(), // at the beginning of the active guidance loop
"activePost", LIST(), // at the end of the loop
"final", LIST() // right before exiting the script
).
FUNCTION register_hook {
// store a given delegate in the registry
DECLARE PARAMETER hook. // delegate to be called, supplied by addon
DECLARE PARAMETER mode. // string identyfying when to call the hook (registry key)
addonHookRegistry[mode]:ADD(hook).
}
FUNCTION call_hooks {
DECLARE PARAMETER mode.
FOR fun IN addonHookRegistry[mode] {
fun:CALL().
}
}
FUNCTION scan_addons {
// look at all the script files in the addons directory and execute them
LOCAL addonDir IS CORE:CURRENTVOLUME:OPEN("addons"). // is this right?
LOCAL addonItems IS addonDir:LEXICON().
FOR itemName IN addonItems:KEYS() {
// check if a ".ks" file, ignore if not
// otherwise execute the addon script:
RUNPATH("addons/" + itemName).
}
}
In pegas.ks
add lines like call_hooks("init").
in the designated points, with respective arguments.
Now, each addon would have a following structure:
FUNCTION addon_function_that_does_something {
// user code goes here
// they should have the ability to access all PEGAS globals, modify them etc
// as well as call all PEGAS functions
// the only restriction is that this should not expect any argument
// neither should it return anything, as the output will be discarded anyway
// also, large functions should probably be avoided as in-loop hooks
}
// however, nothing happens until this function is registered:
register_hook(addon_function_that_does_something@, "init").
// this tells PEGAS to run the above function at initialization
Added in c6874bc
Discussion on #31 raised an interesting idea of creating a system for custom add-ons, i.e. modules that could be added to PEGAS to enhance its capabilities without modifying its own code. Let's discuss whether such a system could be useful, how practical could be its implementation without a thorough rewrite of the core, and how could it be implemented.
I'm imagining something akin to how Python's modules work: you can put
.py
files in a directory and then load them by name (import my_module
) or useimportlib
to do all kinds of magic and e.g. automatically import specific objects/classes/functions from all modules in a given directory (example). If this could even be done in kOS, the system could work like this on the initialization side:addons
directory on the PEGAS volume,RUN
each file in the directory,register_module
function exposed by PEGAS' addon interface,register_module
receives a delegate from the calling addon and adds it to some internal registry.This way adding a new add-on would be as simple as putting its
.ks
file into the addons directory - no modification of any core module neccessary. What I definitely wouldn't want is to need to add a line topegas.ks
every time I want to integrate a new add-on.Then during PEGAS' runtime, the subsystem would periodically call all of the registered addon delegates, which are neccessarily lightweight so that each loop over addons doesn't take forever. These functions could check conditions and call heavier handling functions if needed (interrupt-style), or even schedule their execution (event-like). Such a handler could basically hack anything - all of PEGAS is built on global variables and kOS does not limit the scope of such vars (as far as I remember) so just knowing their names should be enough to monkeypatch anything the user would want.
However, my kerboscript is quite rusty by now so I don't know how practical this is. Maybe it cannot be done this way? Let's talk about this. And let's talk about what potential uses this system might have - it's important to keep in mind the practical problem that we want this to solve.