#include "ScriptEngine.h" #include "Game.h" #include #include #include namespace py = pybind11; // Static pointer used by the embedded module (set before interpreter starts). static ZL::Game* s_game = nullptr; // The embedded module must be defined at file scope before the interpreter // is started. It exposes a minimal surface: one function per scripting command. PYBIND11_EMBEDDED_MODULE(game_api, m) { m.doc() = "Game scripting API"; // npc_walk_to(index, x, y, z, on_arrived=None) // Tells the NPC at `index` to walk to (x,y,z). // on_arrived is an optional Python callable invoked once when the NPC arrives. // It can call npc_walk_to again (or anything else) to chain behaviour. m.def("npc_walk_to", [](int index, float x, float y, float z, py::object on_arrived) { if (!s_game) { std::cerr << "[script] game_api.npc_walk_to: engine not ready\n"; return; } auto& npcs = s_game->npcs; if (index < 0 || index >= static_cast(npcs.size())) { std::cerr << "[script] game_api.npc_walk_to: index " << index << " out of range (0.." << npcs.size() - 1 << ")\n"; return; } std::function cb; if (!on_arrived.is_none()) { cb = [on_arrived]() { try { on_arrived(); } catch (const py::error_already_set& e) { std::cerr << "[script] on_arrived callback error:\n" << e.what() << "\n"; } }; } npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb)); }, py::arg("index"), py::arg("x"), py::arg("y"), py::arg("z"), py::arg("on_arrived") = py::none(), "Command NPC[index] to walk to (x,y,z). on_arrived is called when the NPC arrives."); } namespace ZL { ScriptEngine::ScriptEngine() = default; ScriptEngine::~ScriptEngine() = default; void ScriptEngine::init(Game* game) { s_game = game; interpreter = std::make_unique(); runScript("resources/start.py"); } void ScriptEngine::runScript(const std::string& path) { std::ifstream file(path); if (!file.is_open()) { std::cerr << "[script] Could not open script: " << path << "\n"; return; } std::string source((std::istreambuf_iterator(file)), std::istreambuf_iterator()); try { py::exec(source); } catch (const py::error_already_set& e) { std::cerr << "[script] Error in " << path << ":\n" << e.what() << "\n"; } } } // namespace ZL