aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/common/c_content.cpp128
-rw-r--r--src/script/common/c_content.h6
-rw-r--r--src/script/cpp_api/CMakeLists.txt1
-rw-r--r--src/script/cpp_api/s_base.cpp24
-rw-r--r--src/script/cpp_api/s_base.h13
-rw-r--r--src/script/cpp_api/s_cheats.cpp123
-rw-r--r--src/script/cpp_api/s_cheats.h58
-rw-r--r--src/script/cpp_api/s_client.cpp177
-rw-r--r--src/script/cpp_api/s_client.h15
-rw-r--r--src/script/cpp_api/s_security.cpp11
-rw-r--r--src/script/lua_api/CMakeLists.txt2
-rw-r--r--src/script/lua_api/l_base.cpp5
-rw-r--r--src/script/lua_api/l_base.h3
-rw-r--r--src/script/lua_api/l_client.cpp261
-rw-r--r--src/script/lua_api/l_client.h33
-rw-r--r--src/script/lua_api/l_clientobject.cpp342
-rw-r--r--src/script/lua_api/l_clientobject.h106
-rw-r--r--src/script/lua_api/l_env.cpp169
-rw-r--r--src/script/lua_api/l_env.h12
-rw-r--r--src/script/lua_api/l_inventoryaction.cpp215
-rw-r--r--src/script/lua_api/l_inventoryaction.h74
-rw-r--r--src/script/lua_api/l_item.cpp20
-rw-r--r--src/script/lua_api/l_localplayer.cpp148
-rw-r--r--src/script/lua_api/l_localplayer.h28
-rw-r--r--src/script/lua_api/l_mainmenu.cpp4
-rw-r--r--src/script/lua_api/l_server.cpp1
-rw-r--r--src/script/lua_api/l_util.cpp5
-rw-r--r--src/script/scripting_client.cpp19
-rw-r--r--src/script/scripting_client.h4
29 files changed, 1948 insertions, 59 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 79830ddb4..0bdeaab9e 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "object_properties.h"
#include "collision.h"
#include "cpp_api/s_node.h"
+#include "lua_api/l_clientobject.h"
#include "lua_api/l_object.h"
#include "lua_api/l_item.h"
#include "common/c_internal.h"
@@ -174,10 +175,12 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
}
push_groups(L, i.groups);
lua_setfield(L, -2, "groups");
+ lua_newtable(L);
push_soundspec(L, i.sound_place);
- lua_setfield(L, -2, "sound_place");
+ lua_setfield(L, -2, "place");
push_soundspec(L, i.sound_place_failed);
- lua_setfield(L, -2, "sound_place_failed");
+ lua_setfield(L, -2, "place_failed");
+ lua_setfield(L, -2, "sounds");
lua_pushstring(L, i.node_placement_prediction.c_str());
lua_setfield(L, -2, "node_placement_prediction");
}
@@ -197,14 +200,14 @@ void read_object_properties(lua_State *L, int index,
if (getintfield(L, -1, "hp_max", hp_max)) {
prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
- if (prop->hp_max < sao->getHP()) {
+ if (sao && prop->hp_max < sao->getHP()) {
PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
sao->setHP(prop->hp_max, reason);
}
}
if (getintfield(L, -1, "breath_max", prop->breath_max)) {
- if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ if (sao && sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
PlayerSAO *player = (PlayerSAO *)sao;
if (prop->breath_max < player->getBreath())
player->setBreath(prop->breath_max);
@@ -511,6 +514,35 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
}
/******************************************************************************/
+void push_tiledef(lua_State *L, TileDef tiledef)
+{
+ lua_newtable(L);
+ setstringfield(L, -1, "name", tiledef.name);
+ setboolfield(L, -1, "backface_culling", tiledef.backface_culling);
+ setboolfield(L, -1, "tileable_horizontal", tiledef.tileable_horizontal);
+ setboolfield(L, -1, "tileable_vertical", tiledef.tileable_vertical);
+ std::string align_style;
+ switch (tiledef.align_style) {
+ case ALIGN_STYLE_USER_DEFINED:
+ align_style = "user";
+ break;
+ case ALIGN_STYLE_WORLD:
+ align_style = "world";
+ break;
+ default:
+ align_style = "node";
+ }
+ setstringfield(L, -1, "align_style", align_style);
+ setintfield(L, -1, "scale", tiledef.scale);
+ if (tiledef.has_color) {
+ push_ARGB8(L, tiledef.color);
+ lua_setfield(L, -2, "color");
+ }
+ push_animation_definition(L, tiledef.animation);
+ lua_setfield(L, -2, "animation");
+}
+
+/******************************************************************************/
void read_content_features(lua_State *L, ContentFeatures &f, int index)
{
if(index < 0)
@@ -849,9 +881,32 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
- /* Missing "tiles" because I don't see a usecase (at least not yet). */
+ lua_newtable(L);
+
+ // tiles
+ lua_newtable(L);
+ for (int i = 0; i < 6; i++) {
+ push_tiledef(L, c.tiledef[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "tiles");
+ // overlay_tiles
lua_newtable(L);
+ for (int i = 0; i < 6; i++) {
+ push_tiledef(L, c.tiledef_overlay[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "overlay_tiles");
+
+ // special_tiles
+ lua_newtable(L);
+ for (int i = 0; i < CF_SPECIAL_COUNT; i++) {
+ push_tiledef(L, c.tiledef_special[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "special_tiles");
+
lua_pushboolean(L, c.has_on_construct);
lua_setfield(L, -2, "has_on_construct");
lua_pushboolean(L, c.has_on_destruct);
@@ -955,11 +1010,11 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
lua_setfield(L, -2, "collision_box");
lua_newtable(L);
push_soundspec(L, c.sound_footstep);
- lua_setfield(L, -2, "sound_footstep");
+ lua_setfield(L, -2, "footstep");
push_soundspec(L, c.sound_dig);
- lua_setfield(L, -2, "sound_dig");
+ lua_setfield(L, -2, "dig");
push_soundspec(L, c.sound_dug);
- lua_setfield(L, -2, "sound_dug");
+ lua_setfield(L, -2, "dug");
lua_setfield(L, -2, "sounds");
lua_pushboolean(L, c.legacy_facedir_simple);
lua_setfield(L, -2, "legacy_facedir_simple");
@@ -1435,6 +1490,29 @@ struct TileAnimationParams read_animation_definition(lua_State *L, int index)
return anim;
}
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim)
+{
+ switch (anim.type) {
+ case TAT_NONE:
+ lua_pushnil(L);
+ break;
+ case TAT_VERTICAL_FRAMES:
+ lua_newtable(L);
+ setstringfield(L, -1, "type", "vertical_frames");
+ setfloatfield(L, -1, "aspect_w", anim.vertical_frames.aspect_w);
+ setfloatfield(L, -1, "aspect_h", anim.vertical_frames.aspect_h);
+ setfloatfield(L, -1, "length", anim.vertical_frames.length);
+ break;
+ case TAT_SHEET_2D:
+ lua_newtable(L);
+ setstringfield(L, -1, "type", "sheet_2d");
+ setintfield(L, -1, "frames_w", anim.sheet_2d.frames_w);
+ setintfield(L, -1, "frames_h", anim.sheet_2d.frames_h);
+ setintfield(L, -1, "frame_length", anim.sheet_2d.frame_length);
+ break;
+ }
+}
+
/******************************************************************************/
ToolCapabilities read_tool_capabilities(
lua_State *L, int table)
@@ -1868,14 +1946,8 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
} else if (pointed.type == POINTEDTHING_OBJECT) {
lua_pushstring(L, "object");
lua_setfield(L, -2, "type");
-
- if (csm) {
- lua_pushinteger(L, pointed.object_id);
- lua_setfield(L, -2, "id");
- } else {
- push_objectRef(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
+ push_objectRef(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
} else {
lua_pushstring(L, "nothing");
lua_setfield(L, -2, "type");
@@ -2147,3 +2219,27 @@ void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
lua_setfield(L, -2, "collisions");
/**/
}
+
+/******************************************************************************/
+void push_physics_override(lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+ lua_createtable(L, 0, 6);
+
+ lua_pushnumber(L, speed);
+ lua_setfield(L, -2, "speed");
+
+ lua_pushnumber(L, jump);
+ lua_setfield(L, -2, "jump");
+
+ lua_pushnumber(L, gravity);
+ lua_setfield(L, -2, "gravity");
+
+ lua_pushboolean(L, sneak);
+ lua_setfield(L, -2, "sneak");
+
+ lua_pushboolean(L, sneak_glitch);
+ lua_setfield(L, -2, "sneak_glitch");
+
+ lua_pushboolean(L, new_move);
+ lua_setfield(L, -2, "new_move");
+}
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index a7b8709c6..a6b96c012 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -101,6 +101,7 @@ void push_hit_params (lua_State *L,
ItemStack read_item (lua_State *L, int index, IItemDefManager *idef);
struct TileAnimationParams read_animation_definition(lua_State *L, int index);
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim);
ToolCapabilities read_tool_capabilities (lua_State *L, int table);
void push_tool_capabilities (lua_State *L,
@@ -120,6 +121,9 @@ void read_object_properties (lua_State *L, int index,
void push_object_properties (lua_State *L,
ObjectProperties *prop);
+void push_inventory (lua_State *L,
+ Inventory *inventory);
+
void push_inventory_list (lua_State *L,
const InventoryList &invlist);
void push_inventory_lists (lua_State *L,
@@ -204,3 +208,5 @@ void push_hud_element (lua_State *L, HudElement *elem);
bool read_hud_change (lua_State *L, HudElementStat &stat, HudElement *elem, void **value);
void push_collision_move_result(lua_State *L, const collisionMoveResult &res);
+
+void push_physics_override (lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move);
diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt
index 3cfd7709a..d2c55b7c5 100644
--- a/src/script/cpp_api/CMakeLists.txt
+++ b/src/script/cpp_api/CMakeLists.txt
@@ -15,6 +15,7 @@ set(common_SCRIPT_CPP_API_SRCS
set(client_SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_cheats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index 595c9e540..ae4a16771 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_internal.h"
#include "cpp_api/s_security.h"
#include "lua_api/l_object.h"
+#include "lua_api/l_clientobject.h"
#include "common/c_converter.h"
#include "server/player_sao.h"
#include "filesys.h"
@@ -85,9 +86,9 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
lua_atpanic(m_luastack, &luaPanic);
- if (m_type == ScriptingType::Client)
+ /*if (m_type == ScriptingType::Client)
clientOpenLibs(m_luastack);
- else
+ else*/
luaL_openlibs(m_luastack);
// Load bit library
@@ -365,13 +366,18 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
* since we lose control over the ref and the contained pointer.
*/
-void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::addObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
// Create object on stack
- ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+#ifndef SERVER
+ if (m_type == ScriptingType::Client)
+ ClientObjectRef::create(L, dynamic_cast<ClientActiveObject *>(cobj));
+ else
+#endif
+ ObjectRef::create(L, dynamic_cast<ServerActiveObject *>(cobj)); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
// Get core.object_refs table
@@ -386,7 +392,7 @@ void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
lua_settable(L, objectstable);
}
-void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::removeObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
@@ -401,7 +407,12 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
lua_pushnumber(L, cobj->getId()); // Push id
lua_gettable(L, objectstable);
// Set object reference to NULL
- ObjectRef::set_null(L);
+#ifndef SERVER
+ if (m_type == ScriptingType::Client)
+ ClientObjectRef::set_null(L);
+ else
+#endif
+ ObjectRef::set_null(L);
lua_pop(L, 1); // pop object
// Set object_refs[id] = nil
@@ -424,7 +435,6 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
<< ", this is probably a bug." << std::endl;
}
}
-
void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
{
if (reason.hasLuaReference())
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 244d81605..19ae8783b 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -67,10 +67,12 @@ enum class ScriptingType: u8 {
class Server;
#ifndef SERVER
class Client;
+class Game;
#endif
class IGameDef;
class Environment;
class GUIEngine;
+class ActiveObject;
class ServerActiveObject;
struct PlayerHPChangeReason;
@@ -97,14 +99,15 @@ public:
RunCallbacksMode mode, const char *fxn);
/* object */
- void addObjectReference(ServerActiveObject *cobj);
- void removeObjectReference(ServerActiveObject *cobj);
+ void addObjectReference(ActiveObject *cobj);
+ void removeObjectReference(ActiveObject *cobj);
IGameDef *getGameDef() { return m_gamedef; }
Server* getServer();
ScriptingType getType() { return m_type; }
#ifndef SERVER
Client* getClient();
+ Game *getGame() { return m_game; }
#endif
// IMPORTANT: these cannot be used for any security-related uses, they exist
@@ -145,6 +148,9 @@ protected:
void stackDump(std::ostream &o);
void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
+#ifndef SERVER
+ void setGame(Game *game) { m_game = game; }
+#endif
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
@@ -172,6 +178,9 @@ private:
lua_State *m_luastack = nullptr;
IGameDef *m_gamedef = nullptr;
+#ifndef SERVER
+ Game *m_game = nullptr;
+#endif
Environment *m_environment = nullptr;
#ifndef SERVER
GUIEngine *m_guiengine = nullptr;
diff --git a/src/script/cpp_api/s_cheats.cpp b/src/script/cpp_api/s_cheats.cpp
new file mode 100644
index 000000000..3d0c5e645
--- /dev/null
+++ b/src/script/cpp_api/s_cheats.cpp
@@ -0,0 +1,123 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "cpp_api/s_cheats.h"
+#include "cpp_api/s_base.h"
+#include "cpp_api/s_internal.h"
+#include "settings.h"
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(
+ const std::string &name, const std::string &setting) :
+ m_name(name),
+ m_setting(setting), m_function_ref(0)
+{
+}
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(const std::string &name, const int &function) :
+ m_name(name), m_setting(""), m_function_ref(function)
+{
+}
+
+bool ScriptApiCheatsCheat::is_enabled()
+{
+ try {
+ return !m_function_ref && g_settings->getBool(m_setting);
+ } catch (SettingNotFoundException &) {
+ return false;
+ }
+}
+
+void ScriptApiCheatsCheat::toggle(lua_State *L, int error_handler)
+{
+ if (m_function_ref) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_ref);
+ lua_pcall(L, 0, 0, error_handler);
+ } else
+ g_settings->setBool(m_setting, !is_enabled());
+}
+
+ScriptApiCheatsCategory::ScriptApiCheatsCategory(const std::string &name) : m_name(name)
+{
+}
+
+ScriptApiCheatsCategory::~ScriptApiCheatsCategory()
+{
+ for (auto i = m_cheats.begin(); i != m_cheats.end(); i++)
+ delete *i;
+}
+
+void ScriptApiCheatsCategory::read_cheats(lua_State *L)
+{
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ ScriptApiCheatsCheat *cheat = nullptr;
+ std::string name = lua_tostring(L, -2);
+ if (lua_isstring(L, -1))
+ cheat = new ScriptApiCheatsCheat(name, lua_tostring(L, -1));
+ else if (lua_isfunction(L, -1)) {
+ cheat = new ScriptApiCheatsCheat(
+ name, luaL_ref(L, LUA_REGISTRYINDEX));
+ lua_pushnil(L);
+ }
+ if (cheat)
+ m_cheats.push_back(cheat);
+ lua_pop(L, 1);
+ }
+}
+
+ScriptApiCheats::~ScriptApiCheats()
+{
+ for (auto i = m_cheat_categories.begin(); i != m_cheat_categories.end(); i++)
+ delete *i;
+}
+
+void ScriptApiCheats::init_cheats()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "cheats");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 2);
+ return;
+ }
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_istable(L, -1)) {
+ ScriptApiCheatsCategory *category =
+ new ScriptApiCheatsCategory(lua_tostring(L, -2));
+ category->read_cheats(L);
+ m_cheat_categories.push_back(category);
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 2);
+ m_cheats_loaded = true;
+}
+
+void ScriptApiCheats::toggle_cheat(ScriptApiCheatsCheat *cheat)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - 1;
+ lua_insert(L, error_handler);
+
+ cheat->toggle(L, error_handler);
+}
diff --git a/src/script/cpp_api/s_cheats.h b/src/script/cpp_api/s_cheats.h
new file mode 100644
index 000000000..9f36333b7
--- /dev/null
+++ b/src/script/cpp_api/s_cheats.h
@@ -0,0 +1,58 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+
+#include "cpp_api/s_base.h"
+#include <vector>
+#include <string>
+
+class ScriptApiCheatsCheat
+{
+public:
+ ScriptApiCheatsCheat(const std::string &name, const std::string &setting);
+ ScriptApiCheatsCheat(const std::string &name, const int &function);
+ std::string m_name;
+ bool is_enabled();
+ void toggle(lua_State *L, int error_handler);
+
+private:
+ std::string m_setting;
+ int m_function_ref;
+};
+
+class ScriptApiCheatsCategory
+{
+public:
+ ScriptApiCheatsCategory(const std::string &name);
+ ~ScriptApiCheatsCategory();
+ std::string m_name;
+ void read_cheats(lua_State *L);
+ std::vector<ScriptApiCheatsCheat *> m_cheats;
+};
+
+class ScriptApiCheats : virtual public ScriptApiBase
+{
+public:
+ virtual ~ScriptApiCheats();
+ void init_cheats();
+ void toggle_cheat(ScriptApiCheatsCheat *cheat);
+ bool m_cheats_loaded = false;
+ std::vector<ScriptApiCheatsCategory *> m_cheat_categories;
+};
diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp
index b02a0c7be..e54a1361d 100644
--- a/src/script/cpp_api/s_client.cpp
+++ b/src/script/cpp_api/s_client.cpp
@@ -18,11 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "nodedef.h"
+#include "itemdef.h"
#include "s_client.h"
#include "s_internal.h"
#include "client/client.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "lua_api/l_clientobject.h"
#include "s_item.h"
void ScriptApiClient::on_mods_loaded()
@@ -212,7 +215,7 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
const NodeDefManager *ndef = getClient()->ndef();
- // Get core.registered_on_punchgnode
+ // Get core.registered_on_punchnode
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_punchnode");
@@ -274,6 +277,121 @@ bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &poi
return readParam<bool>(L, -1);
}
+bool ScriptApiClient::on_recieve_physics_override(float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_recieve_physics_override
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_recieve_physics_override");
+
+ // Push data
+ push_physics_override(L, speed, jump, gravity, sneak, sneak_glitch, new_move);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_play_sound(SimpleSoundSpec spec)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_play_sound
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_play_sound");
+
+ // Push data
+ push_soundspec(L, spec);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_spawn_particle(struct ParticleParameters param)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_play_sound
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_spawn_particle");
+
+ // Push data
+ lua_newtable(L);
+ push_v3f(L, param.pos);
+ lua_setfield(L, -2, "pos");
+ push_v3f(L, param.vel);
+ lua_setfield(L, -2, "velocity");
+ push_v3f(L, param.acc);
+ lua_setfield(L, -2, "acceleration");
+ setfloatfield(L, -1, "expirationtime", param.expirationtime);
+ setboolfield(L, -1, "collisiondetection", param.collisiondetection);
+ setboolfield(L, -1, "collision_removal", param.collision_removal);
+ setboolfield(L, -1, "object_collision", param.object_collision);
+ setboolfield(L, -1, "vertical", param.vertical);
+ push_animation_definition(L, param.animation);
+ lua_setfield(L, -2, "animation");
+ setstringfield(L, -1, "texture", param.texture);
+ setintfield(L, -1, "glow", param.glow);
+ if (param.node.getContent() != CONTENT_IGNORE) {
+ pushnode(L, param.node, getGameDef()->ndef());
+ lua_setfield(L, -2, "node");
+ }
+ setintfield(L, -1, "node_tile", param.node_tile);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
+void ScriptApiClient::on_object_properties_change(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_properties_change
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_properties_change");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::on_object_hp_change(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_hp_change
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_hp_change");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiClient::on_object_add(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_add
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_add");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
bool ScriptApiClient::on_inventory_open(Inventory *inventory)
{
SCRIPTAPI_PRECHECKHEADER
@@ -292,6 +410,63 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
return readParam<bool>(L, -1);
}
+void ScriptApiClient::open_enderchest()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - 1;
+ lua_insert(L, error_handler);
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "open_enderchest");
+ if (lua_isfunction(L, -1))
+ lua_pcall(L, 0, 0, error_handler);
+}
+
+v3f ScriptApiClient::get_send_speed(v3f speed)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - 1;
+ lua_insert(L, error_handler);
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "get_send_speed");
+ if (lua_isfunction(L, -1)) {
+ speed /= BS;
+ push_v3f(L, speed);
+ lua_pcall(L, 1, 1, error_handler);
+ speed = read_v3f(L, -1);
+ speed *= BS;
+ }
+
+ return speed;
+}
+
+void ScriptApiClient::set_node_def(const ContentFeatures &f)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_nodes");
+
+ push_content_features(L, f);
+ lua_setfield(L, -2, f.name.c_str());
+}
+
+void ScriptApiClient::set_item_def(const ItemDefinition &i)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_items");
+
+ push_item_definition(L, i);
+ lua_setfield(L, -2, i.name.c_str());
+}
+
void ScriptApiClient::setEnv(ClientEnvironment *env)
{
ScriptApiBase::setEnv(env);
diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h
index 93fe96791..6d1a05943 100644
--- a/src/script/cpp_api/s_client.h
+++ b/src/script/cpp_api/s_client.h
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "util/pointedthing.h"
#include "lua_api/l_item.h"
+#include "particles.h"
#ifdef _CRT_MSVCP_CURRENT
#include <cstdint>
@@ -57,8 +58,22 @@ public:
bool on_punchnode(v3s16 p, MapNode node);
bool on_placenode(const PointedThing &pointed, const ItemDefinition &item);
bool on_item_use(const ItemStack &item, const PointedThing &pointed);
+ bool on_recieve_physics_override(float override_speed, float override_jump,
+ float override_gravity, bool sneak, bool sneak_glitch,
+ bool new_move);
+ bool on_play_sound(SimpleSoundSpec spec);
+ bool on_spawn_particle(struct ParticleParameters param);
+ void on_object_properties_change(s16 id);
+ void on_object_hp_change(s16 id);
+ bool on_object_add(s16 id);
bool on_inventory_open(Inventory *inventory);
+ void open_enderchest();
+
+ v3f get_send_speed(v3f speed);
+
+ void set_node_def(const ContentFeatures &f);
+ void set_item_def(const ItemDefinition &i);
void setEnv(ClientEnvironment *env);
};
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index f68cd1777..76509038f 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -111,6 +111,7 @@ void ScriptApiSecurity::initializeSecurity()
"bit"
};
static const char *io_whitelist[] = {
+ "open",
"close",
"flush",
"read",
@@ -201,7 +202,7 @@ void ScriptApiSecurity::initializeSecurity()
copy_safe(L, io_whitelist, sizeof(io_whitelist));
// And replace unsafe ones
- SECURE_API(io, open);
+ //SECURE_API(io, open);
SECURE_API(io, input);
SECURE_API(io, output);
SECURE_API(io, lines);
@@ -320,7 +321,6 @@ void ScriptApiSecurity::initializeSecurityClient()
"getinfo", // used by builtin and unset before mods load
"traceback"
};
-
#if USE_LUAJIT
static const char *jit_whitelist[] = {
"arch",
@@ -340,6 +340,10 @@ void ScriptApiSecurity::initializeSecurityClient()
lua_State *L = getStack();
int thread = getThread(L);
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
// create an empty environment
createEmptyEnv(L);
@@ -356,8 +360,6 @@ void ScriptApiSecurity::initializeSecurityClient()
SECURE_API(g, require);
lua_pop(L, 2);
-
-
// Copy safe OS functions
lua_getglobal(L, "os");
lua_newtable(L);
@@ -372,6 +374,7 @@ void ScriptApiSecurity::initializeSecurityClient()
copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
lua_setfield(L, -3, "debug");
lua_pop(L, 1); // Pop old debug
+
#if USE_LUAJIT
// Copy safe jit functions, if they exist
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index 32f6a2793..3f1b89085 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -28,6 +28,8 @@ set(common_SCRIPT_LUA_API_SRCS
set(client_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_camera.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_clientobject.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_inventoryaction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_localplayer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_minimap.cpp
diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp
index f842671b8..fce6282a5 100644
--- a/src/script/lua_api/l_base.cpp
+++ b/src/script/lua_api/l_base.cpp
@@ -55,6 +55,11 @@ Client *ModApiBase::getClient(lua_State *L)
{
return getScriptApiBase(L)->getClient();
}
+
+Game *ModApiBase::getGame(lua_State *L)
+{
+ return getScriptApiBase(L)->getGame();
+}
#endif
IGameDef *ModApiBase::getGameDef(lua_State *L)
diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h
index aa5905d26..9ba50dabf 100644
--- a/src/script/lua_api/l_base.h
+++ b/src/script/lua_api/l_base.h
@@ -32,6 +32,7 @@ extern "C" {
#ifndef SERVER
class Client;
+class Game;
class GUIEngine;
#endif
@@ -47,11 +48,11 @@ public:
static ServerInventoryManager *getServerInventoryMgr(lua_State *L);
#ifndef SERVER
static Client* getClient(lua_State *L);
+ static Game* getGame(lua_State *L);
static GUIEngine* getGuiEngine(lua_State *L);
#endif // !SERVER
static IGameDef* getGameDef(lua_State *L);
-
static Environment* getEnv(lua_State *L);
// When we are not loading the mod, this function returns "."
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
index aaced7cd0..265c7d3fc 100644
--- a/src/script/lua_api/l_client.cpp
+++ b/src/script/lua_api/l_client.cpp
@@ -24,16 +24,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/clientevent.h"
#include "client/sound.h"
#include "client/clientenvironment.h"
+#include "client/game.h"
#include "common/c_content.h"
#include "common/c_converter.h"
#include "cpp_api/s_base.h"
#include "gettext.h"
#include "l_internal.h"
+#include "l_clientobject.h"
#include "lua_api/l_nodemeta.h"
#include "gui/mainmenumanager.h"
#include "map.h"
#include "util/string.h"
#include "nodedef.h"
+#include "client/keycode.h"
#define checkCSMRestrictionFlag(flag) \
( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
@@ -414,6 +417,253 @@ int ModApiClient::l_get_csm_restrictions(lua_State *L)
return 1;
}
+// send_damage(damage)
+int ModApiClient::l_send_damage(lua_State *L)
+{
+ u16 damage = luaL_checknumber(L, 1);
+ getClient(L)->sendDamage(damage);
+ return 0;
+}
+
+// place_node(pos)
+int ModApiClient::l_place_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ ClientMap &map = client->getEnv().getClientMap();
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ ItemStack selected_item, hand_item;
+ player->getWieldedItem(&selected_item, &hand_item);
+ const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ NodeMetadata *meta = map.getNodeMetadata(pos);
+ g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta, true);
+ return 0;
+}
+
+// dig_node(pos)
+int ModApiClient::l_dig_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ client->interact(INTERACT_START_DIGGING, pointed);
+ client->interact(INTERACT_DIGGING_COMPLETED, pointed);
+ client->removeNode(pos);
+ return 0;
+}
+
+// get_inventory(location)
+int ModApiClient::l_get_inventory(lua_State *L)
+{
+ Client *client = getClient(L);
+ InventoryLocation inventory_location;
+ Inventory *inventory;
+ std::string location;
+
+ location = readParam<std::string>(L, 1);
+
+ try {
+ inventory_location.deSerialize(location);
+ inventory = client->getInventory(inventory_location);
+ if (! inventory)
+ throw SerializationError(std::string("Attempt to access nonexistant inventory (") + location + ")");
+ push_inventory_lists(L, *inventory);
+ } catch (SerializationError &) {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+// set_keypress(key_setting, pressed) -> returns true on success
+int ModApiClient::l_set_keypress(lua_State *L)
+{
+ std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
+ bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
+ try {
+ KeyPress keyCode = getKeySetting(setting_name.c_str());
+ if (pressed)
+ g_game->input->setKeypress(keyCode);
+ else
+ g_game->input->unsetKeypress(keyCode);
+ lua_pushboolean(L, true);
+ } catch (SettingNotFoundException &) {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// drop_selected_item()
+int ModApiClient::l_drop_selected_item(lua_State *L)
+{
+ g_game->dropSelectedItem();
+ return 0;
+}
+
+// get_objects_inside_radius(pos, radius)
+int ModApiClient::l_get_objects_inside_radius(lua_State *L)
+{
+ ClientEnvironment &env = getClient(L)->getEnv();
+
+ v3f pos = checkFloatPos(L, 1);
+ float radius = readParam<float>(L, 2) * BS;
+
+ std::vector<DistanceSortedActiveObject> objs;
+ env.getActiveObjects(pos, radius, objs);
+
+ int i = 0;
+ lua_createtable(L, objs.size(), 0);
+ for (const auto obj : objs) {
+ push_objectRef(L, obj.obj->getId());
+ lua_rawseti(L, -2, ++i);
+ }
+ return 1;
+}
+
+// make_screenshot()
+int ModApiClient::l_make_screenshot(lua_State *L)
+{
+ getClient(L)->makeScreenshot();
+ return 0;
+}
+
+/*
+`pointed_thing`
+---------------
+
+* `{type="nothing"}`
+* `{type="node", under=pos, above=pos}`
+ * Indicates a pointed node selection box.
+ * `under` refers to the node position behind the pointed face.
+ * `above` refers to the node position in front of the pointed face.
+* `{type="object", ref=ObjectRef}`
+
+Exact pointing location (currently only `Raycast` supports these fields):
+
+* `pointed_thing.intersection_point`: The absolute world coordinates of the
+ point on the selection box which is pointed at. May be in the selection box
+ if the pointer is in the box too.
+* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
+ from 1).
+* `pointed_thing.intersection_normal`: Unit vector, points outwards of the
+ selected selection box. This specifies which face is pointed at.
+ Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the
+ selection box.
+*/
+
+// interact(action, pointed_thing)
+int ModApiClient::l_interact(lua_State *L)
+{
+ std::string action_str = readParam<std::string>(L, 1);
+ InteractAction action;
+
+ if (action_str == "start_digging")
+ action = INTERACT_START_DIGGING;
+ else if (action_str == "stop_digging")
+ action = INTERACT_STOP_DIGGING;
+ else if (action_str == "digging_completed")
+ action = INTERACT_DIGGING_COMPLETED;
+ else if (action_str == "place")
+ action = INTERACT_PLACE;
+ else if (action_str == "use")
+ action = INTERACT_USE;
+ else if (action_str == "activate")
+ action = INTERACT_ACTIVATE;
+ else
+ return 0;
+
+ lua_getfield(L, 2, "type");
+ if (! lua_isstring(L, -1))
+ return 0;
+ std::string type_str = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ PointedThingType type;
+
+ if (type_str == "nothing")
+ type = POINTEDTHING_NOTHING;
+ else if (type_str == "node")
+ type = POINTEDTHING_NODE;
+ else if (type_str == "object")
+ type = POINTEDTHING_OBJECT;
+ else
+ return 0;
+
+ PointedThing pointed;
+ pointed.type = type;
+ ClientObjectRef *obj;
+
+ switch (type) {
+ case POINTEDTHING_NODE:
+ lua_getfield(L, 2, "under");
+ pointed.node_undersurface = check_v3s16(L, -1);
+
+ lua_getfield(L, 2, "above");
+ pointed.node_abovesurface = check_v3s16(L, -1);
+ break;
+ case POINTEDTHING_OBJECT:
+ lua_getfield(L, 2, "ref");
+ obj = ClientObjectRef::checkobject(L, -1);
+ pointed.object_id = obj->getClientActiveObject()->getId();
+ break;
+ default:
+ break;
+ }
+
+ getClient(L)->interact(action, pointed);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+StringMap *table_to_stringmap(lua_State *L, int index)
+{
+ StringMap *m = new StringMap;
+
+ lua_pushvalue(L, index);
+ lua_pushnil(L);
+
+ while (lua_next(L, -2)) {
+ lua_pushvalue(L, -2);
+ std::basic_string<char> key = lua_tostring(L, -1);
+ std::basic_string<char> value = lua_tostring(L, -2);
+ (*m)[key] = value;
+ lua_pop(L, 2);
+ }
+
+ lua_pop(L, 1);
+
+ return m;
+}
+
+// send_inventory_fields(formname, fields)
+// Only works if the inventory form was opened beforehand.
+int ModApiClient::l_send_inventory_fields(lua_State *L)
+{
+ std::string formname = luaL_checkstring(L, 1);
+ StringMap *fields = table_to_stringmap(L, 2);
+
+ getClient(L)->sendInventoryFields(formname, *fields);
+ return 0;
+}
+
+// send_nodemeta_fields(position, formname, fields)
+int ModApiClient::l_send_nodemeta_fields(lua_State *L)
+{
+ v3s16 pos = check_v3s16(L, 1);
+ std::string formname = luaL_checkstring(L, 2);
+ StringMap *m = table_to_stringmap(L, 3);
+
+ getClient(L)->sendNodemetaFields(pos, formname, *m);
+ return 0;
+}
+
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
@@ -441,4 +691,15 @@ void ModApiClient::Initialize(lua_State *L, int top)
API_FCT(get_builtin_path);
API_FCT(get_language);
API_FCT(get_csm_restrictions);
+ API_FCT(send_damage);
+ API_FCT(place_node);
+ API_FCT(dig_node);
+ API_FCT(get_inventory);
+ API_FCT(set_keypress);
+ API_FCT(drop_selected_item);
+ API_FCT(get_objects_inside_radius);
+ API_FCT(make_screenshot);
+ API_FCT(interact);
+ API_FCT(send_inventory_fields);
+ API_FCT(send_nodemeta_fields);
}
diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h
index 5dc3efdad..caf21f78e 100644
--- a/src/script/lua_api/l_client.h
+++ b/src/script/lua_api/l_client.h
@@ -105,6 +105,39 @@ private:
// get_csm_restrictions()
static int l_get_csm_restrictions(lua_State *L);
+ // send_damage(damage)
+ static int l_send_damage(lua_State *L);
+
+ // place_node(pos)
+ static int l_place_node(lua_State *L);
+
+ // dig_node(pos)
+ static int l_dig_node(lua_State *L);
+
+ // get_inventory(location)
+ static int l_get_inventory(lua_State *L);
+
+ // set_keypress(key_setting, pressed)
+ static int l_set_keypress(lua_State *L);
+
+ // drop_selected_item()
+ static int l_drop_selected_item(lua_State *L);
+
+ // get_objects_inside_radius(pos, radius)
+ static int l_get_objects_inside_radius(lua_State *L);
+
+ // make_screenshot()
+ static int l_make_screenshot(lua_State *L);
+
+ // interact(action, pointed_thing)
+ static int l_interact(lua_State *L);
+
+ // send_inventory_fields(formname, fields)
+ static int l_send_inventory_fields(lua_State *L);
+
+ // send_nodemeta_fields(position, formname, fields)
+ static int l_send_nodemeta_fields(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_clientobject.cpp b/src/script/lua_api/l_clientobject.cpp
new file mode 100644
index 000000000..d3739639a
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.cpp
@@ -0,0 +1,342 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "lua_api/l_clientobject.h"
+#include "l_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "client/client.h"
+#include "object_properties.h"
+#include "util/pointedthing.h"
+
+ClientActiveObject *ClientObjectRef::getClientActiveObject()
+{
+ return m_object;
+}
+
+ClientObjectRef *ClientObjectRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *userdata = luaL_checkudata(L, narg, className);
+ if (!userdata)
+ luaL_typerror(L, narg, className);
+ return *(ClientObjectRef **)userdata;
+}
+
+ClientActiveObject *ClientObjectRef::get_cao(ClientObjectRef *ref)
+{
+ ClientActiveObject *obj = ref->m_object;
+ return obj;
+}
+
+GenericCAO *ClientObjectRef::get_generic_cao(ClientObjectRef *ref, lua_State *L)
+{
+ ClientActiveObject *obj = get_cao(ref);
+ if (!obj)
+ return nullptr;
+ ClientEnvironment &env = getClient(L)->getEnv();
+ GenericCAO *gcao = env.getGenericCAO(obj->getId());
+ return gcao;
+}
+
+int ClientObjectRef::l_get_pos(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ ClientActiveObject *cao = get_cao(ref);
+ if (!cao)
+ return 0;
+ push_v3f(L, cao->getPosition() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_velocity(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ push_v3f(L, gcao->getVelocity() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_acceleration(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ push_v3f(L, gcao->getAcceleration() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_rotation(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ push_v3f(L, gcao->getRotation());
+ return 1;
+}
+
+int ClientObjectRef::l_is_player(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ lua_pushboolean(L, gcao->isPlayer());
+ return 1;
+}
+
+int ClientObjectRef::l_is_local_player(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ lua_pushboolean(L, gcao->isLocalPlayer());
+ return 1;
+}
+
+int ClientObjectRef::l_get_name(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ lua_pushstring(L, gcao->getName().c_str());
+ return 1;
+}
+
+int ClientObjectRef::l_get_attach(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ClientActiveObject *parent = gcao->getParent();
+ if (!parent)
+ return 0;
+ push_objectRef(L, parent->getId());
+ return 1;
+}
+
+int ClientObjectRef::l_get_nametag(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_nametag, use get_properties().nametag "
+ "instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushstring(L, props->nametag.c_str());
+ return 1;
+}
+
+int ClientObjectRef::l_get_item_textures(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_item_textures, use "
+ "get_properties().textures instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *props = gcao->getProperties();
+ lua_newtable(L);
+
+ for (std::string &texture : props->textures) {
+ lua_pushstring(L, texture.c_str());
+ }
+ return 1;
+}
+
+int ClientObjectRef::l_get_max_hp(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_max_hp, use get_properties().hp_max "
+ "instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushnumber(L, props->hp_max);
+ return 1;
+}
+
+int ClientObjectRef::l_get_properties(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *prop = gcao->getProperties();
+ push_object_properties(L, prop);
+ return 1;
+}
+
+int ClientObjectRef::l_set_properties(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties prop = *gcao->getProperties();
+ read_object_properties(L, 2, nullptr, &prop, getClient(L)->idef());
+ gcao->setProperties(prop);
+ return 1;
+}
+
+int ClientObjectRef::l_get_hp(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ lua_pushnumber(L, gcao->getHp());
+ return 1;
+}
+
+int ClientObjectRef::l_punch(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ getClient(L)->interact(INTERACT_START_DIGGING, pointed);
+ return 0;
+}
+
+int ClientObjectRef::l_rightclick(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ getClient(L)->interact(INTERACT_PLACE, pointed);
+ return 0;
+}
+
+int ClientObjectRef::l_remove(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ ClientActiveObject *cao = get_cao(ref);
+ if (!cao)
+ return 0;
+ getClient(L)->getEnv().removeActiveObject(cao->getId());
+
+ return 0;
+}
+
+int ClientObjectRef::l_set_nametag_images(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ gcao->nametag_images.clear();
+ if (lua_istable(L, 2)) {
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0) {
+ gcao->nametag_images.push_back(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
+ }
+ gcao->updateNametag();
+
+ return 0;
+}
+
+ClientObjectRef::ClientObjectRef(ClientActiveObject *object) : m_object(object)
+{
+}
+
+void ClientObjectRef::create(lua_State *L, ClientActiveObject *object)
+{
+ ClientObjectRef *o = new ClientObjectRef(object);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void ClientObjectRef::create(lua_State *L, s16 id)
+{
+ create(L, ((ClientEnvironment *)getEnv(L))->getActiveObject(id));
+}
+
+void ClientObjectRef::set_null(lua_State *L)
+{
+ ClientObjectRef *obj = checkobject(L, -1);
+ obj->m_object = nullptr;
+}
+
+int ClientObjectRef::gc_object(lua_State *L)
+{
+ ClientObjectRef *obj = *(ClientObjectRef **)(lua_touserdata(L, 1));
+ delete obj;
+ return 0;
+}
+
+// taken from LuaLocalPlayer
+void ClientObjectRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // Drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // Drop methodtable
+}
+
+const char ClientObjectRef::className[] = "ClientObjectRef";
+luaL_Reg ClientObjectRef::methods[] = {luamethod(ClientObjectRef, get_pos),
+ luamethod(ClientObjectRef, get_velocity),
+ luamethod(ClientObjectRef, get_acceleration),
+ luamethod(ClientObjectRef, get_rotation),
+ luamethod(ClientObjectRef, is_player),
+ luamethod(ClientObjectRef, is_local_player),
+ luamethod(ClientObjectRef, get_name),
+ luamethod(ClientObjectRef, get_attach),
+ luamethod(ClientObjectRef, get_nametag),
+ luamethod(ClientObjectRef, get_item_textures),
+ luamethod(ClientObjectRef, get_properties),
+ luamethod(ClientObjectRef, set_properties),
+ luamethod(ClientObjectRef, get_hp),
+ luamethod(ClientObjectRef, get_max_hp), luamethod(ClientObjectRef, punch),
+ luamethod(ClientObjectRef, rightclick),
+ luamethod(ClientObjectRef, remove),
+ luamethod(ClientObjectRef, set_nametag_images), {0, 0}};
diff --git a/src/script/lua_api/l_clientobject.h b/src/script/lua_api/l_clientobject.h
new file mode 100644
index 000000000..c4c95cb41
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.h
@@ -0,0 +1,106 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "lua_api/l_base.h"
+#include "client/clientobject.h"
+#include "client/content_cao.h"
+
+class ClientObjectRef : public ModApiBase
+{
+public:
+ ClientObjectRef(ClientActiveObject *object);
+
+ ~ClientObjectRef() = default;
+
+ ClientActiveObject *getClientActiveObject();
+
+ static void Register(lua_State *L);
+
+ static void create(lua_State *L, ClientActiveObject *object);
+ static void create(lua_State *L, s16 id);
+
+ static void set_null(lua_State *L);
+
+ static ClientObjectRef *checkobject(lua_State *L, int narg);
+
+private:
+ ClientActiveObject *m_object = nullptr;
+ static const char className[];
+ static luaL_Reg methods[];
+
+ static ClientActiveObject *get_cao(ClientObjectRef *ref);
+ static GenericCAO *get_generic_cao(ClientObjectRef *ref, lua_State *L);
+
+ static int gc_object(lua_State *L);
+
+ // get_pos(self)
+ // returns: {x=num, y=num, z=num}
+ static int l_get_pos(lua_State *L);
+
+ // get_velocity(self)
+ static int l_get_velocity(lua_State *L);
+
+ // get_acceleration(self)
+ static int l_get_acceleration(lua_State *L);
+
+ // get_rotation(self)
+ static int l_get_rotation(lua_State *L);
+
+ // is_player(self)
+ static int l_is_player(lua_State *L);
+
+ // is_local_player(self)
+ static int l_is_local_player(lua_State *L);
+
+ // get_name(self)
+ static int l_get_name(lua_State *L);
+
+ // get_attach(self)
+ static int l_get_attach(lua_State *L);
+
+ // get_nametag(self)
+ static int l_get_nametag(lua_State *L);
+
+ // get_item_textures(self)
+ static int l_get_item_textures(lua_State *L);
+
+ // get_properties(self)
+ static int l_get_properties(lua_State *L);
+
+ // set_properties(self, properties)
+ static int l_set_properties(lua_State *L);
+
+ // get_hp(self)
+ static int l_get_hp(lua_State *L);
+
+ // get_max_hp(self)
+ static int l_get_max_hp(lua_State *L);
+
+ // punch(self)
+ static int l_punch(lua_State *L);
+
+ // rightclick(self)
+ static int l_rightclick(lua_State *L);
+
+ // remove(self)
+ static int l_remove(lua_State *L);
+
+ // set_nametag_images(self, images)
+ static int l_set_nametag_images(lua_State *L);
+};
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 7640f2782..a489d245c 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -857,7 +857,6 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
int radius = luaL_checkinteger(L, 2);
std::vector<content_t> filter;
collectNodeIds(L, 3, ndef, filter);
-
int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
#ifndef SERVER
@@ -880,6 +879,165 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
return 0;
}
+// find_nodes_near(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it != filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
+// find_nodes_near_under_air(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ v3s16 psurf(p.X, p.Y + 1, p.Z);
+ content_t csurf = map.getNode(psurf).getContent();
+ if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+ continue;
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it != filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
+// find_nodes_near_under_air_except(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ v3s16 psurf(p.X, p.Y + 1, p.Z);
+ content_t csurf = map.getNode(psurf).getContent();
+ if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+ continue;
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it == filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
static void checkArea(v3s16 &minp, v3s16 &maxp)
{
auto volume = VoxelArea(minp, maxp).getVolume();
@@ -1285,7 +1443,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
// max_jump, max_drop, algorithm) -> table containing path
int ModApiEnvMod::l_find_path(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
v3s16 pos1 = read_v3s16(L, 1);
v3s16 pos2 = read_v3s16(L, 2);
@@ -1303,7 +1461,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
algo = PA_DIJKSTRA;
}
- std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2,
+ std::vector<v3s16> path = get_path(&env->getMap(), env->getGameDef()->ndef(), pos1, pos2,
searchdistance, max_jump, max_drop, algo);
if (!path.empty()) {
@@ -1504,8 +1662,13 @@ void ModApiEnvMod::InitializeClient(lua_State *L, int top)
API_FCT(get_node_level);
API_FCT(find_nodes_with_meta);
API_FCT(find_node_near);
+ API_FCT(find_nodes_near);
+ API_FCT(find_nodes_near_under_air);
+ API_FCT(find_nodes_near_under_air_except);
API_FCT(find_nodes_in_area);
API_FCT(find_nodes_in_area_under_air);
+ API_FCT(get_voxel_manip);
+ API_FCT(find_path);
API_FCT(line_of_sight);
API_FCT(raycast);
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index a7d406d2a..70a8d2398 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -134,6 +134,18 @@ private:
// find_node_near(pos, radius, nodenames, search_center) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_node_near(lua_State *L);
+
+ // find_nodes_near(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near(lua_State *L);
+
+ // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near_under_air(lua_State *L);
+
+ // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near_under_air_except(lua_State *L);
// find_nodes_in_area(minp, maxp, nodenames) -> list of positions
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
diff --git a/src/script/lua_api/l_inventoryaction.cpp b/src/script/lua_api/l_inventoryaction.cpp
new file mode 100644
index 000000000..f65137465
--- /dev/null
+++ b/src/script/lua_api/l_inventoryaction.cpp
@@ -0,0 +1,215 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "l_inventoryaction.h"
+#include "l_internal.h"
+#include "client/client.h"
+
+int LuaInventoryAction::gc_object(lua_State *L)
+{
+ LuaInventoryAction *o = *(LuaInventoryAction **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+int LuaInventoryAction::mt_tostring(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+ std::ostringstream os(std::ios::binary);
+ o->m_action->serialize(os);
+ lua_pushfstring(L, "InventoryAction(\"%s\")", os.str().c_str());
+ return 1;
+}
+
+int LuaInventoryAction::l_apply(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ std::ostringstream os(std::ios::binary);
+ o->m_action->serialize(os);
+
+ std::istringstream is(os.str(), std::ios_base::binary);
+
+ InventoryAction *a = InventoryAction::deSerialize(is);
+
+ getClient(L)->inventoryAction(a);
+ return 0;
+}
+
+int LuaInventoryAction::l_from(lua_State *L)
+{
+ GET_MOVE_ACTION
+ readFullInventoryLocationInto(L, &act->from_inv, &act->from_list, &act->from_i);
+ return 0;
+}
+
+int LuaInventoryAction::l_to(lua_State *L)
+{
+ GET_MOVE_ACTION
+ readFullInventoryLocationInto(L, &act->to_inv, &act->to_list, &act->to_i);
+ return 0;
+}
+
+int LuaInventoryAction::l_craft(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ if (o->m_action->getType() != IAction::Craft)
+ return 0;
+
+ std::string locStr;
+ InventoryLocation loc;
+
+ locStr = readParam<std::string>(L, 2);
+
+ try {
+ loc.deSerialize(locStr);
+ dynamic_cast<ICraftAction *>(o->m_action)->craft_inv = loc;
+ } catch (SerializationError &) {
+ }
+
+ return 0;
+}
+
+int LuaInventoryAction::l_set_count(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ s16 count = luaL_checkinteger(L, 2);
+
+ switch (o->m_action->getType()) {
+ case IAction::Move:
+ ((IMoveAction *)o->m_action)->count = count;
+ break;
+ case IAction::Drop:
+ ((IDropAction *)o->m_action)->count = count;
+ break;
+ case IAction::Craft:
+ ((ICraftAction *)o->m_action)->count = count;
+ break;
+ }
+
+ return 0;
+}
+
+LuaInventoryAction::LuaInventoryAction(const IAction &type) : m_action(nullptr)
+{
+ switch (type) {
+ case IAction::Move:
+ m_action = new IMoveAction();
+ break;
+ case IAction::Drop:
+ m_action = new IDropAction();
+ break;
+ case IAction::Craft:
+ m_action = new ICraftAction();
+ break;
+ }
+}
+
+LuaInventoryAction::~LuaInventoryAction()
+{
+ delete m_action;
+}
+
+void LuaInventoryAction::readFullInventoryLocationInto(
+ lua_State *L, InventoryLocation *loc, std::string *list, s16 *index)
+{
+ try {
+ loc->deSerialize(readParam<std::string>(L, 2));
+ std::string l = readParam<std::string>(L, 3);
+ *list = l;
+ *index = luaL_checkinteger(L, 4) - 1;
+ } catch (SerializationError &) {
+ }
+}
+
+int LuaInventoryAction::create_object(lua_State *L)
+{
+ IAction type;
+ std::string typeStr;
+
+ typeStr = readParam<std::string>(L, 1);
+
+ if (typeStr == "move")
+ type = IAction::Move;
+ else if (typeStr == "drop")
+ type = IAction::Drop;
+ else if (typeStr == "craft")
+ type = IAction::Craft;
+ else
+ return 0;
+
+ LuaInventoryAction *o = new LuaInventoryAction(type);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+int LuaInventoryAction::create(lua_State *L, const IAction &type)
+{
+ LuaInventoryAction *o = new LuaInventoryAction(type);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaInventoryAction *LuaInventoryAction::checkobject(lua_State *L, int narg)
+{
+ return *(LuaInventoryAction **)luaL_checkudata(L, narg, className);
+}
+
+void LuaInventoryAction::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__tostring");
+ lua_pushcfunction(L, mt_tostring);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1);
+
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
+
+ lua_register(L, className, create_object);
+}
+
+const char LuaInventoryAction::className[] = "InventoryAction";
+const luaL_Reg LuaInventoryAction::methods[] = {luamethod(LuaInventoryAction, apply),
+ luamethod(LuaInventoryAction, from), luamethod(LuaInventoryAction, to),
+ luamethod(LuaInventoryAction, craft),
+ luamethod(LuaInventoryAction, set_count), {0, 0}};
diff --git a/src/script/lua_api/l_inventoryaction.h b/src/script/lua_api/l_inventoryaction.h
new file mode 100644
index 000000000..a4cc6cbe5
--- /dev/null
+++ b/src/script/lua_api/l_inventoryaction.h
@@ -0,0 +1,74 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "inventorymanager.h"
+#include "lua_api/l_base.h"
+
+#define GET_MOVE_ACTION \
+ LuaInventoryAction *o = checkobject(L, 1); \
+ if (o->m_action->getType() == IAction::Craft) \
+ return 0; \
+ MoveAction *act = dynamic_cast<MoveAction *>(o->m_action);
+
+class LuaInventoryAction : public ModApiBase
+{
+private:
+ InventoryAction *m_action;
+
+ static void readFullInventoryLocationInto(lua_State *L, InventoryLocation *loc,
+ std::string *list, s16 *index);
+
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // __tostring metamethod
+ static int mt_tostring(lua_State *L);
+
+ // apply(self)
+ static int l_apply(lua_State *L);
+
+ // from(self, location, list, index)
+ static int l_from(lua_State *L);
+
+ // to(self, location, list, index)
+ static int l_to(lua_State *L);
+
+ // craft(self, location)
+ static int l_craft(lua_State *L);
+
+ // set_count(self, count)
+ static int l_set_count(lua_State *L);
+
+public:
+ LuaInventoryAction(const IAction &type);
+ ~LuaInventoryAction();
+
+ // LuaInventoryAction(inventory action type)
+ // Creates an LuaInventoryAction and leaves it on top of stack
+ static int create_object(lua_State *L);
+ // Not callable from Lua
+ static int create(lua_State *L, const IAction &type);
+ static LuaInventoryAction *checkobject(lua_State *L, int narg);
+ static void Register(lua_State *L);
+};
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index b58b994d9..9220259ff 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -28,7 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "inventory.h"
#include "log.h"
-
+#include "script/cpp_api/s_base.h"
+#ifndef SERVER
+#include "client/client.h"
+#include "client/renderingengine.h"
+#include "client/shader.h"
+#endif
// garbage collector
int LuaItemStack::gc_object(lua_State *L)
@@ -552,9 +557,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
// Get the writable item and node definition managers from the server
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
NodeDefManager *ndef =
- getServer(L)->getWritableNodeDefManager();
+ getGameDef(L)->getWritableNodeDefManager();
// Check if name is defined
std::string name;
@@ -602,8 +607,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
+ itos(MAX_REGISTERED_CONTENT+1)
+ ") exceeded (" + name + ")");
}
+
}
-
+
return 0; /* number of results */
}
@@ -614,12 +620,12 @@ int ModApiItemMod::l_unregister_item_raw(lua_State *L)
std::string name = luaL_checkstring(L, 1);
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
// Unregister the node
if (idef->get(name).type == ITEM_NODE) {
NodeDefManager *ndef =
- getServer(L)->getWritableNodeDefManager();
+ getGameDef(L)->getWritableNodeDefManager();
ndef->removeNode(name);
}
@@ -637,7 +643,7 @@ int ModApiItemMod::l_register_alias_raw(lua_State *L)
// Get the writable item definition manager from the server
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
idef->registerAlias(name, convert_to);
diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp
index 2efb976c7..1da0679d6 100644
--- a/src/script/lua_api/l_localplayer.cpp
+++ b/src/script/lua_api/l_localplayer.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "l_clientobject.h"
#include "l_localplayer.h"
#include "l_internal.h"
#include "lua_api/l_item.h"
@@ -24,7 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/localplayer.h"
#include "hud.h"
#include "common/c_content.h"
+#include "client/client.h"
#include "client/content_cao.h"
+#include "client/game.h"
LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m)
{
@@ -60,6 +63,57 @@ int LuaLocalPlayer::l_get_velocity(lua_State *L)
return 1;
}
+int LuaLocalPlayer::l_set_velocity(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ v3f pos = checkFloatPos(L, 2);
+ player->setSpeed(pos);
+
+ return 0;
+}
+
+int LuaLocalPlayer::l_get_yaw(lua_State *L)
+{
+ lua_pushnumber(L, wrapDegrees_0_360(g_game->cam_view.camera_yaw));
+ return 1;
+}
+
+int LuaLocalPlayer::l_set_yaw(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ if (lua_isnumber(L, 2)) {
+ double yaw = lua_tonumber(L, 2);
+ player->setYaw(yaw);
+ g_game->cam_view.camera_yaw = yaw;
+ g_game->cam_view_target.camera_yaw = yaw;
+ }
+
+ return 0;
+}
+
+int LuaLocalPlayer::l_get_pitch(lua_State *L)
+{
+ lua_pushnumber(L, -wrapDegrees_180(g_game->cam_view.camera_pitch) );
+ return 1;
+}
+
+int LuaLocalPlayer::l_set_pitch(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ if (lua_isnumber(L, 2)) {
+ double pitch = lua_tonumber(L, 2);
+ player->setPitch(pitch);
+ g_game->cam_view.camera_pitch = pitch;
+ g_game->cam_view_target.camera_pitch = pitch;
+ }
+
+ return 0;
+}
+
+
int LuaLocalPlayer::l_get_hp(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
@@ -81,10 +135,24 @@ int LuaLocalPlayer::l_get_wield_index(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
- lua_pushinteger(L, player->getWieldIndex());
+ lua_pushinteger(L, player->getWieldIndex() + 1);
return 1;
}
+// set_wield_index(self)
+int LuaLocalPlayer::l_set_wield_index(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ u32 index = luaL_checkinteger(L, 2) - 1;
+
+ player->setWieldIndex(index);
+ g_game->processItemSelection(&g_game->runData.new_playeritem);
+ ItemStack selected_item, hand_item;
+ ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
+ g_game->camera->wield(tool_item);
+ return 0;
+}
+
// get_wielded_item(self)
int LuaLocalPlayer::l_get_wielded_item(lua_State *L)
{
@@ -157,26 +225,30 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
- lua_newtable(L);
- lua_pushnumber(L, player->physics_override_speed);
- lua_setfield(L, -2, "speed");
+ push_physics_override(L, player->physics_override_speed, player->physics_override_jump, player->physics_override_gravity, player->physics_override_sneak, player->physics_override_sneak_glitch, player->physics_override_new_move);
- lua_pushnumber(L, player->physics_override_jump);
- lua_setfield(L, -2, "jump");
-
- lua_pushnumber(L, player->physics_override_gravity);
- lua_setfield(L, -2, "gravity");
-
- lua_pushboolean(L, player->physics_override_sneak);
- lua_setfield(L, -2, "sneak");
+ return 1;
+}
- lua_pushboolean(L, player->physics_override_sneak_glitch);
- lua_setfield(L, -2, "sneak_glitch");
+// set_physics_override(self, override)
+int LuaLocalPlayer::l_set_physics_override(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
- lua_pushboolean(L, player->physics_override_new_move);
- lua_setfield(L, -2, "new_move");
+ player->physics_override_speed = getfloatfield_default(
+ L, 2, "speed", player->physics_override_speed);
+ player->physics_override_jump = getfloatfield_default(
+ L, 2, "jump", player->physics_override_jump);
+ player->physics_override_gravity = getfloatfield_default(
+ L, 2, "gravity", player->physics_override_gravity);
+ player->physics_override_sneak = getboolfield_default(
+ L, 2, "sneak", player->physics_override_sneak);
+ player->physics_override_sneak_glitch = getboolfield_default(
+ L, 2, "sneak_glitch", player->physics_override_sneak_glitch);
+ player->physics_override_new_move = getboolfield_default(
+ L, 2, "new_move", player->physics_override_new_move);
- return 1;
+ return 0;
}
int LuaLocalPlayer::l_get_last_pos(lua_State *L)
@@ -261,6 +333,17 @@ int LuaLocalPlayer::l_get_pos(lua_State *L)
return 1;
}
+// set_pos(self, pos)
+int LuaLocalPlayer::l_set_pos(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ v3f pos = checkFloatPos(L, 2);
+ player->setPosition(pos);
+ getClient(L)->sendPlayerPos();
+ return 0;
+}
+
// get_movement_acceleration(self)
int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L)
{
@@ -400,6 +483,27 @@ int LuaLocalPlayer::l_hud_get(lua_State *L)
return 1;
}
+// get_object(self)
+int LuaLocalPlayer::l_get_object(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ ClientEnvironment &env = getClient(L)->getEnv();
+ ClientActiveObject *obj = env.getGenericCAO(player->getCAO()->getId());
+
+ push_objectRef(L, obj->getId());
+
+ return 1;
+}
+
+// get_hotbar_size(self)
+int LuaLocalPlayer::l_get_hotbar_size(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ lua_pushnumber(L, player->hud_hotbar_itemcount);
+
+ return 1;
+}
+
LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
@@ -460,9 +564,15 @@ void LuaLocalPlayer::Register(lua_State *L)
const char LuaLocalPlayer::className[] = "LocalPlayer";
const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, get_velocity),
+ luamethod(LuaLocalPlayer, set_velocity),
+ luamethod(LuaLocalPlayer, get_yaw),
+ luamethod(LuaLocalPlayer, set_yaw),
+ luamethod(LuaLocalPlayer, get_pitch),
+ luamethod(LuaLocalPlayer, set_pitch),
luamethod(LuaLocalPlayer, get_hp),
luamethod(LuaLocalPlayer, get_name),
luamethod(LuaLocalPlayer, get_wield_index),
+ luamethod(LuaLocalPlayer, set_wield_index),
luamethod(LuaLocalPlayer, get_wielded_item),
luamethod(LuaLocalPlayer, is_attached),
luamethod(LuaLocalPlayer, is_touching_ground),
@@ -471,6 +581,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, is_climbing),
luamethod(LuaLocalPlayer, swimming_vertical),
luamethod(LuaLocalPlayer, get_physics_override),
+ luamethod(LuaLocalPlayer, set_physics_override),
// TODO: figure our if these are useful in any way
luamethod(LuaLocalPlayer, get_last_pos),
luamethod(LuaLocalPlayer, get_last_velocity),
@@ -480,6 +591,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, get_control),
luamethod(LuaLocalPlayer, get_breath),
luamethod(LuaLocalPlayer, get_pos),
+ luamethod(LuaLocalPlayer, set_pos),
luamethod(LuaLocalPlayer, get_movement_acceleration),
luamethod(LuaLocalPlayer, get_movement_speed),
luamethod(LuaLocalPlayer, get_movement),
@@ -488,6 +600,8 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, hud_remove),
luamethod(LuaLocalPlayer, hud_change),
luamethod(LuaLocalPlayer, hud_get),
+ luamethod(LuaLocalPlayer, get_object),
+ luamethod(LuaLocalPlayer, get_hotbar_size),
luamethod(LuaLocalPlayer, get_move_resistance),
diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h
index 041545a49..458c824e6 100644
--- a/src/script/lua_api/l_localplayer.h
+++ b/src/script/lua_api/l_localplayer.h
@@ -35,6 +35,21 @@ private:
// get_velocity(self)
static int l_get_velocity(lua_State *L);
+ // set_velocity(self, vel)
+ static int l_set_velocity(lua_State *L);
+
+ // get_yaw(self)
+ static int l_get_yaw(lua_State *L);
+
+ // set_yaw(self, yaw)
+ static int l_set_yaw(lua_State *L);
+
+ // get_pitch(self)
+ static int l_get_pitch(lua_State *L);
+
+ // set_pitch(self,pitch)
+ static int l_set_pitch(lua_State *L);
+
// get_hp(self)
static int l_get_hp(lua_State *L);
@@ -44,9 +59,15 @@ private:
// get_wield_index(self)
static int l_get_wield_index(lua_State *L);
+ // set_wield_index(self)
+ static int l_set_wield_index(lua_State *L);
+
// get_wielded_item(self)
static int l_get_wielded_item(lua_State *L);
+ // get_hotbar_size(self)
+ static int l_get_hotbar_size(lua_State *L);
+
static int l_is_attached(lua_State *L);
static int l_is_touching_ground(lua_State *L);
static int l_is_in_liquid(lua_State *L);
@@ -55,6 +76,7 @@ private:
static int l_swimming_vertical(lua_State *L);
static int l_get_physics_override(lua_State *L);
+ static int l_set_physics_override(lua_State *L);
static int l_get_override_pos(lua_State *L);
@@ -72,6 +94,9 @@ private:
// get_pos(self)
static int l_get_pos(lua_State *L);
+ // set_pos(self, pos)
+ static int l_set_pos(lua_State *L);
+
// get_movement_acceleration(self)
static int l_get_movement_acceleration(lua_State *L);
@@ -97,6 +122,9 @@ private:
static int l_get_move_resistance(lua_State *L);
+ // get_object(self)
+ static int l_get_object(lua_State *L);
+
LocalPlayer *m_localplayer = nullptr;
public:
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index db031dde5..2b46a4d51 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -705,6 +705,10 @@ bool ModApiMainMenu::mayModifyPath(std::string path)
if (fs::PathStartsWith(path, path_user + DIR_DELIM "client"))
return true;
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "clientmods"))
+ return true;
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures"))
+ return true;
if (fs::PathStartsWith(path, path_user + DIR_DELIM "games"))
return true;
if (fs::PathStartsWith(path, path_user + DIR_DELIM "mods"))
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 4b0b45887..e8105dd75 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -336,6 +336,7 @@ int ModApiServer::l_disconnect_player(lua_State *L)
return 1;
}
+// remove_player(name)
int ModApiServer::l_remove_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 97068ce4c..fa749c2e5 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -640,6 +640,8 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(compress);
API_FCT(decompress);
+ API_FCT(request_insecure_environment);
+
API_FCT(encode_base64);
API_FCT(decode_base64);
@@ -647,6 +649,9 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(sha1);
API_FCT(colorspec_to_colorstring);
API_FCT(colorspec_to_bytes);
+
+ LuaSettings::create(L, g_settings, g_settings_path);
+ lua_setfield(L, top, "settings");
}
void ModApiUtil::InitializeAsync(lua_State *L, int top)
diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp
index 6643a9509..c30de9ee8 100644
--- a/src/script/scripting_client.cpp
+++ b/src/script/scripting_client.cpp
@@ -20,9 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "scripting_client.h"
#include "client/client.h"
+#include "client/game.h"
#include "cpp_api/s_internal.h"
#include "lua_api/l_client.h"
+#include "lua_api/l_clientobject.h"
#include "lua_api/l_env.h"
+#include "lua_api/l_inventoryaction.h"
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_minimap.h"
@@ -33,13 +36,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_util.h"
#include "lua_api/l_item.h"
#include "lua_api/l_nodemeta.h"
+#include "lua_api/l_noise.h"
#include "lua_api/l_localplayer.h"
#include "lua_api/l_camera.h"
+#include "lua_api/l_settings.h"
+#include "lua_api/l_http.h"
+#include "lua_api/l_vmanip.h"
ClientScripting::ClientScripting(Client *client):
ScriptApiBase(ScriptingType::Client)
{
setGameDef(client);
+ setGame(g_game);
SCRIPTAPI_PRECHECKHEADER
@@ -65,6 +73,11 @@ ClientScripting::ClientScripting(Client *client):
void ClientScripting::InitializeModApi(lua_State *L, int top)
{
LuaItemStack::Register(L);
+ LuaPerlinNoise::Register(L);
+ LuaPerlinNoiseMap::Register(L);
+ LuaPseudoRandom::Register(L);
+ LuaPcgRandom::Register(L);
+ LuaSecureRandom::Register(L);
ItemStackMetaRef::Register(L);
LuaRaycast::Register(L);
StorageRef::Register(L);
@@ -73,8 +86,14 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
LuaLocalPlayer::Register(L);
LuaCamera::Register(L);
ModChannelRef::Register(L);
+ LuaSettings::Register(L);
+ ClientObjectRef::Register(L);
+ LuaInventoryAction::Register(L);
+ LuaVoxelManip::Register(L);
+ ModApiItemMod::Initialize(L, top);
ModApiUtil::InitializeClient(L, top);
+ ModApiHttp::Initialize(L, top);
ModApiClient::Initialize(L, top);
ModApiStorage::Initialize(L, top);
ModApiEnvMod::InitializeClient(L, top);
diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h
index 3088029f0..e162f8bcf 100644
--- a/src/script/scripting_client.h
+++ b/src/script/scripting_client.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_base.h"
#include "cpp_api/s_client.h"
+#include "cpp_api/s_cheats.h"
#include "cpp_api/s_modchannels.h"
#include "cpp_api/s_security.h"
@@ -34,7 +35,8 @@ class ClientScripting:
virtual public ScriptApiBase,
public ScriptApiSecurity,
public ScriptApiClient,
- public ScriptApiModChannels
+ public ScriptApiModChannels,
+ public ScriptApiCheats
{
public:
ClientScripting(Client *client);