51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <algorithm>
#include "lua_api/l_env.h"
#include "lua_api/l_internal.h"
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
-#include <algorithm>
#include "scripting_server.h"
#include "environment.h"
#include "mapblock.h"
#include "nodedef.h"
#include "daynightratio.h"
#include "util/pointedthing.h"
-#include "content_sao.h"
#include "mapgen/treegen.h"
#include "emerge.h"
#include "pathfinder.h"
#include "face_position_cache.h"
#include "remoteplayer.h"
+#include "server/luaentity_sao.h"
+#include "server/player_sao.h"
+#include "util/string.h"
+#include "translation.h"
#ifndef SERVER
-#include "client.h"
+#include "client/client.h"
#endif
-struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
-{
- {CLEAR_OBJECTS_MODE_FULL, "full"},
- {CLEAR_OBJECTS_MODE_QUICK, "quick"},
- {0, NULL},
+struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = {
+ {CLEAR_OBJECTS_MODE_FULL, "full"},
+ {CLEAR_OBJECTS_MODE_QUICK, "quick"},
+ {0, NULL},
};
///////////////////////////////////////////////////////////////////////////////
-
-void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
- u32 active_object_count, u32 active_object_count_wider)
+void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count,
+ u32 active_object_count_wider)
{
ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_remove(L, -2); // Remove core
// Get registered_abms[m_id]
- lua_pushnumber(L, m_id);
+ lua_pushinteger(L, m_id);
lua_gettable(L, -2);
- if(lua_isnil(L, -1))
+ if (lua_isnil(L, -1))
FATAL_ERROR("");
lua_remove(L, -2); // Remove registered_abms
lua_remove(L, -2); // Remove core
// Get registered_lbms[m_id]
- lua_pushnumber(L, m_id);
+ lua_pushinteger(L, m_id);
lua_gettable(L, -2);
- FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table");
+ FATAL_ERROR_IF(lua_isnil(L, -1),
+ "Entry with given id not found in registered_lbms table");
lua_remove(L, -2); // Remove registered_lbms
scriptIface->setOriginFromTable(-1);
int LuaRaycast::l_next(lua_State *L)
{
- MAP_LOCK_REQUIRED;
+ GET_PLAIN_ENV_PTR;
- ScriptApiItem *script = getScriptApi<ScriptApiItem>(L);
- GET_ENV_PTR;
+ bool csm = false;
+#ifndef SERVER
+ csm = getClient(L) != nullptr;
+#endif
LuaRaycast *o = checkobject(L, 1);
PointedThing pointed;
if (pointed.type == POINTEDTHING_NOTHING)
lua_pushnil(L);
else
- script->pushPointedThing(pointed);
+ push_pointed_thing(L, pointed, csm, true);
return 1;
}
v3f pos1 = checkFloatPos(L, 1);
v3f pos2 = checkFloatPos(L, 2);
if (lua_isboolean(L, 3)) {
- objects = lua_toboolean(L, 3);
+ objects = readParam<bool>(L, 3);
}
if (lua_isboolean(L, 4)) {
- liquids = lua_toboolean(L, 4);
+ liquids = readParam<bool>(L, 4);
}
- LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
- objects, liquids);
+ LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2), objects, liquids);
- *(void **) (lua_newuserdata(L, sizeof(void *))) = o;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
void *ud = luaL_checkudata(L, narg, className);
if (!ud)
luaL_typerror(L, narg, className);
- return *(LuaRaycast **) ud;
+ return *(LuaRaycast **)ud;
}
int LuaRaycast::gc_object(lua_State *L)
{
- LuaRaycast *o = *(LuaRaycast **) (lua_touserdata(L, 1));
+ LuaRaycast *o = *(LuaRaycast **)(lua_touserdata(L, 1));
delete o;
return 0;
}
}
const char LuaRaycast::className[] = "Raycast";
-const luaL_Reg LuaRaycast::methods[] =
-{
- luamethod(LuaRaycast, next),
- { 0, 0 }
-};
+const luaL_Reg LuaRaycast::methods[] = {luamethod(LuaRaycast, next), {0, 0}};
void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
{
{
GET_ENV_PTR;
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
// parameters
v3s16 pos = read_v3s16(L, 1);
MapNode n = readnode(L, 2, ndef);
return 1;
}
+// bulk_set_node([pos1, pos2, ...], node)
+// pos = {x=num, y=num, z=num}
+int ModApiEnvMod::l_bulk_set_node(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ // parameters
+ if (!lua_istable(L, 1)) {
+ return 0;
+ }
+
+ s32 len = lua_objlen(L, 1);
+ if (len == 0) {
+ lua_pushboolean(L, true);
+ return 1;
+ }
+
+ MapNode n = readnode(L, 2, ndef);
+
+ // Do it
+ bool succeeded = true;
+ for (s32 i = 1; i <= len; i++) {
+ lua_rawgeti(L, 1, i);
+ if (!env->setNode(read_v3s16(L, -1), n))
+ succeeded = false;
+ lua_pop(L, 1);
+ }
+
+ lua_pushboolean(L, succeeded);
+ return 1;
+}
+
int ModApiEnvMod::l_add_node(lua_State *L)
{
return l_set_node(L);
{
GET_ENV_PTR;
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
// parameters
v3s16 pos = read_v3s16(L, 1);
MapNode n = readnode(L, 2, ndef);
// pos
v3s16 pos = read_v3s16(L, 1);
// Do it
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
// Return node
pushnode(L, n, env->getGameDef()->ndef());
return 1;
v3s16 pos = read_v3s16(L, 1);
// Do it
bool pos_ok;
- MapNode n = env->getMap().getNodeNoEx(pos, &pos_ok);
+ MapNode n = env->getMap().getNode(pos, &pos_ok);
if (pos_ok) {
// Return node
pushnode(L, n, env->getGameDef()->ndef());
// timeofday: nil = current time, 0 = night, 0.5 = day
int ModApiEnvMod::l_get_node_light(lua_State *L)
{
- GET_ENV_PTR;
+ GET_PLAIN_ENV_PTR;
// Do it
v3s16 pos = read_v3s16(L, 1);
u32 time_of_day = env->getTimeOfDay();
- if(lua_isnumber(L, 2))
+ if (lua_isnumber(L, 2))
time_of_day = 24000.0 * lua_tonumber(L, 2);
time_of_day %= 24000;
u32 dnr = time_to_daynight_ratio(time_of_day, true);
bool is_position_ok;
- MapNode n = env->getMap().getNodeNoEx(pos, &is_position_ok);
+ MapNode n = env->getMap().getNode(pos, &is_position_ok);
if (is_position_ok) {
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
lua_pushinteger(L, n.getLightBlend(dnr, ndef));
} else {
lua_pushnil(L);
ScriptApiItem *scriptIfaceItem = getScriptApi<ScriptApiItem>(L);
Server *server = getServer(L);
- INodeDefManager *ndef = server->ndef();
+ const NodeDefManager *ndef = server->ndef();
IItemDefManager *idef = server->idef();
v3s16 pos = read_v3s16(L, 1);
MapNode n = readnode(L, 2, ndef);
// Don't attempt to load non-loaded area as of now
- MapNode n_old = env->getMap().getNodeNoEx(pos);
- if(n_old.getContent() == CONTENT_IGNORE){
+ MapNode n_old = env->getMap().getNode(pos);
+ if (n_old.getContent() == CONTENT_IGNORE) {
lua_pushboolean(L, false);
return 1;
}
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;
pointed.node_abovesurface = pos;
- pointed.node_undersurface = pos + v3s16(0,-1,0);
+ pointed.node_undersurface = pos + v3s16(0, -1, 0);
// Place it with a NULL placer (appears in Lua as nil)
bool success = scriptIfaceItem->item_OnPlace(item, nullptr, pointed);
lua_pushboolean(L, success);
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
- if(n.getContent() == CONTENT_IGNORE){
+ MapNode n = env->getMap().getNode(pos);
+ if (n.getContent() == CONTENT_IGNORE) {
lua_pushboolean(L, false);
return 1;
}
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
- if(n.getContent() == CONTENT_IGNORE){
+ MapNode n = env->getMap().getNode(pos);
+ if (n.getContent() == CONTENT_IGNORE) {
lua_pushboolean(L, false);
return 1;
}
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_max_level(lua_State *L)
{
- Environment *env = getEnv(L);
- if (!env) {
- return 0;
- }
+ GET_PLAIN_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
return 1;
}
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_level(lua_State *L)
{
- Environment *env = getEnv(L);
- if (!env) {
- return 0;
- }
+ GET_PLAIN_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
return 1;
}
v3s16 pos = read_v3s16(L, 1);
u8 level = 1;
- if(lua_isnumber(L, 2))
+ if (lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level));
env->setNode(pos, n);
return 1;
// add_node_level(pos, level)
// pos = {x=num, y=num, z=num}
-// level: 0..63
+// level: -127..127
int ModApiEnvMod::l_add_node_level(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
- u8 level = 1;
- if(lua_isnumber(L, 2))
+ s16 level = 1;
+ if (lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
env->setNode(pos, n);
return 1;
// find_nodes_with_meta(pos1, pos2)
int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L)
{
- GET_ENV_PTR;
+ GET_PLAIN_ENV_PTR;
std::vector<v3s16> positions = env->getMap().findNodesWithMetadata(
- check_v3s16(L, 1), check_v3s16(L, 2));
+ check_v3s16(L, 1), check_v3s16(L, 2));
- lua_newtable(L);
+ lua_createtable(L, positions.size(), 0);
for (size_t i = 0; i != positions.size(); i++) {
push_v3s16(L, positions[i]);
lua_rawseti(L, -2, i + 1);
// Do it
v3s16 p = read_v3s16(L, 1);
- NodeTimerRef::create(L, p, env);
+ NodeTimerRef::create(L, p, &env->getServerMap());
return 1;
}
{
GET_ENV_PTR;
- // pos
v3f pos = checkFloatPos(L, 1);
- // content
const char *name = luaL_checkstring(L, 2);
- // staticdata
const char *staticdata = luaL_optstring(L, 3, "");
- // Do it
+
ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata);
int objectid = env->addActiveObject(obj);
// If failed to add, return nothing (reads as nil)
- if(objectid == 0)
+ if (objectid == 0)
+ return 0;
+
+ // If already deleted (can happen in on_activate), return nil
+ if (obj->isGone())
return 0;
- // Return ObjectRef
getScriptApiBase(L)->objectrefGetOrCreate(L, obj);
return 1;
}
GET_ENV_PTR;
// pos
- //v3f pos = checkFloatPos(L, 1);
+ // v3f pos = checkFloatPos(L, 1);
// item
- ItemStack item = read_item(L, 2,getServer(L)->idef());
- if(item.empty() || !item.isKnown(getServer(L)->idef()))
+ ItemStack item = read_item(L, 2, getServer(L)->idef());
+ if (item.empty() || !item.isKnown(getServer(L)->idef()))
return 0;
int error_handler = PUSH_ERROR_HANDLER(L);
lua_getglobal(L, "core");
lua_getfield(L, -1, "spawn_item");
lua_remove(L, -2); // Remove core
- if(lua_isnil(L, -1))
+ if (lua_isnil(L, -1))
return 0;
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
return 1;
}
+// get_connected_players()
+int ModApiEnvMod::l_get_connected_players(lua_State *L)
+{
+ ServerEnvironment *env = (ServerEnvironment *)getEnv(L);
+ if (!env) {
+ log_deprecated(L, "Calling get_connected_players() at mod load time"
+ " is deprecated");
+ lua_createtable(L, 0, 0);
+ return 1;
+ }
+
+ lua_createtable(L, env->getPlayerCount(), 0);
+ u32 i = 0;
+ for (RemotePlayer *player : env->getPlayers()) {
+ if (player->getPeerId() == PEER_ID_INEXISTENT)
+ continue;
+ PlayerSAO *sao = player->getPlayerSAO();
+ if (sao && !sao->isGone()) {
+ getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
+ lua_rawseti(L, -2, ++i);
+ }
+ }
+ return 1;
+}
+
// get_player_by_name(name)
int ModApiEnvMod::l_get_player_by_name(lua_State *L)
{
// Do it
const char *name = luaL_checkstring(L, 1);
- RemotePlayer *player = dynamic_cast<RemotePlayer *>(env->getPlayer(name));
- if (player == NULL){
- lua_pushnil(L);
- return 1;
- }
+ RemotePlayer *player = env->getPlayer(name);
+ if (!player || player->getPeerId() == PEER_ID_INEXISTENT)
+ return 0;
PlayerSAO *sao = player->getPlayerSAO();
- if(sao == NULL){
- lua_pushnil(L);
- return 1;
- }
+ if (!sao || sao->isGone())
+ return 0;
// Put player on stack
getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
return 1;
int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
{
GET_ENV_PTR;
+ ScriptApiBase *script = getScriptApiBase(L);
// Do it
v3f pos = checkFloatPos(L, 1);
- float radius = luaL_checknumber(L, 2) * BS;
- std::vector<u16> ids;
- env->getObjectsInsideRadius(ids, pos, radius);
- ScriptApiBase *script = getScriptApiBase(L);
- lua_createtable(L, ids.size(), 0);
- std::vector<u16>::const_iterator iter = ids.begin();
- for(u32 i = 0; iter != ids.end(); ++iter) {
- ServerActiveObject *obj = env->getActiveObject(*iter);
- if (!obj->isGone()) {
- // Insert object reference into table
- script->objectrefGetOrCreate(L, obj);
- lua_rawseti(L, -2, ++i);
- }
+ float radius = readParam<float>(L, 2) * BS;
+ std::vector<ServerActiveObject *> objs;
+
+ auto include_obj_cb = [](ServerActiveObject *obj) { return !obj->isGone(); };
+ env->getObjectsInsideRadius(objs, pos, radius, include_obj_cb);
+
+ int i = 0;
+ lua_createtable(L, objs.size(), 0);
+ for (const auto obj : objs) {
+ // Insert object reference into table
+ script->objectrefGetOrCreate(L, obj);
+ lua_rawseti(L, -2, ++i);
}
return 1;
}
GET_ENV_PTR;
// Do it
- float timeofday_f = luaL_checknumber(L, 1);
+ float timeofday_f = readParam<float>(L, 1);
sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
int timeofday_mh = (int)(timeofday_f * 24000.0);
// This should be set directly in the environment but currently
// such changes aren't immediately sent to the clients, so call
// the server instead.
- //env->setTimeOfDay(timeofday_mh);
+ // env->setTimeOfDay(timeofday_mh);
getServer(L)->setTimeOfDay(timeofday_mh);
return 0;
}
// get_timeofday() -> 0...1
int ModApiEnvMod::l_get_timeofday(lua_State *L)
{
- Environment *env = getEnv(L);
- if (!env) {
- return 0;
- }
+ GET_PLAIN_ENV_PTR;
// Do it
int timeofday_mh = env->getTimeOfDay();
// get_day_count() -> int
int ModApiEnvMod::l_get_day_count(lua_State *L)
{
- Environment *env = getEnv(L);
- if (!env) {
- return 0;
- }
+ GET_PLAIN_ENV_PTR;
lua_pushnumber(L, env->getDayCount());
return 1;
return 1;
}
-
-// find_node_near(pos, radius, nodenames, search_center) -> pos or nil
-// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
-int ModApiEnvMod::l_find_node_near(lua_State *L)
+void ModApiEnvMod::collectNodeIds(lua_State *L, int idx, const NodeDefManager *ndef,
+ std::vector<content_t> &filter)
{
- Environment *env = getEnv(L);
- if (!env) {
- return 0;
- }
-
- INodeDefManager *ndef = getGameDef(L)->ndef();
- v3s16 pos = read_v3s16(L, 1);
- int radius = luaL_checkinteger(L, 2);
- std::vector<content_t> filter;
- if (lua_istable(L, 3)) {
+ if (lua_istable(L, idx)) {
lua_pushnil(L);
- while (lua_next(L, 3) != 0) {
+ while (lua_next(L, idx) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
- ndef->getIds(lua_tostring(L, -1), filter);
+ ndef->getIds(readParam<std::string>(L, -1), filter);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
- } else if (lua_isstring(L, 3)) {
- ndef->getIds(lua_tostring(L, 3), filter);
+ } else if (lua_isstring(L, idx)) {
+ ndef->getIds(readParam<std::string>(L, 3), filter);
}
+}
- int start_radius = (lua_toboolean(L, 4)) ? 0 : 1;
+// find_node_near(pos, radius, nodenames, [search_center]) -> pos or nil
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_node_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 (getClient(L) &&
- getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOOKUP_NODES)) {
- radius = std::max<int>(radius, getClient(L)->getCSMNodeRangeLimit());
- }
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
#endif
for (int d = start_radius; d <= radius; d++) {
- std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
for (const v3s16 &i : list) {
v3s16 p = pos + i;
- content_t c = env->getMap().getNodeNoEx(p).getContent();
+ content_t c = map.getNode(p).getContent();
if (CONTAINS(filter, c)) {
push_v3s16(L, p);
return 1;
return 0;
}
-// find_nodes_in_area(minp, maxp, nodenames) -> list of positions
+// find_nodes_near(pos, radius, nodenames, [search_center])
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
-int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
+int ModApiEnvMod::l_find_nodes_near(lua_State *L)
{
- GET_ENV_PTR;
+ GET_PLAIN_ENV_PTR;
- INodeDefManager *ndef = getServer(L)->ndef();
- v3s16 minp = read_v3s16(L, 1);
- v3s16 maxp = read_v3s16(L, 2);
- sortBoxVerticies(minp, maxp);
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
- v3s16 cube = maxp - minp + 1;
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
- /* Limit for too large areas, assume default values
- * and give tolerances of 1 node on each side
- * (chunksize * MAP_BLOCKSIZE + 2)^3 = 551368
- */
- if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 551368) {
- luaL_error(L, "find_nodes_in_area(): area volume"
- " exceeds allowed value of 551368");
- return 0;
+ 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;
- if (lua_istable(L, 3)) {
- lua_pushnil(L);
- while (lua_next(L, 3) != 0) {
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- ndef->getIds(lua_tostring(L, -1), filter);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
+ 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]++;
+ }
}
- } else if (lua_isstring(L, 3)) {
- ndef->getIds(lua_tostring(L, 3), filter);
}
+ 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);
- u64 i = 0;
- for (s16 x = minp.X; x <= maxp.X; x++)
- for (s16 y = minp.Y; y <= maxp.Y; y++)
- for (s16 z = minp.Z; z <= maxp.Z; z++) {
- v3s16 p(x, y, z);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
-
- std::vector<content_t>::iterator it = std::find(filter.begin(), filter.end(), c);
- if (it != filter.end()) {
- push_v3s16(L, p);
- lua_rawseti(L, -2, ++i);
+ u32 i = 0;
- u32 filt_index = it - filter.begin();
- individual_count[filt_index]++;
+ 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_newtable(L);
+ lua_createtable(L, 0, filter.size());
for (u32 i = 0; i < filter.size(); i++) {
- lua_pushnumber(L, individual_count[i]);
+ lua_pushinteger(L, individual_count[i]);
lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
}
return 2;
}
+// find_nodes_in_area(minp, maxp, nodenames, [grouped])
+int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ v3s16 minp = read_v3s16(L, 1);
+ v3s16 maxp = read_v3s16(L, 2);
+ sortBoxVerticies(minp, maxp);
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+#ifndef SERVER
+ if (Client *client = getClient(L)) {
+ minp = client->CSMClampPos(minp);
+ maxp = client->CSMClampPos(maxp);
+ }
+#endif
+
+ v3s16 cube = maxp - minp + 1;
+ // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+ if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
+ luaL_error(L, "find_nodes_in_area(): area volume"
+ " exceeds allowed value of 4096000");
+ return 0;
+ }
+
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+
+ bool grouped = lua_isboolean(L, 4) && readParam<bool>(L, 4);
+
+ if (grouped) {
+ // create the table we will be returning
+ lua_createtable(L, 0, filter.size());
+ int base = lua_gettop(L);
+
+ // create one table for each filter
+ std::vector<u32> idx;
+ idx.resize(filter.size());
+ for (u32 i = 0; i < filter.size(); i++)
+ lua_newtable(L);
+
+ v3s16 p;
+ for (p.X = minp.X; p.X <= maxp.X; p.X++)
+ for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++)
+ for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
+ content_t c = map.getNode(p).getContent();
+
+ auto it = std::find(
+ filter.begin(), filter.end(), c);
+ if (it != filter.end()) {
+ // Calculate index of the table and append
+ // the position
+ u32 filt_index = it - filter.begin();
+ push_v3s16(L, p);
+ lua_rawseti(L, base + 1 + filt_index,
+ ++idx[filt_index]);
+ }
+ }
+
+ // last filter table is at top of stack
+ u32 i = filter.size() - 1;
+ do {
+ if (idx[i] == 0) {
+ // No such node found -> drop the empty table
+ lua_pop(L, 1);
+ } else {
+ // This node was found -> put table into the return table
+ lua_setfield(L, base, ndef->get(filter[i]).name.c_str());
+ }
+ } while (i-- != 0);
+
+ assert(lua_gettop(L) == base);
+ return 1;
+ } else {
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+ v3s16 p;
+ for (p.X = minp.X; p.X <= maxp.X; p.X++)
+ for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++)
+ for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
+ content_t c = env->getMap().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_in_area_under_air(minp, maxp, nodenames) -> list of positions
// nodenames: e.g. {"ignore", "group:tree"} or "default:dirt"
int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
* TODO
*/
- GET_ENV_PTR;
+ GET_PLAIN_ENV_PTR;
- INodeDefManager *ndef = getServer(L)->ndef();
v3s16 minp = read_v3s16(L, 1);
v3s16 maxp = read_v3s16(L, 2);
sortBoxVerticies(minp, maxp);
- v3s16 cube = maxp - minp + 1;
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+#ifndef SERVER
+ if (Client *client = getClient(L)) {
+ minp = client->CSMClampPos(minp);
+ maxp = client->CSMClampPos(maxp);
+ }
+#endif
- /* Limit for too large areas, assume default values
- * and give tolerances of 1 node on each side
- * (chunksize * MAP_BLOCKSIZE + 2)^3 = 551368
- */
- if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 551368) {
+ v3s16 cube = maxp - minp + 1;
+ // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+ if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
luaL_error(L, "find_nodes_in_area_under_air(): area volume"
- " exceeds allowed value of 551368");
+ " exceeds allowed value of 4096000");
return 0;
}
std::vector<content_t> filter;
-
- if (lua_istable(L, 3)) {
- lua_pushnil(L);
- while (lua_next(L, 3) != 0) {
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- ndef->getIds(lua_tostring(L, -1), filter);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if (lua_isstring(L, 3)) {
- ndef->getIds(lua_tostring(L, 3), filter);
- }
+ collectNodeIds(L, 3, ndef, filter);
lua_newtable(L);
- u64 i = 0;
- for (s16 x = minp.X; x <= maxp.X; x++)
- for (s16 z = minp.Z; z <= maxp.Z; z++) {
- s16 y = minp.Y;
- v3s16 p(x, y, z);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
- for (; y <= maxp.Y; y++) {
- v3s16 psurf(x, y + 1, z);
- content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
- if (c != CONTENT_AIR && csurf == CONTENT_AIR &&
- CONTAINS(filter, c)) {
- push_v3s16(L, v3s16(x, y, z));
- lua_rawseti(L, -2, ++i);
+ u32 i = 0;
+ v3s16 p;
+ for (p.X = minp.X; p.X <= maxp.X; p.X++)
+ for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
+ p.Y = minp.Y;
+ content_t c = map.getNode(p).getContent();
+ for (; p.Y <= maxp.Y; p.Y++) {
+ v3s16 psurf(p.X, p.Y + 1, p.Z);
+ content_t csurf = map.getNode(psurf).getContent();
+ if (c != CONTENT_AIR && csurf == CONTENT_AIR &&
+ CONTAINS(filter, c)) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+ }
+ c = csurf;
}
- c = csurf;
}
- }
return 1;
}
if (lua_istable(L, 1)) {
read_noiseparams(L, 1, ¶ms);
} else {
- params.seed = luaL_checkint(L, 1);
+ params.seed = luaL_checkint(L, 1);
params.octaves = luaL_checkint(L, 2);
- params.persist = luaL_checknumber(L, 3);
- params.spread = v3f(1, 1, 1) * luaL_checknumber(L, 4);
+ params.persist = readParam<float>(L, 3);
+ params.spread = v3f(1, 1, 1) * readParam<float>(L, 4);
}
params.seed += (int)env->getServerMap().getSeed();
GET_ENV_PTR;
Map *map = &(env->getMap());
- LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
- new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) :
- new LuaVoxelManip(map);
+ LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2))
+ ? new LuaVoxelManip(map, read_v3s16(L, 1),
+ read_v3s16(L, 2))
+ : new LuaVoxelManip(map);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, "VoxelManip");
{
GET_ENV_PTR;
- ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL;
+ ClearObjectsMode mode = CLEAR_OBJECTS_MODE_QUICK;
if (lua_istable(L, 1)) {
- mode = (ClearObjectsMode)getenumfield(L, 1, "mode",
- ModApiEnvMod::es_ClearObjectsMode, mode);
+ mode = (ClearObjectsMode)getenumfield(
+ L, 1, "mode", ModApiEnvMod::es_ClearObjectsMode, mode);
}
env->clearObjects(mode);
return 0;
}
-// line_of_sight(pos1, pos2, stepsize) -> true/false, pos
+// line_of_sight(pos1, pos2) -> true/false, pos
int ModApiEnvMod::l_line_of_sight(lua_State *L)
{
- float stepsize = 1.0;
-
- GET_ENV_PTR;
+ GET_PLAIN_ENV_PTR;
// read position 1 from lua
v3f pos1 = checkFloatPos(L, 1);
// read position 2 from lua
v3f pos2 = checkFloatPos(L, 2);
- //read step size from lua
- if (lua_isnumber(L, 3)) {
- stepsize = lua_tonumber(L, 3);
- }
v3s16 p;
- bool success = env->line_of_sight(pos1, pos2, stepsize, &p);
+
+ bool success = env->line_of_sight(pos1, pos2, &p);
lua_pushboolean(L, success);
if (!success) {
push_v3s16(L, p);
bool success = true;
v3s16 blockpos;
for (blockpos.X = blockpos1.X; blockpos.X <= blockpos2.X; blockpos.X++)
- for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++)
- for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; blockpos.Z++) {
- success = success & map.repairBlockLight(blockpos, &modified_blocks);
- }
+ for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++)
+ for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z;
+ blockpos.Z++) {
+ success = success & map.repairBlockLight(blockpos,
+ &modified_blocks);
+ }
if (!modified_blocks.empty()) {
MapEditEvent event;
event.type = MEET_OTHER;
for (auto &modified_block : modified_blocks)
event.modified_blocks.insert(modified_block.first);
- map.dispatchEvent(&event);
+ map.dispatchEvent(event);
}
lua_pushboolean(L, success);
return LuaRaycast::create_object(L);
}
+// load_area(p1, [p2])
+// load mapblocks in area p1..p2, but do not generate map
+int ModApiEnvMod::l_load_area(lua_State *L)
+{
+ GET_ENV_PTR;
+ MAP_LOCK_REQUIRED;
+
+ Map *map = &(env->getMap());
+ v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 1));
+ if (!lua_istable(L, 2)) {
+ map->emergeBlock(bp1);
+ } else {
+ v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 2));
+ sortBoxVerticies(bp1, bp2);
+ for (s16 z = bp1.Z; z <= bp2.Z; z++)
+ for (s16 y = bp1.Y; y <= bp2.Y; y++)
+ for (s16 x = bp1.X; x <= bp2.X; x++) {
+ map->emergeBlock(v3s16(x, y, z));
+ }
+ }
+
+ return 0;
+}
+
// emerge_area(p1, p2, [callback, context])
// emerge mapblocks in area p1..p2, calls callback with context upon completion
int ModApiEnvMod::l_emerge_area(lua_State *L)
int args_ref = luaL_ref(L, LUA_REGISTRYINDEX);
state = new ScriptCallbackState;
- state->script = getServer(L)->getScriptIface();
+ state->script = getServer(L)->getScriptIface();
state->callback_ref = callback_ref;
- state->args_ref = args_ref;
- state->refcount = num_blocks;
- state->origin = getScriptApiBase(L)->getOrigin();
+ state->args_ref = args_ref;
+ state->refcount = num_blocks;
+ state->origin = getScriptApiBase(L)->getOrigin();
}
for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
- for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
- for (s16 x = bpmin.X; x <= bpmax.X; x++) {
- emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT,
- BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state);
- }
+ for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
+ for (s16 x = bpmin.X; x <= bpmax.X; x++) {
+ emerge->enqueueBlockEmergeEx(v3s16(x, y, z),
+ PEER_ID_INEXISTENT,
+ BLOCK_EMERGE_ALLOW_GEN |
+ BLOCK_EMERGE_FORCE_QUEUE,
+ callback, state);
+ }
return 0;
}
bool success = true;
for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
- for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
- for (s16 x = bpmin.X; x <= bpmax.X; x++) {
- v3s16 bp(x, y, z);
- if (map.deleteBlock(bp)) {
- env->setStaticForActiveObjectsInBlock(bp, false);
- event.modified_blocks.insert(bp);
- } else {
- success = false;
- }
- }
+ for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
+ for (s16 x = bpmin.X; x <= bpmax.X; x++) {
+ v3s16 bp(x, y, z);
+ if (map.deleteBlock(bp)) {
+ env->setStaticForActiveObjectsInBlock(bp, false);
+ event.modified_blocks.insert(bp);
+ } else {
+ success = false;
+ }
+ }
- map.dispatchEvent(&event);
+ map.dispatchEvent(event);
lua_pushboolean(L, success);
return 1;
}
// 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);
+ v3s16 pos1 = read_v3s16(L, 1);
+ v3s16 pos2 = read_v3s16(L, 2);
unsigned int searchdistance = luaL_checkint(L, 3);
- unsigned int max_jump = luaL_checkint(L, 4);
- unsigned int max_drop = luaL_checkint(L, 5);
- PathAlgorithm algo = PA_PLAIN_NP;
- if (!lua_isnil(L, 6)) {
- std::string algorithm = luaL_checkstring(L,6);
+ unsigned int max_jump = luaL_checkint(L, 4);
+ unsigned int max_drop = luaL_checkint(L, 5);
+ PathAlgorithm algo = PA_PLAIN_NP;
+ if (!lua_isnoneornil(L, 6)) {
+ std::string algorithm = luaL_checkstring(L, 6);
if (algorithm == "A*")
algo = PA_PLAIN;
algo = PA_DIJKSTRA;
}
- std::vector<v3s16> path = get_path(env, pos1, pos2,
- searchdistance, max_jump, max_drop, algo);
+ std::vector<v3s16> path = get_path(&env->getMap(), env->getGameDef()->ndef(),
+ pos1, pos2, searchdistance, max_jump, max_drop, algo);
if (!path.empty()) {
- lua_newtable(L);
+ lua_createtable(L, path.size(), 0);
int top = lua_gettop(L);
unsigned int index = 1;
for (const v3s16 &i : path) {
- lua_pushnumber(L,index);
+ lua_pushnumber(L, index);
push_v3s16(L, i);
lua_settable(L, top);
index++;
v3s16 p0 = read_v3s16(L, 1);
treegen::TreeDef tree_def;
- std::string trunk,leaves,fruit;
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ std::string trunk, leaves, fruit;
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
- if(lua_istable(L, 2))
- {
+ if (lua_istable(L, 2)) {
getstringfield(L, 2, "axiom", tree_def.initial_axiom);
getstringfield(L, 2, "rules_a", tree_def.rules_a);
getstringfield(L, 2, "rules_b", tree_def.rules_b);
getstringfield(L, 2, "rules_c", tree_def.rules_c);
getstringfield(L, 2, "rules_d", tree_def.rules_d);
getstringfield(L, 2, "trunk", trunk);
- tree_def.trunknode=ndef->getId(trunk);
+ tree_def.trunknode = ndef->getId(trunk);
getstringfield(L, 2, "leaves", leaves);
- tree_def.leavesnode=ndef->getId(leaves);
- tree_def.leaves2_chance=0;
+ tree_def.leavesnode = ndef->getId(leaves);
+ tree_def.leaves2_chance = 0;
getstringfield(L, 2, "leaves2", leaves);
if (!leaves.empty()) {
- tree_def.leaves2node=ndef->getId(leaves);
+ tree_def.leaves2node = ndef->getId(leaves);
getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
}
getintfield(L, 2, "angle", tree_def.angle);
tree_def.iterations_random_level = 0;
getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
- tree_def.fruit_chance=0;
+ tree_def.fruit_chance = 0;
getstringfield(L, 2, "fruit", fruit);
if (!fruit.empty()) {
- tree_def.fruitnode=ndef->getId(fruit);
- getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
+ tree_def.fruitnode = ndef->getId(fruit);
+ getintfield(L, 2, "fruit_chance", tree_def.fruit_chance);
}
tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed);
- }
- else
+ } else
return 0;
+ ServerMap *map = &env->getServerMap();
treegen::error e;
- if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) {
+ if ((e = treegen::spawn_ltree(map, p0, ndef, tree_def)) != treegen::SUCCESS) {
if (e == treegen::UNBALANCED_BRACKETS) {
- luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
+ luaL_error(L, "spawn_tree(): closing ']' has no matching opening "
+ "bracket");
} else {
luaL_error(L, "spawn_tree(): unknown error");
}
return 0;
}
+// get_translated_string(lang_code, string)
+int ModApiEnvMod::l_get_translated_string(lua_State *L)
+{
+ GET_ENV_PTR;
+ std::string lang_code = luaL_checkstring(L, 1);
+ std::string string = luaL_checkstring(L, 2);
+ getServer(L)->loadTranslationLanguage(lang_code);
+ string = wide_to_utf8(translate_string(
+ utf8_to_wide(string), &(*g_server_translations)[lang_code]));
+ lua_pushstring(L, string.c_str());
+ return 1;
+}
+
void ModApiEnvMod::Initialize(lua_State *L, int top)
{
API_FCT(set_node);
+ API_FCT(bulk_set_node);
API_FCT(add_node);
API_FCT(swap_node);
API_FCT(add_item);
API_FCT(find_nodes_with_meta);
API_FCT(get_meta);
API_FCT(get_node_timer);
+ API_FCT(get_connected_players);
API_FCT(get_player_by_name);
API_FCT(get_objects_inside_radius);
API_FCT(set_timeofday);
API_FCT(find_nodes_in_area);
API_FCT(find_nodes_in_area_under_air);
API_FCT(fix_light);
+ API_FCT(load_area);
API_FCT(emerge_area);
API_FCT(delete_area);
API_FCT(get_perlin);
API_FCT(transforming_liquid_add);
API_FCT(forceload_block);
API_FCT(forceload_free_block);
+ API_FCT(get_translated_string);
}
void ModApiEnvMod::InitializeClient(lua_State *L, int top)
{
+ API_FCT(get_node_light);
API_FCT(get_timeofday);
- API_FCT(get_day_count);
API_FCT(get_node_max_level);
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(find_path);
+ API_FCT(line_of_sight);
+ API_FCT(raycast);
}