]> git.lizzy.rs Git - minetest.git/blobdiff - src/scriptapi.cpp
Fix script error reporting a bit
[minetest.git] / src / scriptapi.cpp
index 83efef670e62631568f124107796f831fc1fdaad..db6b7e86e22ce27addaa58793eae9ed582c904ee 100644 (file)
@@ -386,6 +386,163 @@ static int getenumfield(lua_State *L, int table,
        return result;
 }
 
+static void setfloatfield(lua_State *L, int table,
+               const char *fieldname, float value)
+{
+       lua_pushnumber(L, value);
+       if(table < 0)
+               table -= 1;
+       lua_setfield(L, table, fieldname);
+}
+
+/*
+       Inventory stuff
+*/
+
+static void inventory_set_list_from_lua(Inventory *inv, const char *name,
+               lua_State *L, int tableindex, IGameDef *gamedef, int forcesize=-1)
+{
+       if(tableindex < 0)
+               tableindex = lua_gettop(L) + 1 + tableindex;
+       // If nil, delete list
+       if(lua_isnil(L, tableindex)){
+               inv->deleteList(name);
+               return;
+       }
+       // Otherwise set list
+       std::list<std::string> items;
+       luaL_checktype(L, tableindex, LUA_TTABLE);
+       int table = tableindex;
+       lua_pushnil(L);
+       while(lua_next(L, table) != 0){
+               // key at index -2 and value at index -1
+               luaL_checktype(L, -1, LUA_TSTRING);
+               std::string itemstring = lua_tostring(L, -1);
+               items.push_back(itemstring);
+               // removes value, keeps key for next iteration
+               lua_pop(L, 1);
+       }
+       int listsize = (forcesize != -1) ? forcesize : items.size();
+       InventoryList *invlist = inv->addList(name, listsize);
+       int index = 0;
+       for(std::list<std::string>::const_iterator
+                       i = items.begin(); i != items.end(); i++){
+               if(forcesize != -1 && index == forcesize)
+                       break;
+               const std::string &itemstring = *i;
+               InventoryItem *newitem = NULL;
+               if(itemstring != "")
+                       newitem = InventoryItem::deSerialize(itemstring,
+                                       gamedef);
+               InventoryItem *olditem = invlist->changeItem(index, newitem);
+               delete olditem;
+               index++;
+       }
+       while(forcesize != -1 && index < forcesize){
+               InventoryItem *olditem = invlist->changeItem(index, NULL);
+               delete olditem;
+               index++;
+       }
+}
+
+static void inventory_get_list_to_lua(Inventory *inv, const char *name,
+               lua_State *L)
+{
+       InventoryList *invlist = inv->getList(name);
+       if(invlist == NULL){
+               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++){
+               InventoryItem *item = invlist->getItem(i);
+               lua_pushvalue(L, table_insert);
+               lua_pushvalue(L, table);
+               if(item == NULL){
+                       lua_pushstring(L, "");
+               } else {
+                       lua_pushstring(L, item->getItemString().c_str());
+               }
+               if(lua_pcall(L, 2, 0, 0))
+                       script_error(L, "error: %s\n", lua_tostring(L, -1));
+       }
+}
+
+/*
+       ToolDiggingProperties
+*/
+
+static ToolDiggingProperties read_tool_digging_properties(
+               lua_State *L, int table)
+{
+       ToolDiggingProperties prop;
+       getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+       getfloatfield(L, table, "basetime", prop.basetime);
+       getfloatfield(L, table, "dt_weight", prop.dt_weight);
+       getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+       getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+       getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+       getfloatfield(L, table, "basedurability", prop.basedurability);
+       getfloatfield(L, table, "dd_weight", prop.dd_weight);
+       getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+       getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+       getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
+       return prop;
+}
+
+static void set_tool_digging_properties(lua_State *L, int table,
+               const ToolDiggingProperties &prop)
+{
+       setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+       setfloatfield(L, table, "basetime", prop.basetime);
+       setfloatfield(L, table, "dt_weight", prop.dt_weight);
+       setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+       setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+       setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+       setfloatfield(L, table, "basedurability", prop.basedurability);
+       setfloatfield(L, table, "dd_weight", prop.dd_weight);
+       setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+       setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+       setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
+}
+
+static void push_tool_digging_properties(lua_State *L,
+               const ToolDiggingProperties &prop)
+{
+       lua_newtable(L);
+       set_tool_digging_properties(L, -1, prop);
+}
+
+/*
+       ToolDefinition
+*/
+
+static ToolDefinition read_tool_definition(lua_State *L, int table)
+{
+       ToolDefinition def;
+       getstringfield(L, table, "image", def.imagename);
+       def.properties = read_tool_digging_properties(L, table);
+       return def;
+}
+
+static void push_tool_definition(lua_State *L, const ToolDefinition &def)
+{
+       lua_newtable(L);
+       lua_pushstring(L, def.imagename.c_str());
+       lua_setfield(L, -2, "image");
+       set_tool_digging_properties(L, -1, def.properties);
+}
+
+/*
+       EnumString definitions
+*/
+
 struct EnumString es_DrawType[] =
 {
        {NDT_NORMAL, "normal"},
@@ -599,19 +756,7 @@ static int l_register_tool(lua_State *L)
        IWritableToolDefManager *tooldef =
                        server->getWritableToolDefManager();
        
-       ToolDefinition def;
-       
-       getstringfield(L, table, "image", def.imagename);
-       getfloatfield(L, table, "basetime", def.properties.basetime);
-       getfloatfield(L, table, "dt_weight", def.properties.dt_weight);
-       getfloatfield(L, table, "dt_crackiness", def.properties.dt_crackiness);
-       getfloatfield(L, table, "dt_crumbliness", def.properties.dt_crumbliness);
-       getfloatfield(L, table, "dt_cuttability", def.properties.dt_cuttability);
-       getfloatfield(L, table, "basedurability", def.properties.basedurability);
-       getfloatfield(L, table, "dd_weight", def.properties.dd_weight);
-       getfloatfield(L, table, "dd_crackiness", def.properties.dd_crackiness);
-       getfloatfield(L, table, "dd_crumbliness", def.properties.dd_crumbliness);
-       getfloatfield(L, table, "dd_cuttability", def.properties.dd_cuttability);
+       ToolDefinition def = read_tool_definition(L, table);
 
        tooldef->registerTool(name, def);
        return 0; /* number of results */
@@ -956,7 +1101,10 @@ static int l_register_craft(lua_State *L)
                                width = colcount;
                        } else {
                                if(colcount != width){
-                                       script_error(L, "error: %s\n", "Invalid crafting recipe");
+                                       std::string error;
+                                       error += "Invalid crafting recipe (output=\""
+                                                       + output + "\")";
+                                       throw LuaError(error);
                                }
                        }
                        // removes value, keeps key for next iteration
