joo
joo9mo ago

'Spawn' multiple promises from the same module

I'm trying to use Deno for scripted npcs in a game, the main issue that the npc has to await user action so I've used a mpsc Channel for this with an async fn op which works fine. However since the npcs exists on the server side I need to be able to call the same npc multiple times on the same runtime. My current test script looks like this
// actor would be the current actor object
async function npc_action_1000(actor) {
Deno.core.print("Started script for player " + actor + "\n");
let action = await Deno.core.ops.op_wait_action(actor);
if(action === "0") {
Deno.core.print("First selection\n");
} else {
Deno.core.print("Other selection\n");
}
}

globalThis.npc_action_1000 = npc_action_1000;
// actor would be the current actor object
async function npc_action_1000(actor) {
Deno.core.print("Started script for player " + actor + "\n");
let action = await Deno.core.ops.op_wait_action(actor);
if(action === "0") {
Deno.core.print("First selection\n");
} else {
Deno.core.print("Other selection\n");
}
}

globalThis.npc_action_1000 = npc_action_1000;
The problem I'm facing right now, I'd like to load the module once, remove the await in the end and then spawn multiple npc_actions while the event loop is running. So far I was only able to get a Local reference to the function, but when I call It I can no longer run the ev loop because the scope references the runtime. What would be the best way to approach that?
3 Replies
Deno AI Helper
Deno AI Helper9mo ago
Based on the documentation, it seems like you might want to consider using Workers in Deno. Workers in Deno are similar to Web Workers in the browser and can be used to run code on multiple threads. Each instance of a Worker is run on a separate thread, dedicated only to that worker. This could be useful in your case where you want to run multiple instances of npc_action concurrently. Here's a simplified example of how you might use Workers:
// main.js
const workerUrl = new URL("./npc_action_worker.js", import.meta.url);
const worker = new Worker(workerUrl, { type: "module" });

// npc_action_worker.js
self.onmessage = async (evt) => {
let action = await Deno.core.ops.op_wait_action();
if(action === 0) {
Deno.core.print("First selection");
} else {
Deno.core.print("Other selection");
}
};
// main.js
const workerUrl = new URL("./npc_action_worker.js", import.meta.url);
const worker = new Worker(workerUrl, { type: "module" });

// npc_action_worker.js
self.onmessage = async (evt) => {
let action = await Deno.core.ops.op_wait_action();
if(action === 0) {
Deno.core.print("First selection");
} else {
Deno.core.print("Other selection");
}
};
In this example, npc_action_worker.js is a separate module that contains your npc_action function. This module is loaded as a Worker in main.js. You can create multiple Workers by creating multiple instances of Worker. Please note that this is a simplified example and you might need to adjust it to fit your needs. For example, you might need to handle communication between the main thread and the Workers using postMessage and onmessage. Also, please note that this information is not explicitly stated in the documentation, so you might want to experiment with this approach and see if it works for your use case.
joo
joo9mo ago
I've tried to make a small rust example of what I'm trying to do: https://gist.github.com/jon-zu/68fe5f5586d7ede4abf09cd9e6bb20e5 Would be nice to get some feedback if that's the right way to do It or If I should do It differently? I'm also not sure If I should make an extra isolate per execution however I don't know what are the implications for that especially in terms of overhead. Also I'm not sure if the event-loop is cancel-safe, from what I saw It's a simple poll function so It should be right?
Gist
runtime.rs
GitHub Gist: instantly share code, notes, and snippets.
joo
joo9mo ago
Also some further things I'd like to improve on would be: * Make the actor an actual object which stores the receiver, so I avoid having all that Rc/RefCell stuff * Being able to terminate a running task * Being able to handle errors per task * It would be nice If I could load all functions exported by the module during init and call the v8::Function directely