#include "cpp_api/s_entity.h"
#include "cpp_api/s_internal.h"
#include "log.h"
#include "object_properties.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "gamedef.h"
#include <sstream>
bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
{
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_entities");
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name);
if (!lua_istable(L, -1)) {
errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
return false;
}
int prototype_table = lua_gettop(L);
lua_newtable(L);
int object = lua_gettop(L);
lua_pushvalue(L, prototype_table);
lua_setmetatable(L, -2);
push_objectRef(L, id);
assert(lua_type(L, -1) == LUA_TUSERDATA);
lua_setfield(L, -2, "object");
lua_getglobal(L, "core");
lua_getfield(L, -1, "luaentities");
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushvalue(L, object);
lua_rawseti(L, -2, id);
return true;
}
void ScriptApiEntity::luaentity_Activate(u16 id,
const std::string &staticdata, u32 dtime_s)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
luaentity_get(L, id);
int object = lua_gettop(L);
lua_getfield(L, -1, "on_activate");
if (!lua_isnil(L, -1)) {
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
lua_pushlstring(L, staticdata.c_str(), staticdata.size());
lua_pushinteger(L, dtime_s);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 3, 0, error_handler));
} else {
lua_pop(L, 1);
}
lua_pop(L, 2);
}
void ScriptApiEntity::luaentity_Deactivate(u16 id, bool removal)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
luaentity_get(L, id);
int object = lua_gettop(L);
lua_getfield(L, -1, "on_deactivate");
if (!lua_isnil(L, -1)) {
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
lua_pushboolean(L, removal);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 2, 0, error_handler));
} else {
lua_pop(L, 1);
}
lua_pop(L, 2);
}
void ScriptApiEntity::luaentity_Remove(u16 id)
{
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "core");
lua_getfield(L, -1, "luaentities");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
lua_pushnil(L);
lua_rawseti(L, objectstable, id);
lua_pop(L, 2);
}
std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
std::string ret;
luaentity_get(L, id);
int object = lua_gettop(L);
lua_getfield(L, -1, "get_staticdata");
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return ret;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 1, 1, error_handler));
ret = readParam<std::string>(L, -1, "");
lua_pop(L, 2);
return ret;
}
void ScriptApiEntity::logDeprecationForExistingProperties(lua_State *L, int index, const std::string &name)
{
if (deprecation_warned_init_properties.count(name) > 0)
return;
if (index < 0)
index = lua_gettop(L) + 1 + index;
if (!lua_istable(L, index))
return;
for (const char *key : object_property_keys) {
lua_getfield(L, index, key);
bool exists = !lua_isnil(L, -1);
lua_pop(L, 1);
if (exists) {
std::ostringstream os;
os << "Reading initial object properties directly from an entity definition is deprecated, "
<< "move it to the 'initial_properties' table instead. "
<< "(Property '" << key << "' in entity '" << name << "')" << std::endl;
log_deprecated(L, os.str(), -1);
deprecation_warned_init_properties.insert(name);
break;
}
}
}
void ScriptApiEntity::luaentity_GetProperties(u16 id,
ServerActiveObject *self, ObjectProperties *prop, const std::string &entity_name)
{
SCRIPTAPI_PRECHECKHEADER
luaentity_get(L, id);
prop->hp_max = 10;
auto *idef = getGameDef()->idef();
logDeprecationForExistingProperties(L, -1, entity_name);
read_object_properties(L, -1, self, prop, idef, true);
lua_getfield(L, -1, "initial_properties");
read_object_properties(L, -1, self, prop, idef);
lua_pop(L, 1);
}
void ScriptApiEntity::luaentity_Step(u16 id, float dtime,
const CollisionMoveResult *moveresult)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
luaentity_get(L, id);
int object = lua_gettop(L);
lua_getfield(L, -1, "on_step");
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
lua_pushnumber(L, dtime);
if (moveresult)
push_collision_move_result(L, *moveresult);
else
lua_pushnil(L);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 3, 0, error_handler));
lua_pop(L, 2);
}
bool ScriptApiEntity::luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
const ToolCapabilities &toolcap, v3f dir, s32 damage)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
luaentity_get(L,id);
int object = lua_gettop(L);
lua_getfield(L, -1, "on_punch");
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return false;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
if (puncher)
objectrefGetOrCreate(L, puncher);
else
lua_pushnil(L);
lua_pushnumber(L, time_from_last_punch);
push_tool_capabilities(L, toolcap);
push_v3f(L, dir);
lua_pushnumber(L, damage);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 6, 1, error_handler));
bool retval = readParam<bool>(L, -1);
lua_pop(L, 2);
return retval;
}
bool ScriptApiEntity::luaentity_run_simple_callback(u16 id,
ServerActiveObject *sao, const char *field)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
luaentity_get(L, id);
int object = lua_gettop(L);
lua_getfield(L, -1, field);
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return false;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object);
if (sao)
objectrefGetOrCreate(L, sao);
else
lua_pushnil(L);
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 2, 1, error_handler));
bool retval = readParam<bool>(L, -1);
lua_pop(L, 2);
return retval;
}
bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
{
return luaentity_run_simple_callback(id, killer, "on_death");
}
void ScriptApiEntity::luaentity_Rightclick(u16 id, ServerActiveObject *clicker)
{
luaentity_run_simple_callback(id, clicker, "on_rightclick");
}
void ScriptApiEntity::luaentity_on_attach_child(u16 id, ServerActiveObject *child)
{
luaentity_run_simple_callback(id, child, "on_attach_child");
}
void ScriptApiEntity::luaentity_on_detach_child(u16 id, ServerActiveObject *child)
{
luaentity_run_simple_callback(id, child, "on_detach_child");
}
void ScriptApiEntity::luaentity_on_detach(u16 id, ServerActiveObject *parent)
{
luaentity_run_simple_callback(id, parent, "on_detach");
}