Random silliness: Quest's "invoke" in JS

mrangel
11 Dec 2020, 17:40

Random I know.
This was an issue back with QuestJS, the one that tried to convert Quest 5.x games to javascript code. They had a problem that a function's parameters weren't known when it was created. Because Quest's invoke takes a script parameter, and a dictionary of parameters, and the parameter names come from the dictionary.

It randomly popped into my head how you could do this lately. So I present: a javascript function that messes with another javascript function.

function Quest_invoke (script, params) {
  eval("(" + script.toString().replace(/^\s*(function\s*.*?\()/, "$1"+Object.keys(params).join(",")) + ")").apply(null, Object.values(params));
}

function Quest_do (object, scriptname, params) {
  eval("(" + object[scriptname].toString().replace(/^\s*(function\s*.*?\()/, "$1"+Object.keys(params).join(",")) + ")").apply(object, Object.values(params));
}

This is probably useless now; but if someone wants to revive the idea of making a new engine to work with the old files it could be useful.


Richard Headkid
11 Dec 2020, 17:47

By default, you can't do eval due to the security settings in Quest 6.

https://github.com/ThePix/QuestJS/wiki/Code-guidelines#content-security-policy


mrangel
11 Dec 2020, 19:09

Sorry. You can delete this post if you want to keep irrelevant stuff off the forum.

But if you want to do this without eval, you should be able to use some terrible voodoo code like:

function Quest_invoke (script, params) {
  var stash = Object.keys(params);
  stash.push(script.toString().replace(/^.*?\{(.*)\}.*?$/s, "$1"));
  stash.unshift(undefined);
  var modified_script = new (Function.prototype.bind.apply(Function, stash));
  modified_script.apply(null, Object.values(params));
}

(more proof that I can't let go of an unsolved problem even when it's years past being relevant)

For reference:

new (Function.prototype.bind.apply(SomeClassName, some_array));

is equivalent to:

new SomeClassName(some_array[1], some_array[2], some_array[3] …)

I'm using that with the Function constructor, because I have an array of parameter names (from Object.keys(params)). So I can then call the newly created function by using its apply method to supply an array of parameter values rather than the parameters individually.


Richard Headkid
11 Dec 2020, 19:55

Curses!

Uncaught EvalError: call to Function() blocked by CSP
    Quest_invoke debugger eval code:4
    <anonymous> debugger eval code:12
debugger eval code:4:25

Richard Headkid
11 Dec 2020, 19:56

I can't let go of an unsolved problem even when it's years past being relevant

Neither can I, good sir. Neither can I.

Unsolved problems haunt me.


mrangel
11 Dec 2020, 20:23

I wasn't sure if the Function constructor would count as an eval or not; guess I'm out of luck there.


Richard Headkid
11 Dec 2020, 20:55

It was a valiant effort.

I would have used it, just to prove it could be done.