aboutsummaryrefslogtreecommitdiff
path: root/src/script/cpp_api
diff options
context:
space:
mode:
authorAndrew Ward <rw@rubenwardy.com>2018-03-28 16:05:18 +0100
committerGitHub <noreply@github.com>2018-03-28 16:05:18 +0100
commitdfc81983491417c5cd1c99d7db05e421c409379d (patch)
tree7b0457f0ff86f038cfad1a095d3ab0b6c44f2def /src/script/cpp_api
parent2323842dd3dd336b087ca3cf9756e0680b3a1244 (diff)
Add reasons to on_dieplayer and on_hpchange
Diffstat (limited to 'src/script/cpp_api')
-rw-r--r--src/script/cpp_api/s_base.cpp23
-rw-r--r--src/script/cpp_api/s_base.h3
-rw-r--r--src/script/cpp_api/s_player.cpp20
-rw-r--r--src/script/cpp_api/s_player.h6
4 files changed, 43 insertions, 9 deletions
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index f451156bd..571bac611 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -43,6 +43,7 @@ extern "C" {
#include <cstdio>
#include <cstdarg>
#include "script/common/c_content.h"
+#include "content_sao.h"
#include <sstream>
@@ -151,7 +152,7 @@ void ScriptApiBase::clientOpenLibs(lua_State *L)
{ LUA_JITLIBNAME, luaopen_jit },
#endif
};
-
+
for (const std::pair<std::string, lua_CFunction> &lib : m_libs) {
lua_pushcfunction(L, lib.second);
lua_pushstring(L, lib.first.c_str());
@@ -381,6 +382,26 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
}
}
+void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
+{
+ if (reason.lua_reference >= 0) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, reason.lua_reference);
+ luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference);
+ } else
+ lua_newtable(L);
+
+ lua_pushstring(L, reason.getTypeAsString().c_str());
+ lua_setfield(L, -2, "type");
+
+ lua_pushstring(L, reason.from_mod ? "mod" : "engine");
+ lua_setfield(L, -2, "from");
+
+ if (reason.object) {
+ objectrefGetOrCreate(L, reason.object);
+ lua_setfield(L, -2, "object");
+ }
+}
+
Server* ScriptApiBase::getServer()
{
return dynamic_cast<Server *>(m_gamedef);
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 4837f4f99..dc7b581e3 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -72,6 +72,7 @@ class IGameDef;
class Environment;
class GUIEngine;
class ServerActiveObject;
+class PlayerHPChangeReason;
class ScriptApiBase {
public:
@@ -139,6 +140,8 @@ protected:
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
+ void pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason& reason);
+
std::recursive_mutex m_luastackmutex;
std::string m_last_run_mod;
bool m_secure = false;
diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp
index 578298e24..cc2b96d5e 100644
--- a/src/script/cpp_api/s_player.cpp
+++ b/src/script/cpp_api/s_player.cpp
@@ -36,16 +36,20 @@ void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
-void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
+void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason)
{
SCRIPTAPI_PRECHECKHEADER
- // Get core.registered_on_dieplayers
+ // Get callback table
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_dieplayers");
- // Call callbacks
+
+ // Push arguments
objectrefGetOrCreate(L, player);
- runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+ pushPlayerHPChangeReason(L, reason);
+
+ // Run callbacks
+ runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}
bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
@@ -71,7 +75,7 @@ bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
}
s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
- s16 hp_change)
+ s16 hp_change, const PlayerHPChangeReason &reason)
{
SCRIPTAPI_PRECHECKHEADER
@@ -82,9 +86,13 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
lua_getfield(L, -1, "registered_on_player_hpchange");
lua_remove(L, -2);
+ // Push arguments
objectrefGetOrCreate(L, player);
lua_pushnumber(L, hp_change);
- PCALL_RES(lua_pcall(L, 2, 1, error_handler));
+ pushPlayerHPChangeReason(L, reason);
+
+ // Call callbacks
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
hp_change = lua_tointeger(L, -1);
lua_pop(L, 2); // Pop result and error handler
return hp_change;
diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h
index 562805695..59e1505ae 100644
--- a/src/script/cpp_api/s_player.h
+++ b/src/script/cpp_api/s_player.h
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
struct ToolCapabilities;
+struct PlayerHPChangeReason;
class ScriptApiPlayer : virtual public ScriptApiBase
{
@@ -31,7 +32,7 @@ public:
virtual ~ScriptApiPlayer() = default;
void on_newplayer(ServerActiveObject *player);
- void on_dieplayer(ServerActiveObject *player);
+ void on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason);
bool on_respawnplayer(ServerActiveObject *player);
bool on_prejoinplayer(const std::string &name, const std::string &ip,
std::string *reason);
@@ -42,7 +43,8 @@ public:
bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
float time_from_last_punch, const ToolCapabilities *toolcap,
v3f dir, s16 damage);
- s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change);
+ s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change,
+ const PlayerHPChangeReason &reason);
void on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname, const StringMap &fields);
void on_auth_failure(const std::string &name, const std::string &ip);
set_lzb_param(par, val) if params[par] and tonumber(val) then params[par] = tonumber(val) else error("Inexistant param or not a number") end end local function resolve_latest_lzbdata(ckp, index) local i = #ckp local ckpi while i>0 do ckpi = ckp[i] if ckpi.index <= index and ckpi.lzbdata then return ckpi.lzbdata end i=i-1 end return {} end local function look_ahead(id, train) local lzb = train.lzb if lzb.zero_checkpoint then -- if the checkpoints list contains a zero checkpoint, don't look ahead -- in order to not trigger approach callbacks on the wrong path return end local acc = advtrains.get_acceleration(train, 1) -- worst-case: the starting point is maximum speed local vel = train.max_speed or train.velocity local brakedst = ( -(vel*vel) / (2*acc) ) * params.DST_FACTOR --local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE) -- worst case (don't use index_by_offset) local brake_i = atfloor(train.index + brakedst + params.BRAKE_SPACE) --atprint("LZB: looking ahead up to ", brake_i) --local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE) local trav = lzb.trav_index -- retrieve latest lzbdata if not lzb.trav_lzbdata then lzb.trav_lzbdata = resolve_latest_lzbdata(lzb.checkpoints, trav) end if lzb.trav_lzbdata.off_track then --previous position was off track, do not scan any further end while trav <= brake_i and not lzb.zero_checkpoint do local pos = advtrains.path_get(train, trav) -- check offtrack if trav - 1 == train.path_trk_f then lzb.trav_lzbdata.off_track = true advtrains.lzb_add_checkpoint(train, trav - 1, 0, nil, lzb.trav_lzbdata) else -- run callbacks -- Note: those callbacks are defined in trainlogic.lua for consistency with the other node callbacks advtrains.tnc_call_approach_callback(pos, id, train, trav, lzb.trav_lzbdata) end trav = trav + 1 end lzb.trav_index = trav end advtrains.lzb_look_ahead = look_ahead local function call_runover_callbacks(id, train) if not train.lzb then return end local i = 1 local idx = atfloor(train.index) local ckp = train.lzb.checkpoints while ckp[i] do if ckp[i].index <= idx then --atprint("LZB: checkpoint run over: i=",ckp[i].index,"s=",ckp[i].speed,"p=",ckp[i].pos) -- call callback local it = ckp[i] if it.callback then it.callback(it.pos, id, train, it.index, it.speed, train.lzb.lzbdata) end -- note: lzbdata is always defined as look_ahead was called before table.remove(ckp, i) else i = i + 1 end end end -- Flood-fills train.path_speed, based on this checkpoint local function apply_checkpoint_to_path(train, checkpoint) if not checkpoint.speed then return end --atprint("LZB: applying checkpoint: i=",checkpoint.index,"s=",checkpoint.speed,"p=",checkpoint.pos) if checkpoint.speed == 0 then train.lzb.zero_checkpoint = true end -- make sure path exists until checkpoint local pos = advtrains.path_get(train, checkpoint.index) local brake_accel = advtrains.get_acceleration(train, 11) -- start with the checkpoint index at specified speed local index = checkpoint.index local p_speed -- speed in path_speed local c_speed = checkpoint.speed -- calculated speed at current index while true do p_speed = train.path_speed[index] if (p_speed and p_speed <= c_speed) or index < train.index then --we're done. train already slower than wanted at this position return end -- insert calculated target speed train.path_speed[index] = c_speed -- calculate c_speed at previous index advtrains.path_get(train, index-1) local eldist = train.path_dist[index] - train.path_dist[index-1] -- Calculate the start velocity the train would have if it had a end velocity of c_speed and accelerating with brake_accel, after a distance of eldist: -- v0² = v1² - 2*a*s c_speed = math.sqrt( (c_speed * c_speed) - (2 * brake_accel * eldist) ) index = index - 1 end end --[[ Distance needed to accelerate from v0 to v1 with constant acceleration a: v1 - v0 a / v1 - v0 \ 2 v1^2 - v0^2 s = v0 * ------- + - * | ------- | = ----------- a 2 \ a / 2*a ]] -- Removes all LZB checkpoints and restarts the traverser at the current train index function advtrains.lzb_invalidate(train) --advtrains.atprint_context_tid = train.id --atprint("LZB: invalidate") --advtrains.atprint_context_tid = nil train.lzb = { trav_index = atfloor(train.index) + 1, checkpoints = {}, } end -- LZB part of path_invalidate_ahead. Clears all checkpoints that are ahead of start_idx -- in contrast to path_inv_ahead, doesn't complain if start_idx is behind train.index, clears everything then function advtrains.lzb_invalidate_ahead(train, start_idx) --advtrains.atprint_context_tid = train.id --atprint("LZB: invalidate ahead i=",start_idx) if train.lzb then local idx = atfloor(start_idx) --atprint("LZB: invalidate ahead p=",train.path[start_idx]) local i = 1 while train.lzb.checkpoints[i] do if train.lzb.checkpoints[i].index >= idx then table.remove(train.lzb.checkpoints, i) else i=i+1 end end train.lzb.trav_index = idx -- FIX reset trav_lzbdata (look_ahead fetches these when required) train.lzb.trav_lzbdata = nil -- re-apply all checkpoints to path_speed train.path_speed = {} train.lzb.zero_checkpoint = false for _,ckp in ipairs(train.lzb.checkpoints) do apply_checkpoint_to_path(train, ckp) end end --advtrains.atprint_context_tid = nil end -- Add LZB control point -- lzbdata: If you modify lzbdata in an approach callback, you MUST add a checkpoint AND pass the (modified) lzbdata into it. -- If you DON'T modify lzbdata, you MUST pass nil as lzbdata. Always modify the lzbdata table in place, never overwrite it! -- udata: user-defined data, do not use externally function advtrains.lzb_add_checkpoint(train, index, speed, callback, lzbdata, udata) local lzb = train.lzb local pos = advtrains.path_get(train, index) local lzbdata_c = nil if lzbdata then -- make a shallow copy of lzbdata lzbdata_c = {} for k,v in pairs(lzbdata) do lzbdata_c[k] = v end end local ckp = { pos = pos, index = index, speed = speed, callback = callback, lzbdata = lzbdata_c, udata = udata, } table.insert(lzb.checkpoints, ckp) apply_checkpoint_to_path(train, ckp) end advtrains.te_register_on_new_path(function(id, train) advtrains.lzb_invalidate(train) -- Taken care of in pre-move hook (see train_step_b) --look_ahead(id, train) end) advtrains.te_register_on_invalidate_ahead(function(id, train, start_idx) advtrains.lzb_invalidate_ahead(train, start_idx) end) advtrains.te_register_on_update(function(id, train) if not train.path or not train.lzb then atprint("LZB run: no path on train, skip step") return end -- Note: look_ahead called from train_step_b before applying movement -- TODO: if more pre-move hooks are added, make a separate callback hook --look_ahead(id, train) call_runover_callbacks(id, train) end, true)