importScripts("https://cdn.jsdelivr.net/pyodide/v0.23.4/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.23.4/full/" }); 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": sensor.distance, // Individual sensor's distance "hitpoint": sensor.hitpoint // Whatever other attributes you need })); //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_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/250 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(); 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" }); } };