#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
-#include "scripting_game.h"
+#include <algorithm>
+#include "scripting_server.h"
#include "environment.h"
+#include "mapblock.h"
#include "server.h"
#include "nodedef.h"
#include "daynightratio.h"
#include "util/pointedthing.h"
#include "content_sao.h"
-#include "treegen.h"
+#include "mapgen/treegen.h"
+#include "emerge.h"
#include "pathfinder.h"
+#include "face_position_cache.h"
+#include "remoteplayer.h"
+#ifndef SERVER
+#include "client.h"
+#endif
-#define GET_ENV_PTR ServerEnvironment* env = \
- dynamic_cast<ServerEnvironment*>(getEnv(L)); \
- if (env == NULL) return 0
+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)
{
- GameScripting *scriptIface = env->getScriptIface();
+ ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();
- assert(lua_checkstack(L, 20));
+ sanity_check(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L);
+ int error_handler = PUSH_ERROR_HANDLER(L);
// Get registered_abms
lua_getglobal(L, "core");
lua_pushnumber(L, m_id);
lua_gettable(L, -2);
if(lua_isnil(L, -1))
- assert(0);
+ FATAL_ERROR("");
lua_remove(L, -2); // Remove registered_abms
+ scriptIface->setOriginFromTable(-1);
+
// Call action
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, "action");
pushnode(L, n, env->getGameDef()->ndef());
lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider);
- if(lua_pcall(L, 4, 0, errorhandler))
- script_error(L);
+
+ int result = lua_pcall(L, 4, 0, error_handler);
+ if (result)
+ scriptIface->scriptError(result, "LuaABM::trigger");
+
lua_pop(L, 1); // Pop error handler
}
+void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
+{
+ ServerScripting *scriptIface = env->getScriptIface();
+ scriptIface->realityCheck();
+
+ lua_State *L = scriptIface->getStack();
+ sanity_check(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ // Get registered_lbms
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_lbms");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_remove(L, -2); // Remove core
+
+ // Get registered_lbms[m_id]
+ lua_pushnumber(L, m_id);
+ lua_gettable(L, -2);
+ 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);
+
+ // Call action
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "action");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_remove(L, -2); // Remove registered_lbms[m_id]
+ push_v3s16(L, p);
+ pushnode(L, n, env->getGameDef()->ndef());
+
+ int result = lua_pcall(L, 2, 0, error_handler);
+ if (result)
+ scriptIface->scriptError(result, "LuaLBM::trigger");
+
+ lua_pop(L, 1); // Pop error handler
+}
+
+int LuaRaycast::l_next(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ ScriptApiItem *script = getScriptApi<ScriptApiItem>(L);
+ GET_ENV_PTR;
+
+ LuaRaycast *o = checkobject(L, 1);
+ PointedThing pointed;
+ env->continueRaycast(&o->state, &pointed);
+ if (pointed.type == POINTEDTHING_NOTHING)
+ lua_pushnil(L);
+ else
+ script->pushPointedThing(pointed);
+
+ return 1;
+}
+
+int LuaRaycast::create_object(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ bool objects = true;
+ bool liquids = false;
+
+ v3f pos1 = checkFloatPos(L, 1);
+ v3f pos2 = checkFloatPos(L, 2);
+ if (lua_isboolean(L, 3)) {
+ objects = lua_toboolean(L, 3);
+ }
+ if (lua_isboolean(L, 4)) {
+ liquids = lua_toboolean(L, 4);
+ }
+
+ LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
+ objects, liquids);
+
+ *(void **) (lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaRaycast *LuaRaycast::checkobject(lua_State *L, int narg)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+ return *(LuaRaycast **) ud;
+}
+
+int LuaRaycast::gc_object(lua_State *L)
+{
+ LuaRaycast *o = *(LuaRaycast **) (lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+void LuaRaycast::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, "__call");
+ lua_pushcfunction(L, l_next);
+ 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 LuaRaycast::className[] = "Raycast";
+const luaL_Reg LuaRaycast::methods[] =
+{
+ luamethod(LuaRaycast, next),
+ { 0, 0 }
+};
+
+void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
+{
+ ScriptCallbackState *state = (ScriptCallbackState *)param;
+ assert(state != NULL);
+ assert(state->script != NULL);
+ assert(state->refcount > 0);
+
+ // state must be protected by envlock
+ Server *server = state->script->getServer();
+ MutexAutoLock envlock(server->m_env_mutex);
+
+ state->refcount--;
+
+ state->script->on_emerge_area_completion(blockpos, action, state);
+
+ if (state->refcount == 0)
+ delete state;
+}
+
// Exported functions
// set_node(pos, node)
{
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);
bool is_position_ok;
MapNode n = env->getMap().getNodeNoEx(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);
return 1;
}
// Create item to place
- ItemStack item(ndef->get(n).name, 1, 0, "", idef);
+ ItemStack item(ndef->get(n).name, 1, 0, idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;
pointed.node_abovesurface = pos;
pointed.node_undersurface = pos + v3s16(0,-1,0);
- // Place it with a NULL placer (appears in Lua as a non-functional
- // ObjectRef)
- bool success = scriptIfaceItem->item_OnPlace(item, NULL, pointed);
+ // Place it with a NULL placer (appears in Lua as nil)
+ bool success = scriptIfaceItem->item_OnPlace(item, nullptr, pointed);
lua_pushboolean(L, success);
return 1;
}
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_max_level(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_level(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
return 1;
}
+// find_nodes_with_meta(pos1, pos2)
+int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ std::vector<v3s16> positions = env->getMap().findNodesWithMetadata(
+ check_v3s16(L, 1), check_v3s16(L, 2));
+
+ lua_newtable(L);
+ for (size_t i = 0; i != positions.size(); i++) {
+ push_v3s16(L, positions[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+
+ return 1;
+}
// get_meta(pos)
int ModApiEnvMod::l_get_meta(lua_State *L)
return 1;
}
-// add_entity(pos, entityname) -> ObjectRef or nil
+// add_entity(pos, entityname, [staticdata]) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_add_entity(lua_State *L)
{
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, "");
+ 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)
// pos
//v3f pos = checkFloatPos(L, 1);
// item
- ItemStack item = read_item(L, 2,getServer(L));
+ ItemStack item = read_item(L, 2,getServer(L)->idef());
if(item.empty() || !item.isKnown(getServer(L)->idef()))
return 0;
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L);
+ int error_handler = PUSH_ERROR_HANDLER(L);
// Use spawn_item to spawn a __builtin:item
lua_getglobal(L, "core");
return 0;
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
- if(lua_pcall(L, 2, 1, errorhandler))
- script_error(L);
- lua_remove(L, errorhandler); // Remove error handler
+
+ PCALL_RESL(L, lua_pcall(L, 2, 1, error_handler));
+
+ lua_remove(L, error_handler);
return 1;
- /*lua_pushvalue(L, 1);
- lua_pushstring(L, "__builtin:item");
- lua_pushstring(L, item.getItemString().c_str());
- return l_add_entity(L);*/
- /*// Do it
- ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
- int objectid = env->addActiveObject(obj);
- // If failed to add, return nothing (reads as nil)
- if(objectid == 0)
- return 0;
- // Return ObjectRef
- objectrefGetOrCreate(L, obj);
- return 1;*/
}
// get_player_by_name(name)
// Do it
const char *name = luaL_checkstring(L, 1);
- Player *player = env->getPlayer(name);
- if(player == NULL){
+ RemotePlayer *player = dynamic_cast<RemotePlayer *>(env->getPlayer(name));
+ if (player == NULL){
lua_pushnil(L);
return 1;
}
// Do it
v3f pos = checkFloatPos(L, 1);
float radius = luaL_checknumber(L, 2) * BS;
- std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
+ std::vector<u16> ids;
+ env->getObjectsInsideRadius(ids, pos, radius);
ScriptApiBase *script = getScriptApiBase(L);
lua_createtable(L, ids.size(), 0);
- std::set<u16>::const_iterator iter = ids.begin();
- for(u32 i = 0; iter != ids.end(); iter++) {
+ std::vector<u16>::const_iterator iter = ids.begin();
+ for(u32 i = 0; iter != ids.end(); ++iter) {
ServerActiveObject *obj = env->getActiveObject(*iter);
- // Insert object reference into table
- script->objectrefGetOrCreate(L, obj);
- lua_rawseti(L, -2, ++i);
+ if (!obj->isGone()) {
+ // Insert object reference into table
+ script->objectrefGetOrCreate(L, obj);
+ lua_rawseti(L, -2, ++i);
+ }
}
return 1;
}
// Do it
float timeofday_f = luaL_checknumber(L, 1);
- assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
+ 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
// get_timeofday() -> 0...1
int ModApiEnvMod::l_get_timeofday(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
// Do it
int timeofday_mh = env->getTimeOfDay();
- float timeofday_f = (float)timeofday_mh / 24000.0;
+ float timeofday_f = (float)timeofday_mh / 24000.0f;
lua_pushnumber(L, timeofday_f);
return 1;
}
+// get_day_count() -> int
+int ModApiEnvMod::l_get_day_count(lua_State *L)
+{
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
+
+ lua_pushnumber(L, env->getDayCount());
+ return 1;
+}
+
// get_gametime()
int ModApiEnvMod::l_get_gametime(lua_State *L)
{
}
-// find_node_near(pos, radius, nodenames) -> pos or nil
+// 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_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
- INodeDefManager *ndef = getServer(L)->ndef();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
v3s16 pos = read_v3s16(L, 1);
int radius = luaL_checkinteger(L, 2);
- std::set<content_t> filter;
- if(lua_istable(L, 3)){
- int table = 3;
+ std::vector<content_t> filter;
+ if (lua_istable(L, 3)) {
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ 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)){
+ } else if (lua_isstring(L, 3)) {
ndef->getIds(lua_tostring(L, 3), filter);
}
- for(int d=1; d<=radius; d++){
+ int start_radius = (lua_toboolean(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());
+ }
+#endif
+
+ for (int d = start_radius; d <= radius; d++) {
std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
- for(std::vector<v3s16>::iterator i = list.begin();
- i != list.end(); ++i){
- v3s16 p = pos + (*i);
+ for (const v3s16 &i : list) {
+ v3s16 p = pos + i;
content_t c = env->getMap().getNodeNoEx(p).getContent();
- if(filter.count(c) != 0){
+ if (CONTAINS(filter, c)) {
push_v3s16(L, p);
return 1;
}
{
GET_ENV_PTR;
- INodeDefManager *ndef = getServer(L)->ndef();
+ const NodeDefManager *ndef = getServer(L)->ndef();
v3s16 minp = read_v3s16(L, 1);
v3s16 maxp = read_v3s16(L, 2);
- std::set<content_t> filter;
- if(lua_istable(L, 3)){
- int table = 3;
+ sortBoxVerticies(minp, maxp);
+
+ v3s16 cube = maxp - minp + 1;
+
+ /* 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;
+ }
+
+ std::vector<content_t> filter;
+ if (lua_istable(L, 3)) {
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ 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)){
+ } else if (lua_isstring(L, 3)) {
ndef->getIds(lua_tostring(L, 3), filter);
}
+ 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++) {
+ 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();
- if(filter.count(c) != 0) {
+
+ 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 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ lua_newtable(L);
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushnumber(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)
+{
+ /* Note: A similar but generalized (and therefore slower) version of this
+ * function could be created -- e.g. find_nodes_in_area_under -- which
+ * would accept a node name (or ID?) or list of names that the "above node"
+ * should be.
+ * TODO
+ */
+
+ GET_ENV_PTR;
+
+ const NodeDefManager *ndef = getServer(L)->ndef();
+ v3s16 minp = read_v3s16(L, 1);
+ v3s16 maxp = read_v3s16(L, 2);
+ sortBoxVerticies(minp, maxp);
+
+ v3s16 cube = maxp - minp + 1;
+
+ /* 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_under_air(): area volume"
+ " exceeds allowed value of 551368");
+ 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);
+ }
+
+ 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);
+ }
+ c = csurf;
}
}
return 1;
// returns world-specific PerlinNoise
int ModApiEnvMod::l_get_perlin(lua_State *L)
{
- GET_ENV_PTR;
+ GET_ENV_PTR_NO_MAP_LOCK;
NoiseParams params;
// returns world-specific PerlinNoiseMap
int ModApiEnvMod::l_get_perlin_map(lua_State *L)
{
- GET_ENV_PTR;
+ GET_ENV_PTR_NO_MAP_LOCK;
NoiseParams np;
if (!read_noiseparams(L, 1, &np))
return 0;
v3s16 size = read_v3s16(L, 2);
- int seed = (int)(env->getServerMap().getSeed());
+ s32 seed = (s32)(env->getServerMap().getSeed());
LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size);
*(void **)(lua_newuserdata(L, sizeof(void *))) = n;
luaL_getmetatable(L, "PerlinNoiseMap");
return 1;
}
-// clear_objects()
+// clear_objects([options])
// clear all objects in the environment
+// where options = {mode = "full" or "quick"}
int ModApiEnvMod::l_clear_objects(lua_State *L)
{
GET_ENV_PTR;
- env->clearAllObjects();
+ ClearObjectsMode mode = CLEAR_OBJECTS_MODE_QUICK;
+ if (lua_istable(L, 1)) {
+ 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;
// 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);
return 1;
}
+// fix_light(p1, p2)
+int ModApiEnvMod::l_fix_light(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ v3s16 blockpos1 = getContainerPos(read_v3s16(L, 1), MAP_BLOCKSIZE);
+ v3s16 blockpos2 = getContainerPos(read_v3s16(L, 2), MAP_BLOCKSIZE);
+ ServerMap &map = env->getServerMap();
+ std::map<v3s16, MapBlock *> modified_blocks;
+ 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);
+ }
+ 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);
+ }
+ lua_pushboolean(L, success);
+
+ return 1;
+}
+
+int ModApiEnvMod::l_raycast(lua_State *L)
+{
+ return LuaRaycast::create_object(L);
+}
+
+// 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)
+{
+ GET_ENV_PTR;
+
+ EmergeCompletionCallback callback = NULL;
+ ScriptCallbackState *state = NULL;
+
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
+ v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
+ sortBoxVerticies(bpmin, bpmax);
+
+ size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume();
+ assert(num_blocks != 0);
+
+ if (lua_isfunction(L, 3)) {
+ callback = LuaEmergeAreaCallback;
+
+ lua_pushvalue(L, 3);
+ int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ lua_pushvalue(L, 4);
+ int args_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ state = new ScriptCallbackState;
+ state->script = getServer(L)->getScriptIface();
+ state->callback_ref = callback_ref;
+ 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);
+ }
+
+ return 0;
+}
+
// delete_area(p1, p2)
// delete mapblocks in area p1..p2
int ModApiEnvMod::l_delete_area(lua_State *L)
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))
+ if (map.deleteBlock(bp)) {
+ env->setStaticForActiveObjectsInBlock(bp, false);
event.modified_blocks.insert(bp);
- else
+ } else {
success = false;
+ }
}
map.dispatchEvent(&event);
unsigned int searchdistance = luaL_checkint(L, 3);
unsigned int max_jump = luaL_checkint(L, 4);
unsigned int max_drop = luaL_checkint(L, 5);
- algorithm algo = A_PLAIN_NP;
+ PathAlgorithm algo = PA_PLAIN_NP;
if (!lua_isnil(L, 6)) {
std::string algorithm = luaL_checkstring(L,6);
if (algorithm == "A*")
- algo = A_PLAIN;
+ algo = PA_PLAIN;
if (algorithm == "Dijkstra")
- algo = DIJKSTRA;
+ 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, pos1, pos2,
+ searchdistance, max_jump, max_drop, algo);
- if (path.size() > 0)
- {
+ if (!path.empty()) {
lua_newtable(L);
int top = lua_gettop(L);
unsigned int index = 1;
- for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
- {
+ for (const v3s16 &i : path) {
lua_pushnumber(L,index);
- push_v3s16(L, *i);
+ push_v3s16(L, i);
lua_settable(L, top);
index++;
}
treegen::TreeDef tree_def;
std::string trunk,leaves,fruit;
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
if(lua_istable(L, 2))
{
tree_def.leavesnode=ndef->getId(leaves);
tree_def.leaves2_chance=0;
getstringfield(L, 2, "leaves2", leaves);
- if (leaves !="")
- {
+ if (!leaves.empty()) {
tree_def.leaves2node=ndef->getId(leaves);
getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
}
getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
tree_def.fruit_chance=0;
getstringfield(L, 2, "fruit", fruit);
- if (fruit != "")
- {
+ if (!fruit.empty()) {
tree_def.fruitnode=ndef->getId(fruit);
getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
}
return 0;
}
-// get_us_time()
-int ModApiEnvMod::l_get_us_time(lua_State *L)
-{
- lua_pushnumber(L, porting::getTimeUs());
- 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(set_node_level);
API_FCT(add_node_level);
API_FCT(add_entity);
+ API_FCT(find_nodes_with_meta);
API_FCT(get_meta);
API_FCT(get_node_timer);
API_FCT(get_player_by_name);
API_FCT(set_timeofday);
API_FCT(get_timeofday);
API_FCT(get_gametime);
+ API_FCT(get_day_count);
API_FCT(find_node_near);
API_FCT(find_nodes_in_area);
+ API_FCT(find_nodes_in_area_under_air);
+ API_FCT(fix_light);
+ API_FCT(emerge_area);
API_FCT(delete_area);
API_FCT(get_perlin);
API_FCT(get_perlin_map);
API_FCT(spawn_tree);
API_FCT(find_path);
API_FCT(line_of_sight);
+ API_FCT(raycast);
API_FCT(transforming_liquid_add);
API_FCT(forceload_block);
API_FCT(forceload_free_block);
- API_FCT(get_us_time);
+}
+
+void ModApiEnvMod::InitializeClient(lua_State *L, int top)
+{
+ API_FCT(get_timeofday);
+ API_FCT(get_day_count);
+ API_FCT(get_node_max_level);
+ API_FCT(get_node_level);
+ API_FCT(find_node_near);
}