Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+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 General Public License for more details.
+GNU Lesser General Public License for more details.
-You should have received a copy of the GNU General Public License along
+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 "filesys.h"
#include "serverobject.h"
#include "script.h"
-//#include "luna.h"
-#include "luaentity_common.h"
-#include "content_sao.h" // For LuaEntitySAO
+#include "object_properties.h"
+#include "content_sao.h" // For LuaEntitySAO and PlayerSAO
#include "itemdef.h"
#include "nodedef.h"
#include "craftdef.h"
#include "utility.h"
#include "tool.h"
#include "daynightratio.h"
+#include "noise.h" // PseudoRandom for LuaPseudoRandom
static void stackDump(lua_State *L, std::ostream &o)
{
{0, NULL},
};
+struct EnumString es_CraftMethod[] =
+{
+ {CRAFT_METHOD_NORMAL, "normal"},
+ {CRAFT_METHOD_COOKING, "cooking"},
+ {CRAFT_METHOD_FUEL, "fuel"},
+ {0, NULL},
+};
+
/*
C struct <-> Lua table converter functions
*/
}
}
+/*
+ Privileges
+*/
+static void read_privileges(lua_State *L, int index,
+ std::set<std::string> &result)
+{
+ result.clear();
+ lua_pushnil(L);
+ if(index < 0)
+ index -= 1;
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ std::string key = luaL_checkstring(L, -2);
+ bool value = lua_toboolean(L, -1);
+ if(value)
+ result.insert(key);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+}
+
/*
ToolCapabilities
*/
// This will be created
ToolGroupCap groupcap;
// Read simple parameters
- getfloatfield(L, table_groupcap, "maxwear", groupcap.maxwear);
getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
+ getintfield(L, table_groupcap, "uses", groupcap.uses);
+ // DEPRECATED: maxwear
+ float maxwear = 0;
+ if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
+ if(maxwear != 0)
+ groupcap.uses = 1.0/maxwear;
+ else
+ groupcap.uses = 0;
+ infostream<<script_get_backtrace(L)<<std::endl;
+ infostream<<"WARNING: field \"maxwear\" is deprecated; "
+ <<"should replace with uses=1/maxwear"<<std::endl;
+ }
// Read "times" table
lua_getfield(L, table_groupcap, "times");
if(lua_istable(L, -1)){
// Set subtable "times"
lua_setfield(L, -2, "times");
// Set simple parameters
- setfloatfield(L, -1, "maxwear", groupcap.maxwear);
setintfield(L, -1, "maxlevel", groupcap.maxlevel);
+ setintfield(L, -1, "uses", groupcap.uses);
// Insert groupcap table into groupcaps table
lua_setfield(L, -2, name.c_str());
}
SimpleSoundSpec
*/
-static SimpleSoundSpec read_soundspec(lua_State *L, int index)
+static void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
- SimpleSoundSpec spec;
if(lua_isnil(L, index)){
} else if(lua_istable(L, index)){
getstringfield(L, index, "name", spec.name);
} else if(lua_isstring(L, index)){
spec.name = lua_tostring(L, index);
}
- return spec;
+}
+
+/*
+ ObjectProperties
+*/
+
+static void read_object_properties(lua_State *L, int index,
+ ObjectProperties *prop)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+ if(!lua_istable(L, index))
+ return;
+
+ prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+
+ getboolfield(L, -1, "physical", prop->physical);
+
+ getfloatfield(L, -1, "weight", prop->weight);
+
+ lua_getfield(L, -1, "collisionbox");
+ if(lua_istable(L, -1))
+ prop->collisionbox = read_aabbox3df32(L, -1, 1.0);
+ lua_pop(L, 1);
+
+ getstringfield(L, -1, "visual", prop->visual);
+
+ lua_getfield(L, -1, "visual_size");
+ if(lua_istable(L, -1))
+ prop->visual_size = read_v2f(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "textures");
+ if(lua_istable(L, -1)){
+ prop->textures.clear();
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ prop->textures.push_back(lua_tostring(L, -1));
+ else
+ prop->textures.push_back("");
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "spritediv");
+ if(lua_istable(L, -1))
+ prop->spritediv = read_v2s16(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "initial_sprite_basepos");
+ if(lua_istable(L, -1))
+ prop->initial_sprite_basepos = read_v2s16(L, -1);
+ lua_pop(L, 1);
+
+ getboolfield(L, -1, "is_visible", prop->is_visible);
+ getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
+ getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
}
/*
"deprecated: use 'drop' field");
warn_if_field_exists(L, index, "extra_dug_item_rarity",
"deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "metadata_name",
+ "deprecated: use on_add and metadata callbacks");
// True for all ground-like things like stone and mud, false for eg. trees
getboolfield(L, index, "is_ground_content", f.is_ground_content);
getboolfield(L, index, "climbable", f.climbable);
// Player can build on these
getboolfield(L, index, "buildable_to", f.buildable_to);
- // Metadata name of node (eg. "furnace")
- getstringfield(L, index, "metadata_name", f.metadata_name);
// Whether the node is non-liquid, source liquid or flowing liquid
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
es_LiquidType, LIQUID_NONE);
lua_getfield(L, index, "sounds");
if(lua_istable(L, -1)){
lua_getfield(L, -1, "footstep");
- f.sound_footstep = read_soundspec(L, -1);
+ read_soundspec(L, -1, f.sound_footstep);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "dig");
+ read_soundspec(L, -1, f.sound_dig);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "dug");
+ read_soundspec(L, -1, f.sound_dug);
lua_pop(L, 1);
}
lua_pop(L, 1);
*/
static ItemStack read_item(lua_State *L, int index);
+static std::vector<ItemStack> read_items(lua_State *L, int index);
+// creates a table of ItemStacks
+static void push_items(lua_State *L, const std::vector<ItemStack> &items);
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
lua_State *L, int tableindex, int forcesize=-1)
{
- dstream<<"inventory_set_list_from_lua\n";
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
return;
}
// Otherwise set list
- std::vector<ItemStack> items;
- luaL_checktype(L, tableindex, LUA_TTABLE);
- lua_pushnil(L);
- while(lua_next(L, tableindex) != 0){
- // key at index -2 and value at index -1
- items.push_back(read_item(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
+ std::vector<ItemStack> items = read_items(L, tableindex);
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
invlist->deleteItem(index);
index++;
}
- dstream<<"inventory_set_list_from_lua done\n";
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
lua_pushnil(L);
return;
}
- // Get the table insert function
- lua_getglobal(L, "table");
- lua_getfield(L, -1, "insert");
- int table_insert = lua_gettop(L);
- // Create and fill table
- lua_newtable(L);
- int table = lua_gettop(L);
- for(u32 i=0; i<invlist->getSize(); i++){
- ItemStack item = invlist->getItem(i);
- lua_pushvalue(L, table_insert);
- lua_pushvalue(L, table);
- lua_pushstring(L, item.getItemString().c_str());
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- }
+ std::vector<ItemStack> items;
+ for(u32 i=0; i<invlist->getSize(); i++)
+ items.push_back(invlist->getItem(i));
+ push_items(L, items);
}
/*
ItemStack &item = o->m_stack;
u32 takecount = 1;
if(!lua_isnone(L, 2))
- takecount = lua_tointeger(L, 2);
+ takecount = luaL_checkinteger(L, 2);
ItemStack taken = item.takeItem(takecount);
create(L, taken);
return 1;
}
}
+static std::vector<ItemStack> read_items(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ std::vector<ItemStack> items;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ items.push_back(read_item(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return items;
+}
+
+// creates a table of ItemStacks
+static void push_items(lua_State *L, const std::vector<ItemStack> &items)
+{
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ // Create and fill table
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ for(u32 i=0; i<items.size(); i++){
+ ItemStack item = items[i];
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ LuaItemStack::create(L, item);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ lua_remove(L, -2); // Remove table
+ lua_remove(L, -2); // Remove insert
+}
+
/*
InvRef
*/
return 0;
}
+ // is_empty(self, listname) -> true/false
+ static int l_is_empty(lua_State *L)
+ {
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list && list->getUsedSlots() > 0){
+ lua_pushboolean(L, false);
+ } else {
+ lua_pushboolean(L, true);
+ }
+ return 1;
+ }
+
// get_size(self, listname)
static int l_get_size(lua_State *L)
{
};
const char InvRef::className[] = "InvRef";
const luaL_reg InvRef::methods[] = {
+ method(InvRef, is_empty),
method(InvRef, get_size),
method(InvRef, set_size),
method(InvRef, get_stack),
return *(NodeMetaRef**)ud; // unbox pointer
}
- static NodeMetadata* getmeta(NodeMetaRef *ref)
+ static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create)
{
NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
+ if(meta == NULL && auto_create)
+ {
+ meta = new NodeMetadata(ref->m_env->getGameDef());
+ ref->m_env->getMap().setNodeMetadata(ref->m_p, meta);
+ }
return meta;
}
- /*static IGenericNodeMetadata* getgenericmeta(NodeMetaRef *ref)
- {
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL)
- return NULL;
- if(meta->typeId() != NODEMETA_GENERIC)
- return NULL;
- return (IGenericNodeMetadata*)meta;
- }*/
-
static void reportMetadataChange(NodeMetaRef *ref)
{
// Inform other things that the metadata has changed
return 0;
}
- // get_type(self)
- static int l_get_type(lua_State *L)
+ // get_string(self, name)
+ static int l_get_string(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
+ std::string name = luaL_checkstring(L, 2);
+
+ NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
- lua_pushnil(L);
+ lua_pushlstring(L, "", 0);
return 1;
}
- // Do it
- lua_pushstring(L, meta->typeName());
+ std::string str = meta->getString(name);
+ lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
- // allows_text_input(self)
- static int l_allows_text_input(lua_State *L)
+ // set_string(self, name, var)
+ static int l_set_string(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- lua_pushboolean(L, meta->allowsTextInput());
- return 1;
- }
+ std::string name = luaL_checkstring(L, 2);
+ size_t len = 0;
+ const char *s = lua_tolstring(L, 3, &len);
+ std::string str(s, len);
- // set_text(self, text)
- static int l_set_text(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string text = luaL_checkstring(L, 2);
- meta->setText(text);
+ NodeMetadata *meta = getmeta(ref, !str.empty());
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
reportMetadataChange(ref);
return 0;
}
- // get_text(self)
- static int l_get_text(lua_State *L)
+ // get_int(self, name)
+ static int l_get_int(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string text = meta->getText();
- lua_pushstring(L, text.c_str());
- return 1;
- }
+ std::string name = lua_tostring(L, 2);
- // get_owner(self)
- static int l_get_owner(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string owner = meta->getOwner();
- lua_pushstring(L, owner.c_str());
+ NodeMetadata *meta = getmeta(ref, false);
+ if(meta == NULL){
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+ std::string str = meta->getString(name);
+ lua_pushnumber(L, stoi(str));
return 1;
}
- // set_owner(self, string)
- static int l_set_owner(lua_State *L)
+ // set_int(self, name, var)
+ static int l_set_int(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string owner = luaL_checkstring(L, 2);
- meta->setOwner(owner);
+ std::string name = lua_tostring(L, 2);
+ int a = lua_tointeger(L, 3);
+ std::string str = itos(a);
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
reportMetadataChange(ref);
- return 1;
+ return 0;
}
- // get_allow_removal(self)
- static int l_get_allow_removal(lua_State *L)
+ // get_float(self, name)
+ static int l_get_float(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
+ std::string name = lua_tostring(L, 2);
+
+ NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
- lua_pushboolean(L, true);
+ lua_pushnumber(L, 0);
return 1;
}
- // Do it
- lua_pushboolean(L, !meta->nodeRemovalDisabled());
+ std::string str = meta->getString(name);
+ lua_pushnumber(L, stof(str));
return 1;
}
- /* IGenericNodeMetadata interface */
-
- // set_infotext(self, text)
- static int l_set_infotext(lua_State *L)
+ // set_float(self, name, var)
+ static int l_set_float(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string text = luaL_checkstring(L, 2);
- meta->setInfoText(text);
+ std::string name = lua_tostring(L, 2);
+ float a = lua_tonumber(L, 3);
+ std::string str = ftos(a);
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
reportMetadataChange(ref);
return 0;
}
static int l_get_inventory(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
+ getmeta(ref, true); // try to ensure the metadata exists
InvRef::createNodeMeta(L, ref->m_p);
return 1;
}
-
- // set_inventory_draw_spec(self, text)
- static int l_set_inventory_draw_spec(lua_State *L)
+
+ // to_table(self)
+ static int l_to_table(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string text = luaL_checkstring(L, 2);
- meta->setInventoryDrawSpec(text);
- reportMetadataChange(ref);
- return 0;
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_newtable(L);
+ // fields
+ lua_newtable(L);
+ {
+ std::map<std::string, std::string> fields = meta->getStrings();
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushlstring(L, name.c_str(), name.size());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ }
+ lua_setfield(L, -2, "fields");
+ // inventory
+ lua_newtable(L);
+ Inventory *inv = meta->getInventory();
+ if(inv){
+ std::vector<const InventoryList*> lists = inv->getLists();
+ for(std::vector<const InventoryList*>::const_iterator
+ i = lists.begin(); i != lists.end(); i++){
+ inventory_get_list_to_lua(inv, (*i)->getName().c_str(), L);
+ lua_setfield(L, -2, (*i)->getName().c_str());
+ }
+ }
+ lua_setfield(L, -2, "inventory");
+ return 1;
}
- // set_allow_text_input(self, text)
- static int l_set_allow_text_input(lua_State *L)
+ // from_table(self, table)
+ static int l_from_table(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- bool b = lua_toboolean(L, 2);
- meta->setAllowTextInput(b);
+ int base = 2;
+
+ if(lua_isnil(L, base)){
+ // No metadata
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ lua_pushboolean(L, true);
+ return 1;
+ }
+
+ // Has metadata; clear old one first
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ // Create new metadata
+ NodeMetadata *meta = getmeta(ref, true);
+ // Set fields
+ lua_getfield(L, base, "fields");
+ int fieldstable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, fieldstable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ size_t cl;
+ const char *cs = lua_tolstring(L, -1, &cl);
+ std::string value(cs, cl);
+ meta->setString(name, value);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
+ // Set inventory
+ Inventory *inv = meta->getInventory();
+ lua_getfield(L, base, "inventory");
+ int inventorytable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, inventorytable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ inventory_set_list_from_lua(inv, name.c_str(), L, -1);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
reportMetadataChange(ref);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
- // set_allow_removal(self, text)
- static int l_set_allow_removal(lua_State *L)
+public:
+ NodeMetaRef(v3s16 p, ServerEnvironment *env):
+ m_p(p),
+ m_env(env)
{
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- bool b = lua_toboolean(L, 2);
- meta->setRemovalDisabled(!b);
- reportMetadataChange(ref);
- return 0;
}
- // set_enforce_owner(self, text)
- static int l_set_enforce_owner(lua_State *L)
+ ~NodeMetaRef()
{
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- bool b = lua_toboolean(L, 2);
- meta->setEnforceOwner(b);
- reportMetadataChange(ref);
- return 0;
}
- // is_inventory_modified(self)
- static int l_is_inventory_modified(lua_State *L)
+ // Creates an NodeMetaRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, v3s16 p, ServerEnvironment *env)
{
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- lua_pushboolean(L, meta->isInventoryModified());
- return 1;
+ NodeMetaRef *o = new NodeMetaRef(p, env);
+ //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
}
- // reset_inventory_modified(self)
- static int l_reset_inventory_modified(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- meta->resetInventoryModified();
- reportMetadataChange(ref);
- return 0;
- }
-
- // is_text_modified(self)
- static int l_is_text_modified(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- lua_pushboolean(L, meta->isTextModified());
- return 1;
- }
-
- // reset_text_modified(self)
- static int l_reset_text_modified(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- meta->resetTextModified();
- reportMetadataChange(ref);
- return 0;
- }
-
- // set_string(self, name, var)
- static int l_set_string(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string name = luaL_checkstring(L, 2);
- size_t len = 0;
- const char *s = lua_tolstring(L, 3, &len);
- std::string str(s, len);
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_string(self, name)
- static int l_get_string(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- std::string name = luaL_checkstring(L, 2);
- std::string str = meta->getString(name);
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
- }
-
-public:
- NodeMetaRef(v3s16 p, ServerEnvironment *env):
- m_p(p),
- m_env(env)
- {
- }
-
- ~NodeMetaRef()
- {
- }
-
- // Creates an NodeMetaRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, v3s16 p, ServerEnvironment *env)
- {
- NodeMetaRef *o = new NodeMetaRef(p, env);
- //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
-
- static void Register(lua_State *L)
+ static void Register(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
};
const char NodeMetaRef::className[] = "NodeMetaRef";
const luaL_reg NodeMetaRef::methods[] = {
- method(NodeMetaRef, get_type),
- method(NodeMetaRef, allows_text_input),
- method(NodeMetaRef, set_text),
- method(NodeMetaRef, get_text),
- method(NodeMetaRef, get_owner),
- method(NodeMetaRef, set_owner),
- method(NodeMetaRef, get_allow_removal),
- method(NodeMetaRef, set_infotext),
- method(NodeMetaRef, get_inventory),
- method(NodeMetaRef, set_inventory_draw_spec),
- method(NodeMetaRef, set_allow_text_input),
- method(NodeMetaRef, set_allow_removal),
- method(NodeMetaRef, set_enforce_owner),
- method(NodeMetaRef, is_inventory_modified),
- method(NodeMetaRef, reset_inventory_modified),
- method(NodeMetaRef, is_text_modified),
- method(NodeMetaRef, reset_text_modified),
- method(NodeMetaRef, set_string),
method(NodeMetaRef, get_string),
+ method(NodeMetaRef, set_string),
+ method(NodeMetaRef, get_int),
+ method(NodeMetaRef, set_int),
+ method(NodeMetaRef, get_float),
+ method(NodeMetaRef, set_float),
+ method(NodeMetaRef, get_inventory),
+ method(NodeMetaRef, to_table),
+ method(NodeMetaRef, from_table),
{0,0}
};
static const char className[];
static const luaL_reg methods[];
-
+public:
static ObjectRef *checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
ServerActiveObject *co = ref->m_object;
return co;
}
-
+private:
static LuaEntitySAO* getluaobject(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
return (LuaEntitySAO*)obj;
}
- static ServerRemotePlayer* getplayer(ObjectRef *ref)
+ static PlayerSAO* getplayersao(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
if(obj == NULL)
return NULL;
if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
return NULL;
- return static_cast<ServerRemotePlayer*>(obj);
+ return (PlayerSAO*)obj;
+ }
+
+ static Player* getplayer(ObjectRef *ref)
+ {
+ PlayerSAO *playersao = getplayersao(ref);
+ if(playersao == NULL)
+ return NULL;
+ return playersao->getPlayer();
}
// Exported functions
v3f pos = checkFloatPos(L, 2);
// Do it
co->setPos(pos);
- // Move player if applicable
- ServerRemotePlayer *player = getplayer(ref);
- if(player != NULL)
- get_server(L)->SendMovePlayer(player);
return 0;
}
return 1;
}
+ // set_armor_groups(self, groups)
+ static int l_set_armor_groups(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ ItemGroupList groups;
+ read_groups(L, 2, groups);
+ co->setArmorGroups(groups);
+ return 0;
+ }
+
+ // set_properties(self, properties)
+ static int l_set_properties(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ ObjectProperties *prop = co->accessObjectProperties();
+ if(!prop)
+ return 0;
+ read_object_properties(L, 2, prop);
+ co->notifyObjectPropertiesModified();
+ return 0;
+ }
+
/* LuaEntitySAO-only */
// setvelocity(self, {x=num, y=num, z=num})
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
if(co == NULL) return 0;
- // pos
v3f pos = checkFloatPos(L, 2);
// Do it
co->setVelocity(pos);
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
if(co == NULL) return 0;
- // pos
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setYaw(yaw);
return 0;
}
- // set_armor_groups(self, groups)
- static int l_set_armor_groups(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- ItemGroupList groups;
- read_groups(L, 2, groups);
- co->setArmorGroups(groups);
- return 0;
- }
-
// DEPRECATED
// get_entity_name(self)
static int l_get_entity_name(lua_State *L)
}
/* Player-only */
+
+ // is_player(self)
+ static int l_is_player(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ lua_pushboolean(L, (player != NULL));
+ return 1;
+ }
// get_player_name(self)
static int l_get_player_name(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL){
- lua_pushnil(L);
+ lua_pushlstring(L, "", 0);
return 1;
}
// Do it
static int l_get_look_dir(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
float pitch = player->getRadPitch();
static int l_get_look_pitch(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadPitch());
static int l_get_look_yaw(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadYaw());
method(ObjectRef, get_wield_index),
method(ObjectRef, get_wielded_item),
method(ObjectRef, set_wielded_item),
+ method(ObjectRef, set_armor_groups),
+ method(ObjectRef, set_properties),
// LuaEntitySAO-only
method(ObjectRef, setvelocity),
method(ObjectRef, getvelocity),
method(ObjectRef, getyaw),
method(ObjectRef, settexturemod),
method(ObjectRef, setsprite),
- method(ObjectRef, set_armor_groups),
method(ObjectRef, get_entity_name),
method(ObjectRef, get_luaentity),
// Player-only
}
}
+
+/*
+ PerlinNoise
+ */
+
+class LuaPerlinNoise
+{
+private:
+ int seed;
+ int octaves;
+ double persistence;
+ double scale;
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L)
+ {
+ LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
+
+ static int l_get2d(lua_State *L)
+ {
+ LuaPerlinNoise *o = checkobject(L, 1);
+ v2f pos2d = read_v2f(L,2);
+ lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
+ lua_pushnumber(L, val);
+ return 1;
+ }
+ static int l_get3d(lua_State *L)
+ {
+ LuaPerlinNoise *o = checkobject(L, 1);
+ v3f pos3d = read_v3f(L,2);
+ lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
+ lua_pushnumber(L, val);
+ return 1;
+ }
+
+public:
+ LuaPerlinNoise(int a_seed, int a_octaves, double a_persistence,
+ double a_scale):
+ seed(a_seed),
+ octaves(a_octaves),
+ persistence(a_persistence),
+ scale(a_scale)
+ {
+ }
+
+ ~LuaPerlinNoise()
+ {
+ }
+
+ // LuaPerlinNoise(seed, octaves, persistence, scale)
+ // Creates an LuaPerlinNoise and leaves it on top of stack
+ static int create_object(lua_State *L)
+ {
+ int seed = luaL_checkint(L, 1);
+ int octaves = luaL_checkint(L, 2);
+ double persistence = luaL_checknumber(L, 3);
+ double scale = luaL_checknumber(L, 4);
+ LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+
+ static LuaPerlinNoise* checkobject(lua_State *L, int narg)
+ {
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaPerlinNoise**)ud; // unbox pointer
+ }
+
+ static void 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
+
+ // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
+ lua_register(L, className, create_object);
+ }
+};
+const char LuaPerlinNoise::className[] = "PerlinNoise";
+const luaL_reg LuaPerlinNoise::methods[] = {
+ method(LuaPerlinNoise, get2d),
+ method(LuaPerlinNoise, get3d),
+ {0,0}
+};
+
/*
EnvRef
*/
static const char className[];
static const luaL_reg methods[];
+ static int gc_object(lua_State *L) {
+ EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
+
static EnvRef *checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
// Exported functions
- // EnvRef:add_node(pos, node)
+ // EnvRef:set_node(pos, node)
// pos = {x=num, y=num, z=num}
- static int l_add_node(lua_State *L)
+ static int l_set_node(lua_State *L)
{
- //infostream<<"EnvRef::l_add_node()"<<std::endl;
+ //infostream<<"EnvRef::l_set_node()"<<std::endl;
EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
// content
MapNode n = readnode(L, 3, env->getGameDef()->ndef());
// Do it
+ // Call destructor
+ MapNode n_old = env->getMap().getNodeNoEx(pos);
+ scriptapi_node_on_destruct(L, pos, n_old);
+ // Replace node
bool succeeded = env->getMap().addNodeWithEvent(pos, n);
lua_pushboolean(L, succeeded);
+ // Call constructor
+ if(succeeded)
+ scriptapi_node_on_construct(L, pos, n);
return 1;
}
+ static int l_add_node(lua_State *L)
+ {
+ return l_set_node(L);
+ }
+
// EnvRef:remove_node(pos)
// pos = {x=num, y=num, z=num}
static int l_remove_node(lua_State *L)
// pos
v3s16 pos = read_v3s16(L, 2);
// Do it
+ // Call destructor
+ MapNode n = env->getMap().getNodeNoEx(pos);
+ scriptapi_node_on_destruct(L, pos, n);
+ // Replace with air
bool succeeded = env->getMap().removeNodeWithEvent(pos);
lua_pushboolean(L, succeeded);
+ // Air doesn't require constructor
return 1;
}
ItemStack item = read_item(L, 3);
if(item.empty() || !item.isKnown(get_server(L)->idef()))
return 0;
- // Do it
+ // Use minetest.spawn_item to spawn a __builtin:item
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "spawn_item");
+ if(lua_isnil(L, -1))
+ return 0;
+ lua_pushvalue(L, 2);
+ lua_pushstring(L, item.getItemString().c_str());
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ 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)
return 0;
// Return ObjectRef
objectref_get_or_create(L, obj);
- return 1;
+ return 1;*/
}
// EnvRef:add_rat(pos)
if(env == NULL) return 0;
// Do it
const char *name = luaL_checkstring(L, 2);
- ServerRemotePlayer *player =
- static_cast<ServerRemotePlayer*>(env->getPlayer(name));
+ Player *player = env->getPlayer(name);
if(player == NULL){
lua_pushnil(L);
return 1;
}
+ PlayerSAO *sao = player->getPlayerSAO();
+ if(sao == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
// Put player on stack
- objectref_get_or_create(L, player);
+ objectref_get_or_create(L, sao);
return 1;
}
return 1;
}
- static int gc_object(lua_State *L) {
- EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-public:
- EnvRef(ServerEnvironment *env):
- m_env(env)
+ // EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_node_near(lua_State *L)
{
- //infostream<<"EnvRef created"<<std::endl;
- }
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ INodeDefManager *ndef = get_server(L)->ndef();
+ v3s16 pos = read_v3s16(L, 2);
+ int radius = luaL_checkinteger(L, 3);
+ std::set<content_t> filter;
+ if(lua_istable(L, 4)){
+ int table = 4;
+ lua_pushnil(L);
+ while(lua_next(L, table) != 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, 4)){
+ ndef->getIds(lua_tostring(L, 4), filter);
+ }
- ~EnvRef()
- {
- //infostream<<"EnvRef destructing"<<std::endl;
+ for(int d=1; d<=radius; d++){
+ core::list<v3s16> list;
+ getFacePositions(list, d);
+ for(core::list<v3s16>::Iterator i = list.begin();
+ i != list.end(); i++){
+ v3s16 p = pos + (*i);
+ content_t c = env->getMap().getNodeNoEx(p).getContent();
+ if(filter.count(c) != 0){
+ push_v3s16(L, p);
+ return 1;
+ }
+ }
+ }
+ return 0;
}
- // Creates an EnvRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, ServerEnvironment *env)
+ // EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_in_area(lua_State *L)
{
- EnvRef *o = new EnvRef(env);
- //infostream<<"EnvRef::create: o="<<o<<std::endl;
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ INodeDefManager *ndef = get_server(L)->ndef();
+ v3s16 minp = read_v3s16(L, 2);
+ v3s16 maxp = read_v3s16(L, 3);
+ std::set<content_t> filter;
+ if(lua_istable(L, 4)){
+ int table = 4;
+ lua_pushnil(L);
+ while(lua_next(L, table) != 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, 4)){
+ ndef->getIds(lua_tostring(L, 4), filter);
+ }
+
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ 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){
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ push_v3s16(L, p);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ }
+ return 1;
+ }
+
+ // EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
+ // returns world-specific PerlinNoise
+ static int l_get_perlin(lua_State *L)
+ {
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ int seeddiff = luaL_checkint(L, 2);
+ int octaves = luaL_checkint(L, 3);
+ double persistence = luaL_checknumber(L, 4);
+ double scale = luaL_checknumber(L, 5);
+
+ LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
+ luaL_getmetatable(L, "PerlinNoise");
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+
+public:
+ EnvRef(ServerEnvironment *env):
+ m_env(env)
+ {
+ //infostream<<"EnvRef created"<<std::endl;
+ }
+
+ ~EnvRef()
+ {
+ //infostream<<"EnvRef destructing"<<std::endl;
+ }
+
+ // Creates an EnvRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, ServerEnvironment *env)
+ {
+ EnvRef *o = new EnvRef(env);
+ //infostream<<"EnvRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
};
const char EnvRef::className[] = "EnvRef";
const luaL_reg EnvRef::methods[] = {
+ method(EnvRef, set_node),
method(EnvRef, add_node),
method(EnvRef, remove_node),
method(EnvRef, get_node),
method(EnvRef, get_objects_inside_radius),
method(EnvRef, set_timeofday),
method(EnvRef, get_timeofday),
+ method(EnvRef, find_node_near),
+ method(EnvRef, find_nodes_in_area),
+ method(EnvRef, get_perlin),
{0,0}
};
/*
- Global functions
+ LuaPseudoRandom
+*/
+
+
+class LuaPseudoRandom
+{
+private:
+ PseudoRandom m_pseudo;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L)
+ {
+ LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
+
+ // next(self, min=0, max=32767) -> get next value
+ static int l_next(lua_State *L)
+ {
+ LuaPseudoRandom *o = checkobject(L, 1);
+ int min = 0;
+ int max = 32767;
+ lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
+ if(!lua_isnil(L, 2))
+ min = luaL_checkinteger(L, 2);
+ if(!lua_isnil(L, 3))
+ max = luaL_checkinteger(L, 3);
+ if(max - min != 32767 && max - min > 32767/5)
+ throw LuaError(L, "PseudoRandom.next() max-min is not 32767 and is > 32768/5. This is disallowed due to the bad random distribution the implementation would otherwise make.");
+ PseudoRandom &pseudo = o->m_pseudo;
+ int val = pseudo.next();
+ val = (val % (max-min+1)) + min;
+ lua_pushinteger(L, val);
+ return 1;
+ }
+
+public:
+ LuaPseudoRandom(int seed):
+ m_pseudo(seed)
+ {
+ }
+
+ ~LuaPseudoRandom()
+ {
+ }
+
+ const PseudoRandom& getItem() const
+ {
+ return m_pseudo;
+ }
+ PseudoRandom& getItem()
+ {
+ return m_pseudo;
+ }
+
+ // LuaPseudoRandom(seed)
+ // Creates an LuaPseudoRandom and leaves it on top of stack
+ static int create_object(lua_State *L)
+ {
+ int seed = luaL_checknumber(L, 1);
+ LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+
+ static LuaPseudoRandom* checkobject(lua_State *L, int narg)
+ {
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaPseudoRandom**)ud; // unbox pointer
+ }
+
+ static void 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
+
+ // Can be created from Lua (LuaPseudoRandom(seed))
+ lua_register(L, className, create_object);
+ }
+};
+const char LuaPseudoRandom::className[] = "PseudoRandom";
+const luaL_reg LuaPseudoRandom::methods[] = {
+ method(LuaPseudoRandom, next),
+ {0,0}
+};
+
+
+
+/*
+ LuaABM
*/
class LuaABM : public ActiveBlockModifier
}
};
+/*
+ ServerSoundParams
+*/
+
+static void read_server_sound_params(lua_State *L, int index,
+ ServerSoundParams ¶ms)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+ // Clear
+ params = ServerSoundParams();
+ if(lua_istable(L, index)){
+ getfloatfield(L, index, "gain", params.gain);
+ getstringfield(L, index, "to_player", params.to_player);
+ lua_getfield(L, index, "pos");
+ if(!lua_isnil(L, -1)){
+ v3f p = read_v3f(L, -1)*BS;
+ params.pos = p;
+ params.type = ServerSoundParams::SSP_POSITIONAL;
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, index, "object");
+ if(!lua_isnil(L, -1)){
+ ObjectRef *ref = ObjectRef::checkobject(L, -1);
+ ServerActiveObject *sao = ObjectRef::getobject(ref);
+ if(sao){
+ params.object = sao->getId();
+ params.type = ServerSoundParams::SSP_OBJECT;
+ }
+ }
+ lua_pop(L, 1);
+ params.max_hear_distance = BS*getfloatfield_default(L, index,
+ "max_hear_distance", params.max_hear_distance/BS);
+ getboolfield(L, index, "loop", params.loop);
+ }
+}
+
+/*
+ Global functions
+*/
+
// debug(text)
// Writes a line to dstream
static int l_debug(lua_State *L)
return 0; /* number of results */
}
+// setting_set(name, value)
+static int l_setting_set(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+ const char *value = luaL_checkstring(L, 2);
+ g_settings->set(name, value);
+ return 0;
+}
+
// setting_get(name)
static int l_setting_get(lua_State *L)
{
// Do it
lua_newtable(L);
int table = lua_gettop(L);
- u64 privs_i = server->getPlayerEffectivePrivs(name);
- std::set<std::string> privs_s = privsToSet(privs_i);
+ std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
for(std::set<std::string>::const_iterator
i = privs_s.begin(); i != privs_s.end(); i++){
lua_pushboolean(L, true);
// get_modpath(modname)
static int l_get_modpath(lua_State *L)
{
- const char *modname = luaL_checkstring(L, 1);
+ std::string modname = luaL_checkstring(L, 1);
// Do it
+ if(modname == "__builtin"){
+ std::string path = get_server(L)->getBuiltinLuaPath();
+ lua_pushstring(L, path.c_str());
+ return 1;
+ }
const ModSpec *mod = get_server(L)->getModSpec(modname);
if(!mod){
lua_pushnil(L);
return 1;
}
+// sound_play(spec, parameters)
+static int l_sound_play(lua_State *L)
+{
+ SimpleSoundSpec spec;
+ read_soundspec(L, 1, spec);
+ ServerSoundParams params;
+ read_server_sound_params(L, 2, params);
+ s32 handle = get_server(L)->playSound(spec, params);
+ lua_pushinteger(L, handle);
+ return 1;
+}
+
+// sound_stop(handle)
+static int l_sound_stop(lua_State *L)
+{
+ int handle = luaL_checkinteger(L, 1);
+ get_server(L)->stopSound(handle);
+ return 0;
+}
+
+// is_singleplayer()
+static int l_is_singleplayer(lua_State *L)
+{
+ lua_pushboolean(L, get_server(L)->isSingleplayer());
+ return 1;
+}
+
+// get_password_hash(name, raw_password)
+static int l_get_password_hash(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+ std::string raw_password = luaL_checkstring(L, 2);
+ std::string hash = translatePassword(name,
+ narrow_to_wide(raw_password));
+ lua_pushstring(L, hash.c_str());
+ return 1;
+}
+
+// notify_authentication_modified(name)
+static int l_notify_authentication_modified(lua_State *L)
+{
+ std::string name = "";
+ if(lua_isstring(L, 1))
+ name = lua_tostring(L, 1);
+ get_server(L)->reportPrivsModified(name);
+ return 0;
+}
+
+// get_craft_result(input)
+static int l_get_craft_result(lua_State *L)
+{
+ int input_i = 1;
+ std::string method_s = getstringfield_default(L, input_i, "method", "normal");
+ enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
+ es_CraftMethod, CRAFT_METHOD_NORMAL);
+ int width = 1;
+ lua_getfield(L, input_i, "width");
+ if(lua_isnumber(L, -1))
+ width = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, input_i, "items");
+ std::vector<ItemStack> items = read_items(L, -1);
+ lua_pop(L, 1); // items
+
+ IGameDef *gdef = get_server(L);
+ ICraftDefManager *cdef = gdef->cdef();
+ CraftInput input(method, width, items);
+ CraftOutput output;
+ bool got = cdef->getCraftResult(input, output, true, gdef);
+ lua_newtable(L); // output table
+ if(got){
+ ItemStack item;
+ item.deSerialize(output.item, gdef->idef());
+ LuaItemStack::create(L, item);
+ lua_setfield(L, -2, "item");
+ setintfield(L, -1, "time", output.time);
+ } else {
+ LuaItemStack::create(L, ItemStack());
+ lua_setfield(L, -2, "item");
+ setintfield(L, -1, "time", 0);
+ }
+ lua_newtable(L); // decremented input table
+ lua_pushstring(L, method_s.c_str());
+ lua_setfield(L, -2, "method");
+ lua_pushinteger(L, width);
+ lua_setfield(L, -2, "width");
+ push_items(L, input.items);
+ lua_setfield(L, -2, "items");
+ return 2;
+}
+
static const struct luaL_Reg minetest_f [] = {
{"debug", l_debug},
{"log", l_log},
{"register_item_raw", l_register_item_raw},
{"register_alias_raw", l_register_alias_raw},
{"register_craft", l_register_craft},
+ {"setting_set", l_setting_set},
{"setting_get", l_setting_get},
{"setting_getbool", l_setting_getbool},
{"chat_send_all", l_chat_send_all},
{"get_current_modname", l_get_current_modname},
{"get_modpath", l_get_modpath},
{"get_worldpath", l_get_worldpath},
+ {"sound_play", l_sound_play},
+ {"sound_stop", l_sound_stop},
+ {"is_singleplayer", l_is_singleplayer},
+ {"get_password_hash", l_get_password_hash},
+ {"notify_authentication_modified", l_notify_authentication_modified},
+ {"get_craft_result", l_get_craft_result},
{NULL, NULL}
};
NodeMetaRef::Register(L);
ObjectRef::Register(L);
EnvRef::Register(L);
+ LuaPseudoRandom::Register(L);
+ LuaPerlinNoise::Register(L);
}
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
lua_settable(L, objectstable);
}
-bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
- const std::string &message)
+/*
+ misc
+*/
+
+// What scriptapi_run_callbacks does with the return values of callbacks.
+// Regardless of the mode, if only one callback is defined,
+// its return value is the total return value.
+// Modes only affect the case where 0 or >= 2 callbacks are defined.
+enum RunCallbacksMode
{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
+ // Returns the return value of the first callback
+ // Returns nil if list of callbacks is empty
+ RUN_CALLBACKS_MODE_FIRST,
+ // Returns the return value of the last callback
+ // Returns nil if list of callbacks is empty
+ RUN_CALLBACKS_MODE_LAST,
+ // If any callback returns a false value, the first such is returned
+ // Otherwise, the first callback's return value (trueish) is returned
+ // Returns true if list of callbacks is empty
+ RUN_CALLBACKS_MODE_AND,
+ // Like above, but stops calling callbacks (short circuit)
+ // after seeing the first false value
+ RUN_CALLBACKS_MODE_AND_SC,
+ // If any callback returns a true value, the first such is returned
+ // Otherwise, the first callback's return value (falseish) is returned
+ // Returns false if list of callbacks is empty
+ RUN_CALLBACKS_MODE_OR,
+ // Like above, but stops calling callbacks (short circuit)
+ // after seeing the first true value
+ RUN_CALLBACKS_MODE_OR_SC,
+ // Note: "a true value" and "a false value" refer to values that
+ // are converted by lua_toboolean to true or false, respectively.
+};
+
+// Push the list of callbacks (a lua table).
+// Then push nargs arguments.
+// Then call this function, which
+// - runs the callbacks
+// - removes the table and arguments from the lua stack
+// - pushes the return value, computed depending on mode
+static void scriptapi_run_callbacks(lua_State *L, int nargs,
+ RunCallbacksMode mode)
+{
+ // Insert the return value into the lua stack, below the table
+ assert(lua_gettop(L) >= nargs + 1);
+ lua_pushnil(L);
+ lua_insert(L, -(nargs + 1) - 1);
+ // Stack now looks like this:
+ // ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
+
+ int rv = lua_gettop(L) - nargs - 1;
+ int table = rv + 1;
+ int arg = table + 1;
+
+ luaL_checktype(L, table, LUA_TTABLE);
- // Get minetest.registered_on_chat_messages
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_chat_messages");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
// Foreach
lua_pushnil(L);
+ bool first_loop = true;
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TFUNCTION);
// Call function
- lua_pushstring(L, name.c_str());
- lua_pushstring(L, message.c_str());
- if(lua_pcall(L, 2, 1, 0))
+ for(int i = 0; i < nargs; i++)
+ lua_pushvalue(L, arg+i);
+ if(lua_pcall(L, nargs, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
- bool ate = lua_toboolean(L, -1);
- lua_pop(L, 1);
- if(ate)
- return true;
+
+ // Move return value to designated space in stack
+ // Or pop it
+ if(first_loop){
+ // Result of first callback is always moved
+ lua_replace(L, rv);
+ first_loop = false;
+ } else {
+ // Otherwise, what happens depends on the mode
+ if(mode == RUN_CALLBACKS_MODE_FIRST)
+ lua_pop(L, 1);
+ else if(mode == RUN_CALLBACKS_MODE_LAST)
+ lua_replace(L, rv);
+ else if(mode == RUN_CALLBACKS_MODE_AND ||
+ mode == RUN_CALLBACKS_MODE_AND_SC){
+ if(lua_toboolean(L, rv) == true &&
+ lua_toboolean(L, -1) == false)
+ lua_replace(L, rv);
+ else
+ lua_pop(L, 1);
+ }
+ else if(mode == RUN_CALLBACKS_MODE_OR ||
+ mode == RUN_CALLBACKS_MODE_OR_SC){
+ if(lua_toboolean(L, rv) == false &&
+ lua_toboolean(L, -1) == true)
+ lua_replace(L, rv);
+ else
+ lua_pop(L, 1);
+ }
+ else
+ assert(0);
+ }
+
+ // Handle short circuit modes
+ if(mode == RUN_CALLBACKS_MODE_AND_SC &&
+ lua_toboolean(L, rv) == false)
+ break;
+ else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
+ lua_toboolean(L, rv) == true)
+ break;
+
// value removed, keep key for next iteration
}
- return false;
+
+ // Remove stuff from stack, leaving only the return value
+ lua_settop(L, rv);
+
+ // Fix return value in case no callbacks were called
+ if(first_loop){
+ if(mode == RUN_CALLBACKS_MODE_AND ||
+ mode == RUN_CALLBACKS_MODE_AND_SC){
+ lua_pop(L, 1);
+ lua_pushboolean(L, true);
+ }
+ else if(mode == RUN_CALLBACKS_MODE_OR ||
+ mode == RUN_CALLBACKS_MODE_OR_SC){
+ lua_pop(L, 1);
+ lua_pushboolean(L, false);
+ }
+ }
}
-/*
- misc
-*/
+bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
+ const std::string &message)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_on_chat_messages
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, name.c_str());
+ lua_pushstring(L, message.c_str());
+ scriptapi_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
{
// Get minetest.registered_on_newplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_newplayers");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
}
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player)
{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_dieplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_dieplayers");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
-}
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+ // Get minetest.registered_on_dieplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_dieplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
{
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
- dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
-
- bool positioning_handled_by_some = false;
-
// Get minetest.registered_on_respawnplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_respawnplayers");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 1, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- bool positioning_handled = lua_toboolean(L, -1);
- lua_pop(L, 1);
- if(positioning_handled)
- positioning_handled_by_some = true;
- // value removed, keep key for next iteration
- }
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
+ bool positioning_handled_by_some = lua_toboolean(L, -1);
return positioning_handled_by_some;
}
-void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
+void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_on_joinplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_joinplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_on_leaveplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_leaveplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ Inventory *inv = player->getInventory();
+ assert(inv);
+
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
- inventory_set_list_from_lua(&player->inventory, "main", L, -1,
- PLAYER_INVENTORY_SIZE);
+ inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
+}
+
+static void get_auth_handler(lua_State *L)
+{
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_auth_handler");
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "builtin_auth_handler");
+ }
+ if(lua_type(L, -1) != LUA_TTABLE)
+ throw LuaError(L, "Authentication handler table not valid");
+}
+
+bool scriptapi_get_auth(lua_State *L, const std::string &playername,
+ std::string *dst_password, std::set<std::string> *dst_privs)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "get_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing get_auth");
+ lua_pushstring(L, playername.c_str());
+ if(lua_pcall(L, 1, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+
+ // nil = login not allowed
+ if(lua_isnil(L, -1))
+ return false;
+ luaL_checktype(L, -1, LUA_TTABLE);
+
+ std::string password;
+ bool found = getstringfield(L, -1, "password", password);
+ if(!found)
+ throw LuaError(L, "Authentication handler didn't return password");
+ if(dst_password)
+ *dst_password = password;
+
+ lua_getfield(L, -1, "privileges");
+ if(!lua_istable(L, -1))
+ throw LuaError(L,
+ "Authentication handler didn't return privilege table");
+ if(dst_privs)
+ read_privileges(L, -1, *dst_privs);
+ lua_pop(L, 1);
+
+ return true;
+}
+
+void scriptapi_create_auth(lua_State *L, const std::string &playername,
+ const std::string &password)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "create_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing create_auth");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+bool scriptapi_set_password(lua_State *L, const std::string &playername,
+ const std::string &password)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "set_password");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing set_password");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return lua_toboolean(L, -1);
}
/*
return true;
}
-bool scriptapi_node_on_punch(lua_State *L, v3s16 pos, MapNode node,
+bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
ServerActiveObject *puncher)
{
realitycheck(L);
return false;
// Call function
- push_v3s16(L, pos);
+ push_v3s16(L, p);
pushnode(L, node, ndef);
objectref_get_or_create(L, puncher);
if(lua_pcall(L, 3, 0, 0))
return true;
}
-bool scriptapi_node_on_dig(lua_State *L, v3s16 pos, MapNode node,
+bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
ServerActiveObject *digger)
{
realitycheck(L);
return false;
// Call function
- push_v3s16(L, pos);
+ push_v3s16(L, p);
pushnode(L, node, ndef);
objectref_get_or_create(L, digger);
if(lua_pcall(L, 3, 0, 0))
return true;
}
+void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_construct"))
+ return;
+
+ // Call function
+ push_v3s16(L, p);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_destruct"))
+ return;
+
+ // Call function
+ push_v3s16(L, p);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
+ const std::string &formname,
+ const std::map<std::string, std::string> &fields,
+ ServerActiveObject *sender)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_receive_fields"))
+ return;
+
+ // Call function
+ // param 1
+ push_v3s16(L, p);
+ // param 2
+ lua_pushstring(L, formname.c_str());
+ // param 3
+ lua_newtable(L);
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushstring(L, name.c_str());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ // param 4
+ objectref_get_or_create(L, sender);
+ if(lua_pcall(L, 4, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_move"))
+ return;
+
+ // function(pos, from_list, from_index, to_list, to_index, count, player)
+ push_v3s16(L, p);
+ lua_pushstring(L, from_list.c_str());
+ lua_pushinteger(L, from_index + 1);
+ lua_pushstring(L, to_list.c_str());
+ lua_pushinteger(L, to_index + 1);
+ lua_pushinteger(L, count);
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 7, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return stack;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_offer"))
+ return stack;
+
+ // Call function(pos, listname, index, stack, player)
+ push_v3s16(L, p);
+ lua_pushstring(L, listname.c_str());
+ lua_pushinteger(L, index + 1);
+ LuaItemStack::create(L, stack);
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return read_item(L, -1);
+}
+
+ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
+ const std::string &listname, int index, int count,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return ItemStack();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_take"))
+ return ItemStack();
+
+ // Call function(pos, listname, index, count, player)
+ push_v3s16(L, p);
+ lua_pushstring(L, listname.c_str());
+ lua_pushinteger(L, index + 1);
+ lua_pushinteger(L, count);
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return read_item(L, -1);
+}
+
/*
environment
*/
// Get minetest.registered_globalsteps
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_globalsteps");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- lua_pushnumber(L, dtime);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ // Call callbacks
+ lua_pushnumber(L, dtime);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
}
-void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp)
+void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
+ u32 blockseed)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
// Get minetest.registered_on_generateds
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_generateds");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- push_v3s16(L, minp);
- push_v3s16(L, maxp);
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ // Call callbacks
+ push_v3s16(L, minp);
+ push_v3s16(L, maxp);
+ lua_pushnumber(L, blockseed);
+ scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
}
/*
}
void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
- LuaEntityProperties *prop)
+ ObjectProperties *prop)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
luaentity_get(L, id);
//int object = lua_gettop(L);
- /* Read stuff */
-
- prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
-
- getboolfield(L, -1, "physical", prop->physical);
-
- getfloatfield(L, -1, "weight", prop->weight);
-
- lua_getfield(L, -1, "collisionbox");
- if(lua_istable(L, -1))
- prop->collisionbox = read_aabbox3df32(L, -1, 1.0);
- lua_pop(L, 1);
-
- getstringfield(L, -1, "visual", prop->visual);
+ // Set default values that differ from ObjectProperties defaults
+ prop->hp_max = 10;
- lua_getfield(L, -1, "visual_size");
- if(lua_istable(L, -1))
- prop->visual_size = read_v2f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "textures");
- if(lua_istable(L, -1)){
- prop->textures.clear();
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- prop->textures.push_back(lua_tostring(L, -1));
- else
- prop->textures.push_back("");
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
+ // Deprecated: read object properties directly
+ read_object_properties(L, -1, prop);
- lua_getfield(L, -1, "spritediv");
- if(lua_istable(L, -1))
- prop->spritediv = read_v2s16(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "initial_sprite_basepos");
- if(lua_istable(L, -1))
- prop->initial_sprite_basepos = read_v2s16(L, -1);
+ // Read initial_properties
+ lua_getfield(L, -1, "initial_properties");
+ read_object_properties(L, -1, prop);
lua_pop(L, 1);
}