76 lines
2.6 KiB
C++
76 lines
2.6 KiB
C++
#include "ScriptEngine.h"
|
|
#include "Game.h"
|
|
#include <pybind11/embed.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
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<int>(npcs.size())) {
|
|
std::cerr << "[script] game_api.npc_walk_to: index " << index
|
|
<< " out of range (0.." << npcs.size() - 1 << ")\n";
|
|
return;
|
|
}
|
|
std::function<void()> 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<py::scoped_interpreter>();
|
|
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<char>(file)),
|
|
std::istreambuf_iterator<char>());
|
|
try {
|
|
py::exec(source);
|
|
} catch (const py::error_already_set& e) {
|
|
std::cerr << "[script] Error in " << path << ":\n" << e.what() << "\n";
|
|
}
|
|
}
|
|
|
|
} // namespace ZL
|