@@ -1023,6 +1171,30 @@ static int l_chat_send_player(lua_State *L)
        return 0;
 }
 
+// get_player_privs(name, text)
+static int l_get_player_privs(lua_State *L)
+{
+       const char *name = luaL_checkstring(L, 1);
+       // Get server from registry
+       lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+       Server *server = (Server*)lua_touserdata(L, -1);
+       // Do it
+       lua_newtable(L);
+       int table = lua_gettop(L);
+       u64 privs_i = server->getPlayerAuthPrivs(name);
+       // Special case for the "name" setting (local player / server owner)
+       if(name == g_settings->get("name"))
+               privs_i = PRIV_ALL;
+       std::set<std::string> privs_s = privsToSet(privs_i);
+       for(std::set<std::string>::const_iterator
+                       i = privs_s.begin(); i != privs_s.end(); i++){
+               lua_pushboolean(L, true);
+               lua_setfield(L, table, i->c_str());
+       }
+       lua_pushvalue(L, table);
+       return 1;
+}
+
 static const struct luaL_Reg minetest_f [] = {
        {"register_nodedef_defaults", l_register_nodedef_defaults},
        {"register_entity", l_register_entity},
@@ -1035,6 +1207,7 @@ static const struct luaL_Reg minetest_f [] = {
        {"setting_getbool", l_setting_getbool},
        {"chat_send_all", l_chat_send_all},
        {"chat_send_player", l_chat_send_player},
+       {"get_player_privs", l_get_player_privs},
        {NULL, NULL}
 };
 
@@ -1227,41 +1400,9 @@ class NodeMetaRef
                if(meta == NULL) return 0;
                // Do it
                Inventory *inv = meta->getInventory();
-               std::string name = lua_tostring(L, 2);
-               // If nil, delete list
-               if(lua_isnil(L, 3)){
-                       inv->deleteList(name);
-                       return 0;
-               }
-               // Otherwise set list
-               std::list<std::string> items;
-               luaL_checktype(L, 3, LUA_TTABLE);
-               int table = 3;
-               lua_pushnil(L);
-               infostream<<"items: ";
-               while(lua_next(L, table) != 0){
-                       // key at index -2 and value at index -1
-                       luaL_checktype(L, -1, LUA_TSTRING);
-                       std::string itemstring = lua_tostring(L, -1);
-                       infostream<<"\""<<itemstring<<"\" ";
-                       items.push_back(itemstring);
-                       // removes value, keeps key for next iteration
-                       lua_pop(L, 1);
-               }
-               infostream<<std::endl;
-               InventoryList *invlist = inv->addList(name, items.size());
-               int index = 0;
-               for(std::list<std::string>::const_iterator
-                               i = items.begin(); i != items.end(); i++){
-                       const std::string &itemstring = *i;
-                       InventoryItem *newitem = NULL;
-                       if(itemstring != "")
-                               newitem = InventoryItem::deSerialize(itemstring,
-                                               ref->m_env->getGameDef());
-                       InventoryItem *olditem = invlist->changeItem(index, newitem);
-                       delete olditem;
-                       index++;
-               }
+               const char *name = lua_tostring(L, 2);
+               inventory_set_list_from_lua(inv, name, L, 3,
+                               ref->m_env->getGameDef());
                reportMetadataChange(ref);
                return 0;
        }
@@ -1274,31 +1415,8 @@ class NodeMetaRef
                if(meta == NULL) return 0;
                // Do it
                Inventory *inv = meta->getInventory();
-               std::string name = lua_tostring(L, 2);
-               InventoryList *invlist = inv->getList(name);
-               if(invlist == NULL){
-                       lua_pushnil(L);
-                       return 1;
-               }
-               // 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++){
-                       InventoryItem *item = invlist->getItem(i);
-                       lua_pushvalue(L, table_insert);
-                       lua_pushvalue(L, table);
-                       if(item == NULL){
-                               lua_pushnil(L);
-                       } else {
-                               lua_pushstring(L, item->getItemString().c_str());
-                       }
-                       if(lua_pcall(L, 2, 0, 0))
-                               script_error(L, "error: %s\n", lua_tostring(L, -1));
-               }
+               const char *name = lua_tostring(L, 2);
+               inventory_get_list_to_lua(inv, name, L);
                return 1;
        }
 
@@ -1503,183 +1621,469 @@ const luaL_reg NodeMetaRef::methods[] = {
 };
 
 /*
-       EnvRef
+       ObjectRef
 */
 
