Working on stuff
This commit is contained in:
1 parent
17d903fd52
commit
07f45ad1e1
11 files changed
+176
-70
No files matched your search
+104
-54
@@ -11,6 +11,54 @@
|
||||
|
||||
namespace ZL {
|
||||
|
||||
namespace {
|
||||
|
||||
// Wraps a sol::protected_function into a std::function<void()>, invoking it and
|
||||
// logging any Lua-side error to stderr. Shared by every binding that stores a
|
||||
// callback for later, one-shot invocation (npc_walk_to, move_object, etc.) and by
|
||||
// rehydrateNamedCallback, which re-wraps a callback looked up by name after load.
|
||||
std::function<void()> wrapLuaCallback(sol::protected_function fn) {
|
||||
return [fn]() mutable {
|
||||
auto result = fn();
|
||||
if (!result.valid()) {
|
||||
sol::error err = result;
|
||||
std::cerr << "[script] callback error: " << err.what() << "\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Reverse-looks-up the global name a Lua function is registered under, by
|
||||
// comparing raw function pointers via lua_topointer. Returns "" if fn isn't
|
||||
// (or is no longer) reachable as a plain global — e.g. an anonymous function,
|
||||
// or one stored only in a local/upvalue. This lets callback-accepting bindings
|
||||
// remember a callback "by name" for save/load without changing the Lua-facing
|
||||
// API (scripts still just pass a function reference).
|
||||
std::string findGlobalFunctionName(lua_State* L, const sol::protected_function& fn) {
|
||||
if (!fn.valid()) return {};
|
||||
|
||||
fn.push(L);
|
||||
const void* target = lua_topointer(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (!target) return {};
|
||||
|
||||
std::string found;
|
||||
lua_pushglobaltable(L); // stack: [_G]
|
||||
lua_pushnil(L); // stack: [_G, nil]
|
||||
while (lua_next(L, -2) != 0) { // stack: [_G, key, value]
|
||||
if (lua_type(L, -2) == LUA_TSTRING && lua_isfunction(L, -1) &&
|
||||
lua_topointer(L, -1) == target) {
|
||||
found = lua_tostring(L, -2);
|
||||
lua_pop(L, 2); // pop value, key
|
||||
break;
|
||||
}
|
||||
lua_pop(L, 1); // pop value, keep key for next iteration
|
||||
}
|
||||
lua_pop(L, 1); // pop _G
|
||||
return found;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
struct ScriptEngine::Impl {
|
||||
sol::state lua;
|
||||
std::unordered_map<std::string, sol::protected_function> triggerEnterCallbacks;
|
||||
@@ -45,7 +93,7 @@ namespace ZL {
|
||||
// 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",
|
||||
[loc](int index, float x, float y, float z, sol::object on_arrived) {
|
||||
[loc, this_impl = impl.get()](int index, float x, float y, float z, sol::object on_arrived) {
|
||||
auto& npcs = loc->npcs;
|
||||
if (index < 0 || index >= static_cast<int>(npcs.size())) {
|
||||
std::cerr << "[script] npc_walk_to: index " << index
|
||||
@@ -53,18 +101,16 @@ namespace ZL {
|
||||
return;
|
||||
}
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
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";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] npc_walk_to: on_arrived callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
npcs[index]->state.homePosition = Eigen::Vector3f(x, 0.f, z);
|
||||
npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb));
|
||||
npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb), std::move(cbName));
|
||||
});
|
||||
|
||||
|
||||
@@ -83,21 +129,19 @@ namespace ZL {
|
||||
});
|
||||
|
||||
api.set_function("player_walk_to",
|
||||
[loc](float x, float y, float z, sol::object on_arrived) {
|
||||
[loc, this_impl = impl.get()](float x, float y, float z, sol::object on_arrived) {
|
||||
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
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";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] player_walk_to: on_arrived callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
loc->player->state.homePosition = Eigen::Vector3f(x, 0.f, z);
|
||||
loc->player->setTarget(Eigen::Vector3f(x, y, z), std::move(cb));
|
||||
loc->player->setTarget(Eigen::Vector3f(x, y, z), std::move(cb), std::move(cbName));
|
||||
});
|
||||
|
||||
|
||||
@@ -556,7 +600,7 @@ namespace ZL {
|
||||
|
||||
// move_object(name, x, y, z, duration_sec [, on_complete])
|
||||
api.set_function("move_object",
|
||||
[loc](const std::string& name, float x, float y, float z,
|
||||
[loc, this_impl = impl.get()](const std::string& name, float x, float y, float z,
|
||||
float durationSec, sol::object onComplete) {
|
||||
for (auto& intObj : loc->interactiveObjects) {
|
||||
if (intObj.loadedObject.name != name) continue;
|
||||
@@ -565,17 +609,15 @@ namespace ZL {
|
||||
return;
|
||||
}
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
if (onComplete.is<sol::protected_function>()) {
|
||||
sol::protected_function fn = onComplete.as<sol::protected_function>();
|
||||
cb = [fn]() mutable {
|
||||
auto res = fn();
|
||||
if (!res.valid()) {
|
||||
sol::error err = res;
|
||||
std::cerr << "[script] move_object on_complete error: " << err.what() << "\n";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] move_object: on_complete callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
intObj.moveTo(Eigen::Vector3f(x, y, z), durationSec, std::move(cb));
|
||||
intObj.moveTo(Eigen::Vector3f(x, y, z), durationSec, std::move(cb), std::move(cbName));
|
||||
return;
|
||||
}
|
||||
std::cerr << "[script] move_object: object '" << name << "' not found\n";
|
||||
@@ -583,7 +625,7 @@ namespace ZL {
|
||||
|
||||
// rotate_object(name, angle_deg, duration_sec [, on_complete])
|
||||
api.set_function("rotate_object",
|
||||
[loc](const std::string& name, float angleDeg,
|
||||
[loc, this_impl = impl.get()](const std::string& name, float angleDeg,
|
||||
float durationSec, sol::object onComplete) {
|
||||
for (auto& intObj : loc->interactiveObjects) {
|
||||
if (intObj.loadedObject.name != name) continue;
|
||||
@@ -592,18 +634,16 @@ namespace ZL {
|
||||
return;
|
||||
}
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
if (onComplete.is<sol::protected_function>()) {
|
||||
sol::protected_function fn = onComplete.as<sol::protected_function>();
|
||||
cb = [fn]() mutable {
|
||||
auto res = fn();
|
||||
if (!res.valid()) {
|
||||
sol::error err = res;
|
||||
std::cerr << "[script] rotate_object on_complete error: " << err.what() << "\n";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] rotate_object: on_complete callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
const float angleRad = angleDeg * static_cast<float>(M_PI) / 180.f;
|
||||
intObj.rotateTo(intObj.state.rotationY + angleRad, durationSec, std::move(cb));
|
||||
intObj.rotateTo(intObj.state.rotationY + angleRad, durationSec, std::move(cb), std::move(cbName));
|
||||
return;
|
||||
}
|
||||
std::cerr << "[script] rotate_object: object '" << name << "' not found\n";
|
||||
@@ -611,7 +651,7 @@ namespace ZL {
|
||||
|
||||
// fade_object(name, target_alpha, duration_sec [, on_complete])
|
||||
api.set_function("fade_object",
|
||||
[loc](const std::string& name, float targetAlpha,
|
||||
[loc, this_impl = impl.get()](const std::string& name, float targetAlpha,
|
||||
float durationSec, sol::object onComplete) {
|
||||
for (auto& intObj : loc->interactiveObjects) {
|
||||
if (intObj.loadedObject.name != name) continue;
|
||||
@@ -620,17 +660,15 @@ namespace ZL {
|
||||
return;
|
||||
}
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
if (onComplete.is<sol::protected_function>()) {
|
||||
sol::protected_function fn = onComplete.as<sol::protected_function>();
|
||||
cb = [fn]() mutable {
|
||||
auto res = fn();
|
||||
if (!res.valid()) {
|
||||
sol::error err = res;
|
||||
std::cerr << "[script] fade_object on_complete error: " << err.what() << "\n";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] fade_object: on_complete callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
intObj.fadeTo(targetAlpha, durationSec, std::move(cb));
|
||||
intObj.fadeTo(targetAlpha, durationSec, std::move(cb), std::move(cbName));
|
||||
return;
|
||||
}
|
||||
std::cerr << "[script] fade_object: object '" << name << "' not found\n";
|
||||
@@ -638,7 +676,7 @@ namespace ZL {
|
||||
|
||||
// scale_object(name, target_scale, duration_sec [, on_complete])
|
||||
api.set_function("scale_object",
|
||||
[loc](const std::string& name, float targetScale,
|
||||
[loc, this_impl = impl.get()](const std::string& name, float targetScale,
|
||||
float durationSec, sol::object onComplete) {
|
||||
for (auto& intObj : loc->interactiveObjects) {
|
||||
if (intObj.loadedObject.name != name) continue;
|
||||
@@ -647,17 +685,15 @@ namespace ZL {
|
||||
return;
|
||||
}
|
||||
std::function<void()> cb;
|
||||
std::string cbName;
|
||||
if (onComplete.is<sol::protected_function>()) {
|
||||
sol::protected_function fn = onComplete.as<sol::protected_function>();
|
||||
cb = [fn]() mutable {
|
||||
auto res = fn();
|
||||
if (!res.valid()) {
|
||||
sol::error err = res;
|
||||
std::cerr << "[script] scale_object on_complete error: " << err.what() << "\n";
|
||||
}
|
||||
};
|
||||
cb = wrapLuaCallback(fn);
|
||||
cbName = findGlobalFunctionName(this_impl->lua.lua_state(), fn);
|
||||
if (cbName.empty())
|
||||
std::cerr << "[script] scale_object: on_complete callback has no global name, will not survive save/load\n";
|
||||
}
|
||||
intObj.scaleTo(targetScale, durationSec, std::move(cb));
|
||||
intObj.scaleTo(targetScale, durationSec, std::move(cb), std::move(cbName));
|
||||
return;
|
||||
}
|
||||
std::cerr << "[script] scale_object: object '" << name << "' not found\n";
|
||||
@@ -1065,4 +1101,18 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::rehydrateNamedCallback(const std::string& name, std::function<void()>& outCallback) const
|
||||
{
|
||||
outCallback = nullptr;
|
||||
if (!impl || name.empty()) return;
|
||||
|
||||
sol::protected_function fn = impl->lua[name];
|
||||
if (!fn.valid()) {
|
||||
std::cerr << "[SCRIPT] rehydrateNamedCallback: global function '" << name
|
||||
<< "' not found (script changed since save?)\n";
|
||||
return;
|
||||
}
|
||||
outCallback = wrapLuaCallback(fn);
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
Reference in new issue
Block a user