onlinecodesimulator/pyodide-worker.js

198 lines
5.4 KiB
JavaScript

importScripts("https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js");
let sensorData = {}; // ✅ Store sensor values
let gameWorld = null;
async function initializePyodide() {
self.pyodide = await loadPyodide({
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/"
});
console.log("Pyodide loaded:", self.pyodide.version);
self.pyodide.globals.set("send_to_main", (event, data) => {
self.postMessage({ type: event, data: data });
});
// ✅ Expose sensor data to Python
self.pyodide.globals.set("get_sensor_data", (name) => {
if (gameWorld == null) {
return null;
}
//console.log(gameWorld.robots);
let robot = gameWorld.robots[0];
//console.log(robot);
let sensorArray = robot.sensors || []; // Assuming `sensors` is an array inside the robot object
sensorData = sensorArray.map(sensor => ({
"type": sensor.type, // Individual sensor's type
"angle": sensor.angle, // Individual sensor's angle
"distance": Math.round(sensor.distance * 100) / 100, // Individual sensor's distance
"hitpoint": sensor.hitpoint, // Whatever other attributes you need
"canSeeLine": sensor.hasLine
}));
//console.log(robot.sensors);
//console.log(sensorData["x"]);
sensorData = JSON.stringify(sensorData);
return sensorData;
});
self.pyodide.globals.set("get_robot_data", () => {
if (gameWorld == null) {
return null;
}
let robot = gameWorld.robots[0];
let robotData = {
"position": robot.body.position,
"angle": robot.body.angle,
"velocity": robot.body.velocity
};
robotData = JSON.stringify(robotData);
return robotData;
});
// ✅ Run Python initialization
await self.pyodide.runPythonAsync(`
import sys
import pyodide
import asyncio
import time
import json
import math
class RobotModule:
def get_sensor(self, name):
sensor_data = json.loads(get_sensor_data(name))
return sensor_data
def get_distance_left(self):
return self.get_sensors()[0]["distance"]
def get_distance_right(self):
return self.get_sensors()[1]["distance"]
def get_line_left(self):
return self.get_sensors()[2]["canSeeLine"]
def get_line_right(self):
return self.get_sensors()[3]["canSeeLine"]
def get_sensors(self):
return json.loads(get_sensor_data("sensors")) # Returns list of sensor dicts
def get_pos(self):
robot_data = json.loads(get_robot_data())
position = robot_data["position"]
return position
def get_x(self):
robot_data = json.loads(get_robot_data())
position = robot_data["position"]["x"]
return position
def get_y(self):
robot_data = json.loads(get_robot_data())
position = robot_data["position"]["y"]
return position
def get_velocity(self):
robot_data = json.loads(get_robot_data())
velocity = robot_data["velocity"]
return velocity
def get_velocity_magnitude(self):
velXY = self.get_velocity()
velX = velXY["x"]
velY = velXY["y"]
magnitude = math.sqrt(velX**2 + velY**2)
return magnitude
def move(self, speed):
if speed < -1:
speed = -1
elif speed > 1:
speed = 1
speed = speed/5000
send_to_main("move", speed)
def fire(self):
send_to_main("fire", None)
def turn(self, deg):
if deg < -1:
deg = -1
elif deg > 1:
deg = 1
deg = deg/150
send_to_main("turn", deg)
robot = RobotModule()
class ConsoleOutput:
def write(self, text):
if text.strip():
send_to_main("console", text)
def flush(self):
pass
sys.stdout = ConsoleOutput()
sys.stderr = ConsoleOutput()
sys.modules["robot"] = robot
# ✅ Override time.sleep() with an async version
_original_sleep = time.sleep # Backup original sleep
async def async_sleep(seconds):
await asyncio.sleep(seconds) # ✅ Allows JavaScript to process events while sleeping
time.sleep = async_sleep # ✅ Monkey-patch time.sleep()
`);
self.postMessage({ type: "ready" }); // ✅ Notify main thread that Pyodide is ready
}
initializePyodide();
// Add this function to trigger interrupts
function interruptExecution() {
interruptBuffer[0] = 2; // 2 is the magic number for KeyboardInterrupt
}
self.onmessage = async (event) => {
if (!self.pyodide) {
self.postMessage({ type: "error", message: "Pyodide not initialized yet." });
return;
}
if (event.data.type === "sensor_update") {
// ✅ Update sensor data
Object.assign(sensorData, event.data.data);
} else if (event.data.type === "game_state") {
gameWorld = event.data.state;
//console.log(event.data);
} else if (event.data.type === "execute") {
try {
let result = await self.pyodide.runPythonAsync(event.data.code);
if (result !== undefined && result !== null && result !== "") {
self.postMessage({ type: "console", data: result });
}
} catch (error) {
self.postMessage({ type: "error", message: error.toString() });
}
self.postMessage({ type: "execution_done" });
}
};