-class EnvRef
+class ObjectRef
 {
 private:
-       ServerEnvironment *m_env;
+       ServerActiveObject *m_object;
 
        static const char className[];
        static const luaL_reg methods[];
 
-       static EnvRef *checkobject(lua_State *L, int narg)
+       static ObjectRef *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 *(EnvRef**)ud;  // unbox pointer
+               return *(ObjectRef**)ud;  // unbox pointer
        }
        
-       // Exported functions
-
-       // EnvRef:add_node(pos, node)
-       // pos = {x=num, y=num, z=num}
-       static int l_add_node(lua_State *L)
+       static ServerActiveObject* getobject(ObjectRef *ref)
        {
-               //infostream<<"EnvRef::l_add_node()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3s16 pos = readpos(L, 2);
-               // content
-               MapNode n = readnode(L, 3, env->getGameDef()->ndef());
-               // Do it
-               bool succeeded = env->getMap().addNodeWithEvent(pos, n);
-               lua_pushboolean(L, succeeded);
-               return 1;
+               ServerActiveObject *co = ref->m_object;
+               return co;
        }
-
-       // EnvRef:remove_node(pos)
-       // pos = {x=num, y=num, z=num}
-       static int l_remove_node(lua_State *L)
+       
+       static LuaEntitySAO* getluaobject(ObjectRef *ref)
        {
-               //infostream<<"EnvRef::l_remove_node()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3s16 pos = readpos(L, 2);
-               // Do it
-               bool succeeded = env->getMap().removeNodeWithEvent(pos);
-               lua_pushboolean(L, succeeded);
-               return 1;
+               ServerActiveObject *obj = getobject(ref);
+               if(obj == NULL)
+                       return NULL;
+               if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+                       return NULL;
+               return (LuaEntitySAO*)obj;
+       }
+       
+       static ServerRemotePlayer* getplayer(ObjectRef *ref)
+       {
+               ServerActiveObject *obj = getobject(ref);
+               if(obj == NULL)
+                       return NULL;
+               if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
+                       return NULL;
+               return static_cast<ServerRemotePlayer*>(obj);
+       }
+       
+       // Exported functions
+       
+       // garbage collector
+       static int gc_object(lua_State *L) {
+               ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
+               //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
+               delete o;
+               return 0;
        }
 
-       // EnvRef:get_node(pos)
-       // pos = {x=num, y=num, z=num}
-       static int l_get_node(lua_State *L)
+       // remove(self)
+       static int l_remove(lua_State *L)
        {
-               //infostream<<"EnvRef::l_get_node()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3s16 pos = readpos(L, 2);
-               // Do it
-               MapNode n = env->getMap().getNodeNoEx(pos);
-               // Return node
-               pushnode(L, n, env->getGameDef()->ndef());
+               ObjectRef *ref = checkobject(L, 1);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
+               co->m_removed = true;
+               return 0;
+       }
+       
+       // getpos(self)
+       // returns: {x=num, y=num, z=num}
+       static int l_getpos(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               v3f pos = co->getBasePosition() / BS;
+               lua_newtable(L);
+               lua_pushnumber(L, pos.X);
+               lua_setfield(L, -2, "x");
+               lua_pushnumber(L, pos.Y);
+               lua_setfield(L, -2, "y");
+               lua_pushnumber(L, pos.Z);
+               lua_setfield(L, -2, "z");
                return 1;
        }
-
-       // EnvRef:add_luaentity(pos, entityname)
-       // pos = {x=num, y=num, z=num}
-       static int l_add_luaentity(lua_State *L)
+       
+       // setpos(self, pos)
+       static int l_setpos(lua_State *L)
        {
-               //infostream<<"EnvRef::l_add_luaentity()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
+               ObjectRef *ref = checkobject(L, 1);
+               //LuaEntitySAO *co = getluaobject(ref);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
-               // content
-               const char *name = lua_tostring(L, 3);
                // Do it
-               ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
-               env->addActiveObject(obj);
+               co->setPos(pos);
                return 0;
        }
-
-       // EnvRef:add_item(pos, inventorystring)
-       // pos = {x=num, y=num, z=num}
-       static int l_add_item(lua_State *L)
+       
+       // moveto(self, pos, continuous=false)
+       static int l_moveto(lua_State *L)
        {
-               infostream<<"EnvRef::l_add_item()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
+               ObjectRef *ref = checkobject(L, 1);
+               //LuaEntitySAO *co = getluaobject(ref);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
-               // inventorystring
-               const char *inventorystring = lua_tostring(L, 3);
+               // continuous
+               bool continuous = lua_toboolean(L, 3);
                // Do it
-               ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
-               env->addActiveObject(obj);
+               co->moveTo(pos, continuous);
                return 0;
        }
 
-       // EnvRef:add_rat(pos)
-       // pos = {x=num, y=num, z=num}
-       static int l_add_rat(lua_State *L)
+       // punch(self, puncher); puncher = an another ObjectRef
+       static int l_punch(lua_State *L)
        {
-               infostream<<"EnvRef::l_add_rat()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3f pos = readFloatPos(L, 2);
+               ObjectRef *ref = checkobject(L, 1);
+               ObjectRef *ref2 = checkobject(L, 2);
+               ServerActiveObject *co = getobject(ref);
+               ServerActiveObject *co2 = getobject(ref2);
+               if(co == NULL) return 0;
+               if(co2 == NULL) return 0;
                // Do it
-               ServerActiveObject *obj = new RatSAO(env, pos);
-               env->addActiveObject(obj);
+               co->punch(co2);
                return 0;
        }
 
