Create the necessary API for /giveme and /give and implement those commands; also sort out the scripts a bit

This commit is contained in:
Perttu Ahola 2011-11-29 21:30:22 +02:00
parent 2a610b011a
commit 103d4793f0
6 changed files with 534 additions and 382 deletions

@ -147,6 +147,155 @@ minetest.register_node("ignore", {
air_equivalent = true, air_equivalent = true,
}) })
--
-- stackstring manipulation functions
-- example stackstring: 'CraftItem "apple" 4'
-- example item: {type="CraftItem", name="apple"}
-- example item: {type="ToolItem", name="SteelPick", wear="23272"}
--
function stackstring_take_item(stackstring)
if stackstring == nil then
return '', nil
end
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
if stacktype == "NodeItem" or stacktype == "CraftItem" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemcount = tonumber(itemcount)
if itemcount == 0 then
return '', nil
elseif itemcount == 1 then
return '', {type=itemtype, name=itemname}
else
return itemtype.." \""..itemname.."\" "..(itemcount-1),
{type=itemtype, name=itemname}
end
elseif stacktype == "ToolItem" then
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return '', {type=itemtype, name=itemname, wear=itemwear}
end
end
function stackstring_put_item(stackstring, item)
if item == nil then
return stackstring, false
end
stackstring = stackstring or ''
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
stacktype = stacktype or ''
if stacktype ~= '' and stacktype ~= item.type then
return stackstring, false
end
if item.type == "NodeItem" or item.type == "CraftItem" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemtype = itemtype or item.type
itemname = itemname or item.name
if itemcount == nil then
itemcount = 0
end
itemcount = itemcount + 1
return itemtype.." \""..itemname.."\" "..itemcount, true
elseif item.type == "ToolItem" then
if stacktype ~= nil then
return stackstring, false
end
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return itemtype.." \""..itemname.."\" "..itemwear, true
end
return stackstring, false
end
function stackstring_put_stackstring(stackstring, src)
while src ~= '' do
--print("src="..dump(src))
src, item = stackstring_take_item(src)
--print("src="..dump(src).." item="..dump(item))
local success
stackstring, success = stackstring_put_item(stackstring, item)
if not success then
return stackstring, false
end
end
return stackstring, true
end
function test_stackstring()
local stack
local item
local success
stack, item = stackstring_take_item('NodeItem "TNT" 3')
assert(stack == 'NodeItem "TNT" 2')
assert(item.type == 'NodeItem')
assert(item.name == 'TNT')
stack, item = stackstring_take_item('CraftItem "with spaces" 2')
assert(stack == 'CraftItem "with spaces" 1')
assert(item.type == 'CraftItem')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "with spaces" 1')
assert(stack == '')
assert(item.type == 'CraftItem')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "s8df2kj3" 0')
assert(stack == '')
assert(item == nil)
stack, item = stackstring_take_item('ToolItem "With Spaces" 32487')
assert(stack == '')
assert(item.type == 'ToolItem')
assert(item.name == 'With Spaces')
assert(item.wear == 32487)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='NodeItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('CraftItem "With Spaces" 40',
{type='CraftItem', name='With Spaces'})
assert(stack == 'CraftItem "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('ToolItem "With Spaces" 32487',
{type='ToolItem', name='With Spaces'})
assert(stack == 'ToolItem "With Spaces" 32487')
assert(success == false)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='ToolItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 40')
assert(success == false)
assert(stackstring_put_stackstring('NodeItem "With Spaces" 2',
'NodeItem "With Spaces" 1') == 'NodeItem "With Spaces" 3')
end
test_stackstring()
-- --
-- Callback registration -- Callback registration
-- --

