Working on web, change python to lua

This commit is contained in:
Vladislav Khorev committed 2026-04-04 14:29:20 +03:00
1 parent 90e2a369f4
commit 178f69967b
14 files changed
+327 -162

No files matched your search

+43 -57
View File
@@ -1,74 +1,60 @@
#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.");
}
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
namespace ZL {
struct ScriptEngine::Impl {
sol::state lua;
};
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");
impl = std::make_unique<Impl>();
sol::state& lua = impl->lua;
lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::table);
auto api = lua.create_named_table("game_api");
// npc_walk_to(index, x, y, z [, on_arrived])
// on_arrived is an optional Lua function called when the NPC reaches the target.
// It can call npc_walk_to again (or anything else) to chain behaviour.
api.set_function("npc_walk_to",
[game](int index, float x, float y, float z, sol::object on_arrived) {
auto& npcs = game->npcs;
if (index < 0 || index >= static_cast<int>(npcs.size())) {
std::cerr << "[script] npc_walk_to: index " << index
<< " out of range (0.." << npcs.size() - 1 << ")\n";
return;
}
std::function<void()> cb;
if (on_arrived.is<sol::protected_function>()) {
sol::protected_function fn = on_arrived.as<sol::protected_function>();
cb = [fn]() mutable {
auto result = fn();
if (!result.valid()) {
sol::error err = result;
std::cerr << "[script] on_arrived error: " << err.what() << "\n";
}
};
}
npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb));
});
runScript("resources/start.lua");
}
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";
auto result = impl->lua.safe_script_file(path, sol::script_pass_on_error);
if (!result.valid()) {
sol::error err = result;
std::cerr << "[script] Error in " << path << ": " << err.what() << "\n";
}
}