-       // EnvRef:add_firefly(pos)
-       // pos = {x=num, y=num, z=num}
-       static int l_add_firefly(lua_State *L)
+       // right_click(self, clicker); clicker = an another ObjectRef
+       static int l_right_click(lua_State *L)
        {
-               infostream<<"EnvRef::l_add_firefly()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
+               ObjectRef *ref = checkobject(L, 1);
+               ObjectRef *ref2 = checkobject(L, 2);
+               ServerActiveObject *co = getobject(ref);
+               ServerActiveObject *co2 = getobject(ref2);
+               if(co == NULL) return 0;
+               if(co2 == NULL) return 0;
+               // Do it
+               co->rightClick(co2);
+               return 0;
+       }
+
+       // get_wield_digging_properties(self)
+       static int l_get_wield_digging_properties(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               // Do it
+               ToolDiggingProperties prop;
+               co->getWieldDiggingProperties(&prop);
+               push_tool_digging_properties(L, prop);
+               return 1;
+       }
+
+       // damage_wielded_item(self, amount)
+       static int l_damage_wielded_item(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               // Do it
+               int amount = lua_tonumber(L, 2);
+               co->damageWieldedItem(amount);
+               return 0;
+       }
+
+       // add_to_inventory(self, itemstring)
+       // returns: true if item was added, (false, "reason") otherwise
+       static int l_add_to_inventory(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               luaL_checkstring(L, 2);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               // itemstring
+               const char *itemstring = lua_tostring(L, 2);
+               infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
+                               <<" itemstring=\""<<itemstring<<"\""<<std::endl;
+               // Do it
+               std::istringstream is(itemstring, std::ios::binary);
+               ServerEnvironment *env = co->getEnv();
+               assert(env);
+               IGameDef *gamedef = env->getGameDef();
+               try{
+                       InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
+                       if(item->getCount() == 0)
+                               item->setCount(1);
+                       bool added = co->addToInventory(item);
+                       // Return
+                       lua_pushboolean(L, added);
+                       if(!added)
+                               lua_pushstring(L, "failed to add item");
+                       return 2;
+               } catch(SerializationError &e){
+                       // Return
+                       lua_pushboolean(L, false);
+                       lua_pushstring(L, (std::string("Invalid item: ")
+                                       + e.what()).c_str());
+                       return 2;
+               }
+       }
+
+       // add_to_inventory_later(self, itemstring)
+       // returns: nil
+       static int l_add_to_inventory_later(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               luaL_checkstring(L, 2);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               // itemstring
+               const char *itemstring = lua_tostring(L, 2);
+               infostream<<"ObjectRef::l_add_to_inventory_later(): id="<<co->getId()
+                               <<" itemstring=\""<<itemstring<<"\""<<std::endl;
+               // Do it
+               std::istringstream is(itemstring, std::ios::binary);
+               ServerEnvironment *env = co->getEnv();
+               assert(env);
+               IGameDef *gamedef = env->getGameDef();
+               InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
+               infostream<<"item="<<env<<std::endl;
+               co->addToInventoryLater(item);
+               // Return
+               return 0;
+       }
+
+       // set_hp(self, hp)
+       // hp = number of hitpoints (2 * number of hearts)
+       // returns: nil
+       static int l_set_hp(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               luaL_checknumber(L, 2);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               int hp = lua_tonumber(L, 2);
+               infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
+                               <<" hp="<<hp<<std::endl;
+               // Do it
+               co->setHP(hp);
+               // Return
+               return 0;
+       }
+
+       // get_hp(self)
+       // returns: number of hitpoints (2 * number of hearts)
+       // 0 if not applicable to this type of object
+       static int l_get_hp(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerActiveObject *co = getobject(ref);
+               if(co == NULL) return 0;
+               int hp = co->getHP();
+               infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
+                               <<" hp="<<hp<<std::endl;
+               // Return
+               lua_pushnumber(L, hp);
+               return 1;
+       }
+
+       /* LuaEntitySAO-only */
+
+       // setvelocity(self, {x=num, y=num, z=num})
+       static int l_setvelocity(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               LuaEntitySAO *co = getluaobject(ref);
+               if(co == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
                // Do it
-               ServerActiveObject *obj = new FireflySAO(env, pos);
-               env->addActiveObject(obj);
+               co->setVelocity(pos);
                return 0;
        }
-
-       // EnvRef:get_meta(pos)
-       static int l_get_meta(lua_State *L)
+       
+       // setacceleration(self, {x=num, y=num, z=num})
+       static int l_setacceleration(lua_State *L)
        {
-               //infostream<<"EnvRef::l_get_meta()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
+               ObjectRef *ref = checkobject(L, 1);
+               LuaEntitySAO *co = getluaobject(ref);
+               if(co == NULL) return 0;
+               // pos
+               v3f pos = readFloatPos(L, 2);
                // Do it
-               v3s16 p = readpos(L, 2);
-               NodeMetaRef::create(L, p, env);
+               co->setAcceleration(pos);
+               return 0;
+       }
+       
+       // getacceleration(self)
+       static int l_getacceleration(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               LuaEntitySAO *co = getluaobject(ref);
+               if(co == NULL) return 0;
+               // Do it
+               v3f v = co->getAcceleration();
+               pushFloatPos(L, v);
                return 1;
        }
+       
+       // settexturemod(self, mod)
+       static int l_settexturemod(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               LuaEntitySAO *co = getluaobject(ref);
+               if(co == NULL) return 0;
+               // Do it
+               std::string mod = lua_tostring(L, 2);
+               co->setTextureMod(mod);
+               return 0;
+       }
+       
+       // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
+       //           select_horiz_by_yawpitch=false)
+       static int l_setsprite(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               LuaEntitySAO *co = getluaobject(ref);
+               if(co == NULL) return 0;
+               // Do it
+               v2s16 p(0,0);
+               if(!lua_isnil(L, 2))
+                       p = read_v2s16(L, 2);
+               int num_frames = 1;
+               if(!lua_isnil(L, 3))
+                       num_frames = lua_tonumber(L, 3);
+               float framelength = 0.2;
+               if(!lua_isnil(L, 4))
+                       framelength = lua_tonumber(L, 4);
+               bool select_horiz_by_yawpitch = false;
+               if(!lua_isnil(L, 5))
+                       select_horiz_by_yawpitch = lua_toboolean(L, 5);
+               co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
+               return 0;
+       }
 
-       static int gc_object(lua_State *L) {
-               EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
-               delete o;
+       /* Player-only */
+       
+       // get_player_name(self)
+       static int l_get_player_name(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerRemotePlayer *player = getplayer(ref);
+               if(player == NULL){
+                       lua_pushnil(L);
+                       return 1;
+               }
+               // Do it
+               lua_pushstring(L, player->getName());
+               return 1;
+       }
+       
+       // inventory_set_list(self, name, {item1, item2, ...})
+       static int l_inventory_set_list(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerRemotePlayer *player = getplayer(ref);
+               if(player == NULL) return 0;
+               const char *name = lua_tostring(L, 2);
+               // Do it
+               inventory_set_list_from_lua(&player->inventory, name, L, 3,
+                               player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
+               player->m_inventory_not_sent = true;
                return 0;
        }
 
+       // inventory_get_list(self, name)
+       static int l_inventory_get_list(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerRemotePlayer *player = getplayer(ref);
+               if(player == NULL) return 0;
+               const char *name = lua_tostring(L, 2);
+               // Do it
+               inventory_get_list_to_lua(&player->inventory, name, L);
+               return 1;
+       }
+
+       // get_wielded_itemstring(self)
+       static int l_get_wielded_itemstring(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerRemotePlayer *player = getplayer(ref);
+               if(player == NULL) return 0;
+               // Do it
+               InventoryItem *item = player->getWieldedItem();
+               if(item == NULL){
+                       lua_pushnil(L);
+                       return 1;
+               }
+               lua_pushstring(L, item->getItemString().c_str());
+               return 1;
+       }
+
+       // get_wielded_item(self)
+       static int l_get_wielded_item(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               ServerRemotePlayer *player = getplayer(ref);
+               if(player == NULL) return 0;
+               // Do it
+               InventoryItem *item0 = player->getWieldedItem();
+               if(item0 == NULL){
+                       lua_pushnil(L);
+                       return 1;
+               }
+               if(std::string("MaterialItem") == item0->getName()){
+                       MaterialItem *item = (MaterialItem*)item0;
+                       lua_newtable(L);
+                       lua_pushstring(L, "NodeItem");
+                       lua_setfield(L, -2, "type");
+                       lua_pushstring(L, item->getNodeName().c_str());
+                       lua_setfield(L, -2, "name");
+               }
+               else if(std::string("CraftItem") == item0->getName()){
+                       CraftItem *item = (CraftItem*)item0;
+                       lua_newtable(L);
+                       lua_pushstring(L, "CraftItem");
+                       lua_setfield(L, -2, "type");
+                       lua_pushstring(L, item->getSubName().c_str());
+                       lua_setfield(L, -2, "name");
+               }
+               else if(std::string("ToolItem") == item0->getName()){
+                       ToolItem *item = (ToolItem*)item0;
+                       lua_newtable(L);
+                       lua_pushstring(L, "ToolItem");
+                       lua_setfield(L, -2, "type");
+                       lua_pushstring(L, item->getToolName().c_str());
+                       lua_setfield(L, -2, "name");
+                       lua_pushstring(L, itos(item->getWear()).c_str());
+                       lua_setfield(L, -2, "wear");
+               }
+               else{
+                       errorstream<<"l_get_wielded_item: Unknown item name: \""
+                                       <<item0->getName()<<"\""<<std::endl;
+                       lua_pushnil(L);
+               }
+               return 1;
+       }
+
 public:
-       EnvRef(ServerEnvironment *env):
-               m_env(env)
+       ObjectRef(ServerActiveObject *object):
+               m_object(object)
        {
-               infostream<<"EnvRef created"<<std::endl;
+               //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
        }
 
-       ~EnvRef()
+       ~ObjectRef()
        {
-               infostream<<"EnvRef destructing"<<std::endl;
+               /*if(m_object)
+                       infostream<<"ObjectRef destructing for id="
+                                       <<m_object->getId()<<std::endl;
+               else
+                       infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
        }
 
-       // Creates an EnvRef and leaves it on top of stack
+       // Creates an ObjectRef 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)
+       static void create(lua_State *L, ServerActiveObject *object)
        {
-               EnvRef *o = new EnvRef(env);
-               //infostream<<"EnvRef::create: o="<<o<<std::endl;
+               ObjectRef *o = new ObjectRef(object);
+               //infostream<<"ObjectRef::create: o="<<o<<std::endl;
                *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
                luaL_getmetatable(L, className);
                lua_setmetatable(L, -2);
@@ -1687,8 +2091,8 @@ class EnvRef
 
        static void set_null(lua_State *L)
        {
-               EnvRef *o = checkobject(L, -1);
-               o->m_env = NULL;
+               ObjectRef *o = checkobject(L, -1);
+               o->m_object = NULL;
        }
        
        static void Register(lua_State *L)
@@ -1719,313 +2123,244 @@ class EnvRef
                //lua_register(L, className, create_object);
        }
 };
-const char EnvRef::className[] = "EnvRef";
-const luaL_reg EnvRef::methods[] = {
-       method(EnvRef, add_node),
-       method(EnvRef, remove_node),
-       method(EnvRef, get_node),
-       method(EnvRef, add_luaentity),
-       method(EnvRef, add_item),
-       method(EnvRef, add_rat),
-       method(EnvRef, add_firefly),
-       method(EnvRef, get_meta),
+const char ObjectRef::className[] = "ObjectRef";
+const luaL_reg ObjectRef::methods[] = {
+       // ServerActiveObject
+       method(ObjectRef, remove),
+       method(ObjectRef, getpos),
+       method(ObjectRef, setpos),
+       method(ObjectRef, moveto),
+       method(ObjectRef, punch),
+       method(ObjectRef, right_click),
+       method(ObjectRef, get_wield_digging_properties),
+       method(ObjectRef, damage_wielded_item),
+       method(ObjectRef, add_to_inventory),
+       method(ObjectRef, add_to_inventory_later),
+       method(ObjectRef, set_hp),
+       method(ObjectRef, get_hp),
+       // LuaEntitySAO-only
+       method(ObjectRef, setvelocity),
+       method(ObjectRef, setacceleration),
+       method(ObjectRef, getacceleration),
+       method(ObjectRef, settexturemod),
+       method(ObjectRef, setsprite),
+       // Player-only
+       method(ObjectRef, get_player_name),
+       method(ObjectRef, inventory_set_list),
+       method(ObjectRef, inventory_get_list),
+       method(ObjectRef, get_wielded_itemstring),
+       method(ObjectRef, get_wielded_item),
        {0,0}
 };
 
+// Creates a new anonymous reference if id=0
+static void objectref_get_or_create(lua_State *L,
+               ServerActiveObject *cobj)
+{
+       if(cobj->getId() == 0){
+               ObjectRef::create(L, cobj);
+       } else {
+               objectref_get(L, cobj->getId());
+       }
+}
+
 /*
-       ObjectRef
+       EnvRef
 */
 
-class ObjectRef
+class EnvRef
 {
 private:
-       ServerActiveObject *m_object;
+       ServerEnvironment *m_env;
 
        static const char className[];
        static const luaL_reg methods[];
 
-       static ObjectRef *checkobject(lua_State *L, int narg)
+       static EnvRef *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 *(ObjectRef**)ud;  // unbox pointer
-       }
-       
-       static ServerActiveObject* getobject(ObjectRef *ref)
-       {
-               ServerActiveObject *co = ref->m_object;
-               return co;
-       }
-       
-       static LuaEntitySAO* getluaobject(ObjectRef *ref)
-       {
-               ServerActiveObject *obj = getobject(ref);
-               if(obj == NULL)
-                       return NULL;
-               if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
-                       return NULL;
-               return (LuaEntitySAO*)obj;
-       }
-       
-       static ServerRemotePlayer* getplayer(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 *(EnvRef**)ud;  // unbox pointer
        }
        
        // Exported functions
-       
-       // garbage collector
-       static int gc_object(lua_State *L) {
-               ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
-               //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
-               delete o;
-               return 0;
-       }
 
-       // remove(self)
-       static int l_remove(lua_State *L)
+       // EnvRef:add_node(pos, node)
+       // pos = {x=num, y=num, z=num}
+       static int l_add_node(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
-               co->m_removed = true;
-               return 0;
+               //infostream<<"EnvRef::l_add_node()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+               // pos
+               v3s16 pos = readpos(L, 2);
+               // content
+               MapNode n = readnode(L, 3, env->getGameDef()->ndef());
+               // Do it
+               bool succeeded = env->getMap().addNodeWithEvent(pos, n);
+               lua_pushboolean(L, succeeded);
+               return 1;
        }
-       
-       // getpos(self)
-       // returns: {x=num, y=num, z=num}
-       static int l_getpos(lua_State *L)
+
+       // EnvRef:remove_node(pos)
+       // pos = {x=num, y=num, z=num}
+       static int l_remove_node(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               v3f pos = co->getBasePosition() / BS;
-               lua_newtable(L);
-               lua_pushnumber(L, pos.X);
-               lua_setfield(L, -2, "x");
-               lua_pushnumber(L, pos.Y);
-               lua_setfield(L, -2, "y");
-               lua_pushnumber(L, pos.Z);
-               lua_setfield(L, -2, "z");
+               //infostream<<"EnvRef::l_remove_node()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+               // pos
+               v3s16 pos = readpos(L, 2);
+               // Do it
+               bool succeeded = env->getMap().removeNodeWithEvent(pos);
+               lua_pushboolean(L, succeeded);
                return 1;
        }
-       
-       // setpos(self, pos)
-       static int l_setpos(lua_State *L)
+
+       // EnvRef:get_node(pos)
+       // pos = {x=num, y=num, z=num}
+       static int l_get_node(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               //LuaEntitySAO *co = getluaobject(ref);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
+               //infostream<<"EnvRef::l_get_node()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
                // pos
-               v3f pos = readFloatPos(L, 2);
+               v3s16 pos = readpos(L, 2);
                // Do it
-               co->setPos(pos);
-               return 0;
+               MapNode n = env->getMap().getNodeNoEx(pos);
+               // Return node
+               pushnode(L, n, env->getGameDef()->ndef());
+               return 1;
        }
-       
-       // moveto(self, pos, continuous=false)
-       static int l_moveto(lua_State *L)
+
+       // EnvRef:add_luaentity(pos, entityname)
+       // pos = {x=num, y=num, z=num}
+       static int l_add_luaentity(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               //LuaEntitySAO *co = getluaobject(ref);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
+               //infostream<<"EnvRef::l_add_luaentity()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
-               // continuous
-               bool continuous = lua_toboolean(L, 3);
+               // content
+               const char *name = lua_tostring(L, 3);
                // Do it
-               co->moveTo(pos, continuous);
+               ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
+               env->addActiveObject(obj);
                return 0;
        }
 
-       // setvelocity(self, velocity)
-       static int l_setvelocity(lua_State *L)
+       // EnvRef:add_item(pos, inventorystring)
+       // pos = {x=num, y=num, z=num}
+       static int l_add_item(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               LuaEntitySAO *co = getluaobject(ref);
-               if(co == NULL) return 0;
+               infostream<<"EnvRef::l_add_item()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
+               // inventorystring
+               const char *inventorystring = lua_tostring(L, 3);
                // Do it
-               co->setVelocity(pos);
+               ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
+               env->addActiveObject(obj);
                return 0;
        }
-       
-       // setacceleration(self, acceleration)
-       static int l_setacceleration(lua_State *L)
+
+       // EnvRef:add_rat(pos)
+       // pos = {x=num, y=num, z=num}
+       static int l_add_rat(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               LuaEntitySAO *co = getluaobject(ref);
-               if(co == NULL) return 0;
+               infostream<<"EnvRef::l_add_rat()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
                // pos
                v3f pos = readFloatPos(L, 2);
                // Do it
-               co->setAcceleration(pos);
+               ServerActiveObject *obj = new RatSAO(env, pos);
+               env->addActiveObject(obj);
                return 0;
        }
-       
-       // getacceleration(self)
-       static int l_getacceleration(lua_State *L)
-       {
-               ObjectRef *ref = checkobject(L, 1);
-               LuaEntitySAO *co = getluaobject(ref);
-               if(co == NULL) return 0;
-               // Do it
-               v3f v = co->getAcceleration();
-               pushFloatPos(L, v);
-               return 1;
-       }
-       
-       // add_to_inventory(self, itemstring)
-       // returns: true if item was added, false otherwise
-       static int l_add_to_inventory(lua_State *L)
-       {
-               ObjectRef *ref = checkobject(L, 1);
-               luaL_checkstring(L, 2);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               // itemstring
-               const char *itemstring = lua_tostring(L, 2);
-               infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
-                               <<" itemstring=\""<<itemstring<<"\""<<std::endl;
-               // Do it
-               std::istringstream is(itemstring, std::ios::binary);
-               ServerEnvironment *env = co->getEnv();
-               assert(env);
-               IGameDef *gamedef = env->getGameDef();
-               InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
-               infostream<<"item="<<env<<std::endl;
-               bool fits = co->addToInventory(item);
-               // Return
-               lua_pushboolean(L, fits);
-               return 1;
-       }
 
-       // add_to_inventory_later(self, itemstring)
-       // returns: nil
-       static int l_add_to_inventory_later(lua_State *L)
+       // EnvRef:add_firefly(pos)
+       // pos = {x=num, y=num, z=num}
+       static int l_add_firefly(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               luaL_checkstring(L, 2);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               // itemstring
-               const char *itemstring = lua_tostring(L, 2);
-               infostream<<"ObjectRef::l_add_to_inventory_later(): id="<<co->getId()
-                               <<" itemstring=\""<<itemstring<<"\""<<std::endl;
+               infostream<<"EnvRef::l_add_firefly()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+               // pos
+               v3f pos = readFloatPos(L, 2);
                // Do it
-               std::istringstream is(itemstring, std::ios::binary);
-               ServerEnvironment *env = co->getEnv();
-               assert(env);
-               IGameDef *gamedef = env->getGameDef();
-               InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
-               infostream<<"item="<<env<<std::endl;
-               co->addToInventoryLater(item);
-               // Return
+               ServerActiveObject *obj = new FireflySAO(env, pos);
+               env->addActiveObject(obj);
                return 0;
        }
 
-       // get_hp(self)
-       // returns: number of hitpoints (2 * number of hearts)
-       // 0 if not applicable to this type of object
-       static int l_get_hp(lua_State *L)
+       // EnvRef:get_meta(pos)
+       static int l_get_meta(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               int hp = co->getHP();
-               infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
-                               <<" hp="<<hp<<std::endl;
-               // Return
-               lua_pushnumber(L, hp);
+               //infostream<<"EnvRef::l_get_meta()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+               // Do it
+               v3s16 p = readpos(L, 2);
+               NodeMetaRef::create(L, p, env);
                return 1;
        }
 
-       // set_hp(self, hp)
-       // hp = number of hitpoints (2 * number of hearts)
-       // returns: nil
-       static int l_set_hp(lua_State *L)
+       // EnvRef:get_player_by_name(name)
+       static int l_get_player_by_name(lua_State *L)
        {
-               ObjectRef *ref = checkobject(L, 1);
-               luaL_checknumber(L, 2);
-               ServerActiveObject *co = getobject(ref);
-               if(co == NULL) return 0;
-               int hp = lua_tonumber(L, 2);
-               infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
-                               <<" hp="<<hp<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
                // Do it
-               co->setHP(hp);
-               // Return
-               return 0;
+               const char *name = lua_tostring(L, 2);
+               ServerRemotePlayer *player =
+                               static_cast<ServerRemotePlayer*>(env->getPlayer(name));
+               if(player == NULL){
+                       lua_pushnil(L);
+                       return 1;
+               }
+               // Put player on stack
+               objectref_get_or_create(L, player);
+               return 1;
        }
 
-       // settexturemod(self, mod)
-       static int l_settexturemod(lua_State *L)
-       {
-               ObjectRef *ref = checkobject(L, 1);
-               LuaEntitySAO *co = getluaobject(ref);
-               if(co == NULL) return 0;
-               // Do it
-               std::string mod = lua_tostring(L, 2);
-               co->setTextureMod(mod);
-               return 0;
-       }
-       
-       // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
-       //           select_horiz_by_yawpitch=false)
-       static int l_setsprite(lua_State *L)
-       {
-               ObjectRef *ref = checkobject(L, 1);
-               LuaEntitySAO *co = getluaobject(ref);
-               if(co == NULL) return 0;
-               // Do it
-               v2s16 p(0,0);
-               if(!lua_isnil(L, 2))
-                       p = read_v2s16(L, 2);
-               int num_frames = 1;
-               if(!lua_isnil(L, 3))
-                       num_frames = lua_tonumber(L, 3);
-               float framelength = 0.2;
-               if(!lua_isnil(L, 4))
-                       framelength = lua_tonumber(L, 4);
-               bool select_horiz_by_yawpitch = false;
-               if(!lua_isnil(L, 5))
-                       select_horiz_by_yawpitch = lua_toboolean(L, 5);
-               co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
+       static int gc_object(lua_State *L) {
+               EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
+               delete o;
                return 0;
        }
-       
+
 public:
-       ObjectRef(ServerActiveObject *object):
-               m_object(object)
+       EnvRef(ServerEnvironment *env):
+               m_env(env)
        {
-               //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
+               infostream<<"EnvRef created"<<std::endl;
        }
 
-       ~ObjectRef()
+       ~EnvRef()
        {
-               /*if(m_object)
-                       infostream<<"ObjectRef destructing for id="
-                                       <<m_object->getId()<<std::endl;
-               else
-                       infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
+               infostream<<"EnvRef destructing"<<std::endl;
        }
 
-       // Creates an ObjectRef and leaves it on top of stack
+       // 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, ServerActiveObject *object)
+       static void create(lua_State *L, ServerEnvironment *env)
        {
-               ObjectRef *o = new ObjectRef(object);
-               //infostream<<"ObjectRef::create: o="<<o<<std::endl;
+               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);
@@ -2033,8 +2368,8 @@ class ObjectRef
 
        static void set_null(lua_State *L)
        {
-               ObjectRef *o = checkobject(L, -1);
-               o->m_object = NULL;
+               EnvRef *o = checkobject(L, -1);
+               o->m_env = NULL;
        }
        
        static void Register(lua_State *L)
@@ -2065,34 +2400,20 @@ class ObjectRef
                //lua_register(L, className, create_object);
        }
 };
-const char ObjectRef::className[] = "ObjectRef";
-const luaL_reg ObjectRef::methods[] = {
-       method(ObjectRef, remove),
-       method(ObjectRef, getpos),
-       method(ObjectRef, setpos),
-       method(ObjectRef, moveto),
-       method(ObjectRef, setvelocity),
-       method(ObjectRef, setacceleration),
-       method(ObjectRef, add_to_inventory),
-       method(ObjectRef, add_to_inventory_later),
-       method(ObjectRef, get_hp),
-       method(ObjectRef, set_hp),
-       method(ObjectRef, settexturemod),
-       method(ObjectRef, setsprite),
+const char EnvRef::className[] = "EnvRef";
+const luaL_reg EnvRef::methods[] = {
+       method(EnvRef, add_node),
+       method(EnvRef, remove_node),
+       method(EnvRef, get_node),
+       method(EnvRef, add_luaentity),
+       method(EnvRef, add_item),
+       method(EnvRef, add_rat),
+       method(EnvRef, add_firefly),
+       method(EnvRef, get_meta),
+       method(EnvRef, get_player_by_name),
        {0,0}
 };
 
-// Creates a new anonymous reference if id=0
-static void objectref_get_or_create(lua_State *L,
-               ServerActiveObject *cobj)
-{
-       if(cobj->getId() == 0){
-               ObjectRef::create(L, cobj);
-       } else {
-               objectref_get(L, cobj->getId());
-       }
-}
-
 /*
        Main export function
 */
@@ -2151,6 +2472,21 @@ void scriptapi_export(lua_State *L, Server *server)
        ObjectRef::Register(L);
 }
 
+bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
+               const std::string &modname)
+{
+       bool success = false;
+
+       try{
+               success = script_load(L, scriptpath.c_str());
+       }
+       catch(LuaError &e){
+               errorstream<<"Error loading mod: "<<e.what()<<std::endl;
+       }
+
+       return success;
+}
+
 void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
 {
        realitycheck(L);
@@ -2377,6 +2713,15 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
        return positioning_handled_by_some;
 }
 
+void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
+{
+       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->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
+}
+
 /*
        craftitem
 */
@@ -2892,9 +3237,9 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
                script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
 }
 
-// Calls entity:on_punch(ObjectRef puncher)
+// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch)
 void scriptapi_luaentity_punch(lua_State *L, u16 id,
-               ServerActiveObject *puncher)
+               ServerActiveObject *puncher, float time_from_last_punch)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
@@ -2912,8 +3257,9 @@ void scriptapi_luaentity_punch(lua_State *L, u16 id,
        luaL_checktype(L, -1, LUA_TFUNCTION);
        lua_pushvalue(L, object); // self
        objectref_get_or_create(L, puncher); // Clicker reference
+       lua_pushnumber(L, time_from_last_punch);
        // Call with 2 arguments, 0 results
-       if(lua_pcall(L, 2, 0, 0))
+       if(lua_pcall(L, 3, 0, 0))
                script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
 }