@ -26,6 +26,7 @@
-- minetest.setting_getbool(name) -- minetest.setting_getbool(name)
-- minetest.chat_send_all(text) -- minetest.chat_send_all(text)
-- minetest.chat_send_player(name, text) -- minetest.chat_send_player(name, text)
-- minetest.get_player_privs(name)
-- --
-- Global objects: -- Global objects:
-- minetest.env - environment reference -- minetest.env - environment reference
@ -52,6 +53,7 @@
-- - add_rat(pos) -- - add_rat(pos)
-- - add_firefly(pos) -- - add_firefly(pos)
-- - get_meta(pos) -- Get a NodeMetaRef at that position -- - get_meta(pos) -- Get a NodeMetaRef at that position
-- - get_player_by_name(name) -- Get an ObjectRef to a player
-- --
-- NodeMetaRef -- NodeMetaRef
-- - get_type() -- - get_type()
@ -1322,6 +1324,65 @@ function on_punchnode(p, node)
end end
minetest.register_on_punchnode(on_punchnode) minetest.register_on_punchnode(on_punchnode)
minetest.register_on_chat_message(function(name, message)
print("default on_chat_message: name="..dump(name).." message="..dump(message))
local cmd = "/giveme"
if message:sub(0, #cmd) == cmd then
if not minetest.get_player_privs(name)["give"] then
minetest.chat_send_player(name, "you don't have permission to give")
return true -- Handled chat message
end
stackstring = string.match(message, cmd.." (.*)")
if stackstring == nil then
minetest.chat_send_player(name, 'usage: '..cmd..' stackstring')
return true -- Handled chat message
end
print(cmd..' invoked, stackstring="'..stackstring..'"')
player = minetest.env:get_player_by_name(name)
added, error_msg = player:add_to_inventory(stackstring)
if added then
minetest.chat_send_player(name, '"'..stackstring
..'" added to inventory.');
else
minetest.chat_send_player(name, 'Could not give "'..stackstring
..'": '..error_msg);
end
return true -- Handled chat message
end
local cmd = "/give"
if message:sub(0, #cmd) == cmd then
print("minetest.get_player_privs(name)="
..dump(minetest.get_player_privs(name)))
if not minetest.get_player_privs(name)["give"] then
minetest.chat_send_player(name, "you don't have permission to give")
return true -- Handled chat message
end
name2, stackstring = string.match(message, cmd.." ([%a%d_-]+) (.*)")
if name == nil or stackstring == nil then
minetest.chat_send_player(name, 'usage: '..cmd..' name stackstring')
return true -- Handled chat message
end
print(cmd..' invoked, name2="'..name2
..'" stackstring="'..stackstring..'"')
player = minetest.env:get_player_by_name(name2)
if player == nil then
minetest.chat_send_player(name, name2..' is not a known player')
return true -- Handled chat message
end
added, error_msg = player:add_to_inventory(stackstring)
if added then
minetest.chat_send_player(name, '"'..stackstring
..'" added to '..name2..'\'s inventory.');
minetest.chat_send_player(name2, '"'..stackstring
..'" added to inventory.');
else
minetest.chat_send_player(name, 'Could not give "'..stackstring
..'": '..error_msg);
end
return true -- Handled chat message
end
end)
-- --
-- Done, print some random stuff -- Done, print some random stuff
-- --

@ -41,148 +41,6 @@ minetest.register_on_placenode(function(pos, newnode, placer)
end end
end) end)
function stackstring_take_item(stackstring)
if stackstring == nil then
return '', nil
end
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
if stacktype == "NodeItem" or stacktype == "CraftItem" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemcount = tonumber(itemcount)
if itemcount == 0 then
return '', nil
elseif itemcount == 1 then
return '', {type=itemtype, name=itemname}
else
return itemtype.." \""..itemname.."\" "..(itemcount-1),
{type=itemtype, name=itemname}
end
elseif stacktype == "ToolItem" then
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return '', {type=itemtype, name=itemname, wear=itemwear}
end
end
function stackstring_put_item(stackstring, item)
if item == nil then
return stackstring, false
end
stackstring = stackstring or ''
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
stacktype = stacktype or ''
if stacktype ~= '' and stacktype ~= item.type then
return stackstring, false
end
if item.type == "NodeItem" or item.type == "CraftItem" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemtype = itemtype or item.type
itemname = itemname or item.name
if itemcount == nil then
itemcount = 0
end
itemcount = itemcount + 1
return itemtype.." \""..itemname.."\" "..itemcount, true
elseif item.type == "ToolItem" then
if stacktype ~= nil then
return stackstring, false
end
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return itemtype.." \""..itemname.."\" "..itemwear, true
end
return stackstring, false
end
function stackstring_put_stackstring(stackstring, src)
while src ~= '' do
--print("src="..dump(src))
src, item = stackstring_take_item(src)
--print("src="..dump(src).." item="..dump(item))
local success
stackstring, success = stackstring_put_item(stackstring, item)
if not success then
return stackstring, false
end
end
return stackstring, true
end
function test_stack()
local stack
local item
local success
stack, item = stackstring_take_item('NodeItem "TNT" 3')
assert(stack == 'NodeItem "TNT" 2')
assert(item.type == 'NodeItem')
assert(item.name == 'TNT')
stack, item = stackstring_take_item('CraftItem "with spaces" 2')
assert(stack == 'CraftItem "with spaces" 1')
assert(item.type == 'CraftItem')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "with spaces" 1')
assert(stack == '')
assert(item.type == 'CraftItem')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "s8df2kj3" 0')
assert(stack == '')
assert(item == nil)
stack, item = stackstring_take_item('ToolItem "With Spaces" 32487')
assert(stack == '')
assert(item.type == 'ToolItem')
assert(item.name == 'With Spaces')
assert(item.wear == 32487)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='NodeItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('CraftItem "With Spaces" 40',
{type='CraftItem', name='With Spaces'})
assert(stack == 'CraftItem "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('ToolItem "With Spaces" 32487',
{type='ToolItem', name='With Spaces'})
assert(stack == 'ToolItem "With Spaces" 32487')
assert(success == false)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='ToolItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 40')
assert(success == false)
assert(stackstring_put_stackstring('NodeItem "With Spaces" 2',
'NodeItem "With Spaces" 1') == 'NodeItem "With Spaces" 3')
end
test_stack()
minetest.register_abm({ minetest.register_abm({
nodenames = {"luafurnace"}, nodenames = {"luafurnace"},
interval = 1.0, interval = 1.0,
@ -426,7 +284,7 @@ print("setting max_users = " .. dump(minetest.setting_get("max_users")))
print("setting asdf = " .. dump(minetest.setting_get("asdf"))) print("setting asdf = " .. dump(minetest.setting_get("asdf")))
minetest.register_on_chat_message(function(name, message) minetest.register_on_chat_message(function(name, message)
print("on_chat_message: name="..dump(name).." message="..dump(message)) --[[print("on_chat_message: name="..dump(name).." message="..dump(message))
local cmd = "/testcommand" local cmd = "/testcommand"
if message:sub(0, #cmd) == cmd then if message:sub(0, #cmd) == cmd then
print(cmd.." invoked") print(cmd.." invoked")
@ -437,7 +295,7 @@ minetest.register_on_chat_message(function(name, message)
print("script-overridden help command") print("script-overridden help command")
minetest.chat_send_all("script-overridden help command") minetest.chat_send_all("script-overridden help command")
return true return true
end end]]
end) end)
-- Grow papyrus on TNT every 10 seconds -- Grow papyrus on TNT every 10 seconds

@ -25,6 +25,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "strfnd.h" #include "strfnd.h"
#include "debug.h" #include "debug.h"
std::set<std::string> privsToSet(u64 privs)
{
std::set<std::string> s;
if(privs & PRIV_BUILD)
s.insert("build");
if(privs & PRIV_TELEPORT)
s.insert("teleport");
if(privs & PRIV_SETTIME)
s.insert("settime");
if(privs & PRIV_PRIVS)
s.insert("privs");
if(privs & PRIV_SHOUT)
s.insert("shout");
if(privs & PRIV_BAN)
s.insert("ban");
if(privs & PRIV_GIVE)
s.insert("give");
return s;
}
// Convert a privileges value into a human-readable string, // Convert a privileges value into a human-readable string,
// with each component separated by a comma. // with each component separated by a comma.
std::string privsToString(u64 privs) std::string privsToString(u64 privs)
@ -42,6 +62,8 @@ std::string privsToString(u64 privs)
os<<"shout,"; os<<"shout,";
if(privs & PRIV_BAN) if(privs & PRIV_BAN)
os<<"ban,"; os<<"ban,";
if(privs & PRIV_GIVE)
os<<"give,";
if(os.tellp()) if(os.tellp())
{ {
// Drop the trailing comma. (Why on earth can't // Drop the trailing comma. (Why on earth can't
@ -74,6 +96,8 @@ u64 stringToPrivs(std::string str)
privs |= PRIV_SHOUT; privs |= PRIV_SHOUT;
else if(s == "ban") else if(s == "ban")
privs |= PRIV_BAN; privs |= PRIV_BAN;
else if(s == "give")
privs |= PRIV_GIVE;
else else
return PRIV_INVALID; return PRIV_INVALID;
} }

@ -20,10 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef AUTH_HEADER #ifndef AUTH_HEADER
#define AUTH_HEADER #define AUTH_HEADER
#include <set>
#include <string> #include <string>
#include <jthread.h> #include <jthread.h>
#include <jmutex.h> #include <jmutex.h>
#include "common_irrlicht.h" #include "irrlichttypes.h"
#include "exceptions.h" #include "exceptions.h"
// Player privileges. These form a bitmask stored in the privs field // Player privileges. These form a bitmask stored in the privs field
@ -39,6 +40,7 @@ const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn
const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all
// players // players
const u64 PRIV_BAN = 64; // Can ban players const u64 PRIV_BAN = 64; // Can ban players
const u64 PRIV_GIVE = 128; // Can give stuff
// Default privileges - these can be overriden for new players using the // Default privileges - these can be overriden for new players using the
// config option "default_privs" - however, this value still applies for // config option "default_privs" - however, this value still applies for
@ -47,6 +49,8 @@ const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT;
const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL; const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
const u64 PRIV_INVALID = 0x8000000000000000ULL; const u64 PRIV_INVALID = 0x8000000000000000ULL;
std::set<std::string> privsToSet(u64 privs);
// Convert a privileges value into a human-readable string, // Convert a privileges value into a human-readable string,
// with each component separated by a comma. // with each component separated by a comma.
std::string privsToString(u64 privs); std::string privsToString(u64 privs);

@ -1023,6 +1023,30 @@ static int l_chat_send_player(lua_State *L)
return 0; 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 [] = { static const struct luaL_Reg minetest_f [] = {
{"register_nodedef_defaults", l_register_nodedef_defaults}, {"register_nodedef_defaults", l_register_nodedef_defaults},
{"register_entity", l_register_entity}, {"register_entity", l_register_entity},
@ -1035,6 +1059,7 @@ static const struct luaL_Reg minetest_f [] = {
{"setting_getbool", l_setting_getbool}, {"setting_getbool", l_setting_getbool},
{"chat_send_all", l_chat_send_all}, {"chat_send_all", l_chat_send_all},
{"chat_send_player", l_chat_send_player}, {"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs},
{NULL, NULL} {NULL, NULL}
}; };
@ -1502,236 +1527,6 @@ const luaL_reg NodeMetaRef::methods[] = {
{0,0} {0,0}
}; };
/*
EnvRef
*/
class EnvRef
{
private:
ServerEnvironment *m_env;
static const char className[];
static const luaL_reg methods[];
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 *(EnvRef**)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)
{
//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;
}
// EnvRef:remove_node(pos)
// pos = {x=num, y=num, z=num}
static int l_remove_node(lua_State *L)
{
//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;
}
// EnvRef:get_node(pos)
// pos = {x=num, y=num, z=num}
static int l_get_node(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());
return 1;
}
// EnvRef:add_luaentity(pos, entityname)
// pos = {x=num, y=num, z=num}
static int l_add_luaentity(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;
// 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);
return 0;
}
// EnvRef:add_item(pos, inventorystring)
// pos = {x=num, y=num, z=num}
static int l_add_item(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;
// pos
v3f pos = readFloatPos(L, 2);
// inventorystring
const char *inventorystring = lua_tostring(L, 3);
// Do it
ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
env->addActiveObject(obj);
return 0;
}
// EnvRef:add_rat(pos)
// pos = {x=num, y=num, z=num}
static int l_add_rat(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);
// Do it
ServerActiveObject *obj = new RatSAO(env, pos);
env->addActiveObject(obj);
return 0;
}
// EnvRef:add_firefly(pos)
// pos = {x=num, y=num, z=num}
static int l_add_firefly(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;
// pos
v3f pos = readFloatPos(L, 2);
// Do it
ServerActiveObject *obj = new FireflySAO(env, pos);
env->addActiveObject(obj);
return 0;
}
// EnvRef:get_meta(pos)
static int l_get_meta(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;
// Do it
v3s16 p = readpos(L, 2);
NodeMetaRef::create(L, p, env);
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)
{
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);
}
static void set_null(lua_State *L)
{
EnvRef *o = checkobject(L, -1);
o->m_env = NULL;
}
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
// Cannot be created from Lua
//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),
{0,0}
};
/* /*
ObjectRef ObjectRef
*/ */
@ -1886,7 +1681,7 @@ private:
} }
// add_to_inventory(self, itemstring) // add_to_inventory(self, itemstring)
// returns: true if item was added, false otherwise // returns: true if item was added, (false, "reason") otherwise
static int l_add_to_inventory(lua_State *L) static int l_add_to_inventory(lua_State *L)
{ {
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
@ -1902,12 +1697,23 @@ private:
ServerEnvironment *env = co->getEnv(); ServerEnvironment *env = co->getEnv();
assert(env); assert(env);
IGameDef *gamedef = env->getGameDef(); IGameDef *gamedef = env->getGameDef();
InventoryItem *item = InventoryItem::deSerialize(is, gamedef); try{
infostream<<"item="<<env<<std::endl; InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
bool fits = co->addToInventory(item); if(item->getCount() == 0)
// Return item->setCount(1);
lua_pushboolean(L, fits); bool added = co->addToInventory(item);
return 1; // Return
lua_pushboolean(L, added);
if(!added)
lua_pushstring(L, "does not fit");
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) // add_to_inventory_later(self, itemstring)
@ -2093,6 +1899,256 @@ static void objectref_get_or_create(lua_State *L,
} }
} }
/*
EnvRef
*/
class EnvRef
{
private:
ServerEnvironment *m_env;
static const char className[];
static const luaL_reg methods[];
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 *(EnvRef**)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)
{
//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;
}
// EnvRef:remove_node(pos)
// pos = {x=num, y=num, z=num}
static int l_remove_node(lua_State *L)
{
//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;
}
// EnvRef:get_node(pos)
// pos = {x=num, y=num, z=num}
static int l_get_node(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());
return 1;
}
// EnvRef:add_luaentity(pos, entityname)
// pos = {x=num, y=num, z=num}
static int l_add_luaentity(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;
// 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);
return 0;
}
// EnvRef:add_item(pos, inventorystring)
// pos = {x=num, y=num, z=num}
static int l_add_item(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;
// pos
v3f pos = readFloatPos(L, 2);
// inventorystring
const char *inventorystring = lua_tostring(L, 3);
// Do it
ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
env->addActiveObject(obj);
return 0;
}
// EnvRef:add_rat(pos)
// pos = {x=num, y=num, z=num}
static int l_add_rat(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);
// Do it
ServerActiveObject *obj = new RatSAO(env, pos);
env->addActiveObject(obj);
return 0;
}
// EnvRef:add_firefly(pos)
// pos = {x=num, y=num, z=num}
static int l_add_firefly(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;
// pos
v3f pos = readFloatPos(L, 2);
// Do it
ServerActiveObject *obj = new FireflySAO(env, pos);
env->addActiveObject(obj);
return 0;
}
// EnvRef:get_meta(pos)
static int l_get_meta(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;
// Do it
v3s16 p = readpos(L, 2);
NodeMetaRef::create(L, p, env);
return 1;
}
// EnvRef:get_player_by_name(name)
static int l_get_player_by_name(lua_State *L)
{
EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
// Do it
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;
}
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)
{
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);
}
static void set_null(lua_State *L)
{
EnvRef *o = checkobject(L, -1);
o->m_env = NULL;
}
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
// Cannot be created from Lua
//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),
method(EnvRef, get_player_by_name),
{0,0}
};
/* /*
Main export function Main export function
*/ */