2011-11-11 18:33:17 +01:00
|
|
|
/*
|
|
|
|
Minetest-c55
|
|
|
|
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
2012-06-05 16:56:56 +02:00
|
|
|
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
|
2011-11-11 18:33:17 +01:00
|
|
|
(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
|
2012-06-05 16:56:56 +02:00
|
|
|
GNU Lesser General Public License for more details.
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-06-05 16:56:56 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
2011-11-11 18:33:17 +01:00
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "scriptapi.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
2011-11-28 16:11:14 +01:00
|
|
|
#include <list>
|
2011-11-11 18:33:17 +01:00
|
|
|
extern "C" {
|
|
|
|
#include <lua.h>
|
|
|
|
#include <lualib.h>
|
|
|
|
#include <lauxlib.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "porting.h"
|
|
|
|
#include "filesys.h"
|
|
|
|
#include "serverobject.h"
|
|
|
|
#include "script.h"
|
2012-03-30 11:51:51 +02:00
|
|
|
#include "object_properties.h"
|
2012-03-19 03:04:16 +01:00
|
|
|
#include "content_sao.h" // For LuaEntitySAO and PlayerSAO
|
2012-01-12 06:10:39 +01:00
|
|
|
#include "itemdef.h"
|
2011-11-16 14:23:25 +01:00
|
|
|
#include "nodedef.h"
|
2011-11-17 01:28:46 +01:00
|
|
|
#include "craftdef.h"
|
2011-11-26 02:37:09 +01:00
|
|
|
#include "main.h" // For g_settings
|
|
|
|
#include "settings.h" // For accessing g_settings
|
2011-11-28 02:06:21 +01:00
|
|
|
#include "nodemetadata.h"
|
|
|
|
#include "mapblock.h" // For getNodeBlockPos
|
2011-11-28 16:11:14 +01:00
|
|
|
#include "content_nodemeta.h"
|
2012-02-28 18:45:23 +01:00
|
|
|
#include "tool.h"
|
2012-03-16 15:34:30 +01:00
|
|
|
#include "daynightratio.h"
|
2012-03-27 23:38:20 +02:00
|
|
|
#include "noise.h" // PseudoRandom for LuaPseudoRandom
|
2012-06-17 01:40:36 +02:00
|
|
|
#include "util/pointedthing.h"
|
2012-07-26 21:06:45 +02:00
|
|
|
#include "rollback.h"
|
2012-12-29 16:20:09 +01:00
|
|
|
#include "treegen.h"
|
2011-11-11 18:33:17 +01:00
|
|
|
|
|
|
|
static void stackDump(lua_State *L, std::ostream &o)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
for (i = 1; i <= top; i++) { /* repeat for each level */
|
|
|
|
int t = lua_type(L, i);
|
|
|
|
switch (t) {
|
|
|
|
|
|
|
|
case LUA_TSTRING: /* strings */
|
|
|
|
o<<"\""<<lua_tostring(L, i)<<"\"";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TBOOLEAN: /* booleans */
|
|
|
|
o<<(lua_toboolean(L, i) ? "true" : "false");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TNUMBER: /* numbers */ {
|
|
|
|
char buf[10];
|
|
|
|
snprintf(buf, 10, "%g", lua_tonumber(L, i));
|
|
|
|
o<<buf;
|
|
|
|
break; }
|
|
|
|
|
|
|
|
default: /* other values */
|
|
|
|
o<<lua_typename(L, t);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
o<<" ";
|
|
|
|
}
|
|
|
|
o<<std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void realitycheck(lua_State *L)
|
|
|
|
{
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
if(top >= 30){
|
|
|
|
dstream<<"Stack is over 30:"<<std::endl;
|
|
|
|
stackDump(L, dstream);
|
|
|
|
script_error(L, "Stack is over 30 (reality check)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
class StackUnroller
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
lua_State *m_lua;
|
|
|
|
int m_original_top;
|
|
|
|
public:
|
|
|
|
StackUnroller(lua_State *L):
|
|
|
|
m_lua(L),
|
|
|
|
m_original_top(-1)
|
|
|
|
{
|
|
|
|
m_original_top = lua_gettop(m_lua); // store stack height
|
|
|
|
}
|
|
|
|
~StackUnroller()
|
|
|
|
{
|
|
|
|
lua_settop(m_lua, m_original_top); // restore stack height
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-12-03 01:45:55 +01:00
|
|
|
class ModNameStorer
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
lua_State *L;
|
|
|
|
public:
|
|
|
|
ModNameStorer(lua_State *L_, const std::string modname):
|
|
|
|
L(L_)
|
|
|
|
{
|
|
|
|
// Store current modname in registry
|
|
|
|
lua_pushstring(L, modname.c_str());
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
|
|
|
}
|
|
|
|
~ModNameStorer()
|
|
|
|
{
|
|
|
|
// Clear current modname in registry
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
Getters for stuff in main tables
|
|
|
|
*/
|
2011-12-28 16:34:07 +01:00
|
|
|
|
2011-12-06 14:21:56 +01:00
|
|
|
static Server* get_server(lua_State *L)
|
|
|
|
{
|
|
|
|
// Get server from registry
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
|
2012-01-12 06:10:39 +01:00
|
|
|
Server *server = (Server*)lua_touserdata(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return server;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
2012-06-01 19:51:15 +02:00
|
|
|
static ServerEnvironment* get_env(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
|
|
|
// Get environment from registry
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
|
2012-01-12 06:10:39 +01:00
|
|
|
ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pop(L, 1);
|
2012-01-12 06:10:39 +01:00
|
|
|
return env;
|
2012-06-01 19:51:15 +02:00
|
|
|
}
|
2011-11-17 10:22:24 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static void objectref_get(lua_State *L, u16 id)
|
2011-11-17 10:22:24 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
// Get minetest.object_refs[i]
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "object_refs");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushnumber(L, id);
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
lua_remove(L, -2); // object_refs
|
|
|
|
lua_remove(L, -2); // minetest
|
2011-11-17 10:22:24 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static void luaentity_get(lua_State *L, u16 id)
|
2011-11-25 13:58:42 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
// Get minetest.luaentities[i]
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "luaentities");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushnumber(L, id);
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
lua_remove(L, -2); // luaentities
|
|
|
|
lua_remove(L, -2); // minetest
|
2011-11-25 13:58:42 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
Table field getters
|
|
|
|
*/
|
2011-11-25 15:34:12 +01:00
|
|
|
|
2011-11-25 13:58:42 +01:00
|
|
|
static bool getstringfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, std::string &result)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
bool got = false;
|
|
|
|
if(lua_isstring(L, -1)){
|
2012-01-12 06:10:39 +01:00
|
|
|
size_t len = 0;
|
|
|
|
const char *ptr = lua_tolstring(L, -1, &len);
|
|
|
|
result.assign(ptr, len);
|
2011-11-25 13:58:42 +01:00
|
|
|
got = true;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool getintfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, int &result)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
bool got = false;
|
|
|
|
if(lua_isnumber(L, -1)){
|
|
|
|
result = lua_tonumber(L, -1);
|
|
|
|
got = true;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool getfloatfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, float &result)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
bool got = false;
|
|
|
|
if(lua_isnumber(L, -1)){
|
|
|
|
result = lua_tonumber(L, -1);
|
|
|
|
got = true;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool getboolfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, bool &result)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
bool got = false;
|
|
|
|
if(lua_isboolean(L, -1)){
|
|
|
|
result = lua_toboolean(L, -1);
|
|
|
|
got = true;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static std::string checkstringfield(lua_State *L, int table,
|
|
|
|
const char *fieldname)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
std::string s = luaL_checkstring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2011-11-25 13:58:42 +01:00
|
|
|
static std::string getstringfield_default(lua_State *L, int table,
|
|
|
|
const char *fieldname, const std::string &default_)
|
|
|
|
{
|
|
|
|
std::string result = default_;
|
|
|
|
getstringfield(L, table, fieldname, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getintfield_default(lua_State *L, int table,
|
|
|
|
const char *fieldname, int default_)
|
|
|
|
{
|
|
|
|
int result = default_;
|
|
|
|
getintfield(L, table, fieldname, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static float getfloatfield_default(lua_State *L, int table,
|
2011-11-27 03:31:05 +01:00
|
|
|
const char *fieldname, float default_)
|
|
|
|
{
|
|
|
|
float result = default_;
|
|
|
|
getfloatfield(L, table, fieldname, result);
|
|
|
|
return result;
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
2011-11-27 03:31:05 +01:00
|
|
|
|
2011-11-25 13:58:42 +01:00
|
|
|
static bool getboolfield_default(lua_State *L, int table,
|
|
|
|
const char *fieldname, bool default_)
|
|
|
|
{
|
|
|
|
bool result = default_;
|
|
|
|
getboolfield(L, table, fieldname, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EnumString
|
|
|
|
{
|
|
|
|
int num;
|
|
|
|
const char *str;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool string_to_enum(const EnumString *spec, int &result,
|
|
|
|
const std::string &str)
|
|
|
|
{
|
|
|
|
const EnumString *esp = spec;
|
|
|
|
while(esp->str){
|
|
|
|
if(str == std::string(esp->str)){
|
|
|
|
result = esp->num;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
esp++;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static bool enum_to_string(const EnumString *spec, std::string &result,
|
|
|
|
int num)
|
|
|
|
{
|
|
|
|
const EnumString *esp = spec;
|
|
|
|
while(esp){
|
|
|
|
if(num == esp->num){
|
|
|
|
result = esp->str;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
esp++;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}*/
|
|
|
|
|
|
|
|
static int getenumfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, const EnumString *spec, int default_)
|
|
|
|
{
|
|
|
|
int result = default_;
|
|
|
|
string_to_enum(spec, result,
|
|
|
|
getstringfield_default(L, table, fieldname, ""));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
static void setintfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, int value)
|
|
|
|
{
|
|
|
|
lua_pushinteger(L, value);
|
|
|
|
if(table < 0)
|
|
|
|
table -= 1;
|
|
|
|
lua_setfield(L, table, fieldname);
|
|
|
|
}
|
|
|
|
|
2011-12-01 22:33:48 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
static void setboolfield(lua_State *L, int table,
|
|
|
|
const char *fieldname, bool value)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L, value);
|
|
|
|
if(table < 0)
|
|
|
|
table -= 1;
|
|
|
|
lua_setfield(L, table, fieldname);
|
|
|
|
}
|
|
|
|
|
2011-12-04 02:45:02 +01:00
|
|
|
static void warn_if_field_exists(lua_State *L, int table,
|
|
|
|
const char *fieldname, const std::string &message)
|
|
|
|
{
|
|
|
|
lua_getfield(L, table, fieldname);
|
|
|
|
if(!lua_isnil(L, -1)){
|
|
|
|
infostream<<script_get_backtrace(L)<<std::endl;
|
|
|
|
infostream<<"WARNING: field \""<<fieldname<<"\": "
|
|
|
|
<<message<<std::endl;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
2011-11-30 22:38:18 +01:00
|
|
|
/*
|
2012-01-12 06:10:39 +01:00
|
|
|
EnumString definitions
|
2011-11-30 22:38:18 +01:00
|
|
|
*/
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
struct EnumString es_ItemType[] =
|
2011-11-30 22:38:18 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
{ITEM_NONE, "none"},
|
|
|
|
{ITEM_NODE, "node"},
|
|
|
|
{ITEM_CRAFT, "craft"},
|
|
|
|
{ITEM_TOOL, "tool"},
|
|
|
|
{0, NULL},
|
|
|
|
};
|
2011-11-30 22:38:18 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
struct EnumString es_DrawType[] =
|
2011-11-25 13:58:42 +01:00
|
|
|
{
|
|
|
|
{NDT_NORMAL, "normal"},
|
|
|
|
{NDT_AIRLIKE, "airlike"},
|
|
|
|
{NDT_LIQUID, "liquid"},
|
|
|
|
{NDT_FLOWINGLIQUID, "flowingliquid"},
|
|
|
|
{NDT_GLASSLIKE, "glasslike"},
|
|
|
|
{NDT_ALLFACES, "allfaces"},
|
|
|
|
{NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
|
|
|
|
{NDT_TORCHLIKE, "torchlike"},
|
|
|
|
{NDT_SIGNLIKE, "signlike"},
|
|
|
|
{NDT_PLANTLIKE, "plantlike"},
|
|
|
|
{NDT_FENCELIKE, "fencelike"},
|
|
|
|
{NDT_RAILLIKE, "raillike"},
|
2012-03-19 04:25:09 +01:00
|
|
|
{NDT_NODEBOX, "nodebox"},
|
2011-11-25 13:58:42 +01:00
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EnumString es_ContentParamType[] =
|
|
|
|
{
|
|
|
|
{CPT_NONE, "none"},
|
|
|
|
{CPT_LIGHT, "light"},
|
2012-01-21 00:11:44 +01:00
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EnumString es_ContentParamType2[] =
|
|
|
|
{
|
|
|
|
{CPT2_NONE, "none"},
|
|
|
|
{CPT2_FULL, "full"},
|
|
|
|
{CPT2_FLOWINGLIQUID, "flowingliquid"},
|
|
|
|
{CPT2_FACEDIR, "facedir"},
|
|
|
|
{CPT2_WALLMOUNTED, "wallmounted"},
|
2011-11-29 15:41:49 +01:00
|
|
|
{0, NULL},
|
2011-11-25 13:58:42 +01:00
|
|
|
};
|
|
|
|
|
2011-11-25 15:34:12 +01:00
|
|
|
struct EnumString es_LiquidType[] =
|
|
|
|
{
|
|
|
|
{LIQUID_NONE, "none"},
|
|
|
|
{LIQUID_FLOWING, "flowing"},
|
|
|
|
{LIQUID_SOURCE, "source"},
|
2011-11-29 15:41:49 +01:00
|
|
|
{0, NULL},
|
2011-11-25 15:34:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct EnumString es_NodeBoxType[] =
|
|
|
|
{
|
|
|
|
{NODEBOX_REGULAR, "regular"},
|
|
|
|
{NODEBOX_FIXED, "fixed"},
|
|
|
|
{NODEBOX_WALLMOUNTED, "wallmounted"},
|
2011-11-29 15:41:49 +01:00
|
|
|
{0, NULL},
|
2011-11-25 15:34:12 +01:00
|
|
|
};
|
|
|
|
|
2012-06-02 11:19:44 +02:00
|
|
|
struct EnumString es_CraftMethod[] =
|
|
|
|
{
|
|
|
|
{CRAFT_METHOD_NORMAL, "normal"},
|
|
|
|
{CRAFT_METHOD_COOKING, "cooking"},
|
|
|
|
{CRAFT_METHOD_FUEL, "fuel"},
|
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
2012-06-16 02:40:45 +02:00
|
|
|
struct EnumString es_TileAnimationType[] =
|
|
|
|
{
|
|
|
|
{TAT_NONE, "none"},
|
|
|
|
{TAT_VERTICAL_FRAMES, "vertical_frames"},
|
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
2011-11-12 10:59:56 +01:00
|
|
|
/*
|
2012-01-12 06:10:39 +01:00
|
|
|
C struct <-> Lua table converter functions
|
2011-11-12 10:59:56 +01:00
|
|
|
*/
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static void push_v3f(lua_State *L, v3f p)
|
2011-11-26 01:26:19 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushnumber(L, p.X);
|
|
|
|
lua_setfield(L, -2, "x");
|
|
|
|
lua_pushnumber(L, p.Y);
|
|
|
|
lua_setfield(L, -2, "y");
|
|
|
|
lua_pushnumber(L, p.Z);
|
|
|
|
lua_setfield(L, -2, "z");
|
2011-11-26 01:26:19 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static v2s16 read_v2s16(lua_State *L, int index)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
v2s16 p;
|
|
|
|
luaL_checktype(L, index, LUA_TTABLE);
|
|
|
|
lua_getfield(L, index, "x");
|
|
|
|
p.X = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "y");
|
|
|
|
p.Y = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return p;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2011-11-11 23:46:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static v2f read_v2f(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
v2f p;
|
|
|
|
luaL_checktype(L, index, LUA_TTABLE);
|
|
|
|
lua_getfield(L, index, "x");
|
|
|
|
p.X = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "y");
|
|
|
|
p.Y = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return p;
|
|
|
|
}
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static v3f read_v3f(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
v3f pos;
|
|
|
|
luaL_checktype(L, index, LUA_TTABLE);
|
|
|
|
lua_getfield(L, index, "x");
|
|
|
|
pos.X = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "y");
|
|
|
|
pos.Y = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "z");
|
|
|
|
pos.Z = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return pos;
|
|
|
|
}
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static v3f check_v3f(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
v3f pos;
|
|
|
|
luaL_checktype(L, index, LUA_TTABLE);
|
|
|
|
lua_getfield(L, index, "x");
|
|
|
|
pos.X = luaL_checknumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "y");
|
|
|
|
pos.Y = luaL_checknumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "z");
|
|
|
|
pos.Z = luaL_checknumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pushFloatPos(lua_State *L, v3f p)
|
|
|
|
{
|
|
|
|
p /= BS;
|
|
|
|
push_v3f(L, p);
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static v3f checkFloatPos(lua_State *L, int index)
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
return check_v3f(L, index) * BS;
|
|
|
|
}
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static void push_v3s16(lua_State *L, v3s16 p)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushnumber(L, p.X);
|
|
|
|
lua_setfield(L, -2, "x");
|
|
|
|
lua_pushnumber(L, p.Y);
|
|
|
|
lua_setfield(L, -2, "y");
|
|
|
|
lua_pushnumber(L, p.Z);
|
|
|
|
lua_setfield(L, -2, "z");
|
|
|
|
}
|
|
|
|
|
|
|
|
static v3s16 read_v3s16(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
// Correct rounding at <0
|
|
|
|
v3f pf = read_v3f(L, index);
|
|
|
|
return floatToInt(pf, 1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static v3s16 check_v3s16(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
// Correct rounding at <0
|
|
|
|
v3f pf = check_v3f(L, index);
|
|
|
|
return floatToInt(pf, 1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, ndef->get(n).name.c_str());
|
|
|
|
lua_setfield(L, -2, "name");
|
|
|
|
lua_pushnumber(L, n.getParam1());
|
|
|
|
lua_setfield(L, -2, "param1");
|
|
|
|
lua_pushnumber(L, n.getParam2());
|
|
|
|
lua_setfield(L, -2, "param2");
|
|
|
|
}
|
|
|
|
|
|
|
|
static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
|
|
|
|
{
|
|
|
|
lua_getfield(L, index, "name");
|
|
|
|
const char *name = luaL_checkstring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
u8 param1;
|
|
|
|
lua_getfield(L, index, "param1");
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
param1 = 0;
|
|
|
|
else
|
|
|
|
param1 = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
u8 param2;
|
|
|
|
lua_getfield(L, index, "param2");
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
param2 = 0;
|
|
|
|
else
|
|
|
|
param2 = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return MapNode(ndef, name, param1, param2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static video::SColor readARGB8(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
video::SColor color;
|
|
|
|
luaL_checktype(L, index, LUA_TTABLE);
|
|
|
|
lua_getfield(L, index, "a");
|
|
|
|
if(lua_isnumber(L, -1))
|
|
|
|
color.setAlpha(lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "r");
|
|
|
|
color.setRed(lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "g");
|
|
|
|
color.setGreen(lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "b");
|
|
|
|
color.setBlue(lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
static aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
|
2012-01-12 06:10:39 +01:00
|
|
|
{
|
2012-03-19 04:25:09 +01:00
|
|
|
aabb3f box;
|
|
|
|
if(lua_istable(L, index)){
|
|
|
|
lua_rawgeti(L, index, 1);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MinEdge.X = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_rawgeti(L, index, 2);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MinEdge.Y = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_rawgeti(L, index, 3);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MinEdge.Z = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_rawgeti(L, index, 4);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MaxEdge.X = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_rawgeti(L, index, 5);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_rawgeti(L, index, 6);
|
2012-01-12 06:10:39 +01:00
|
|
|
box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return box;
|
|
|
|
}
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
static std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
|
|
|
|
{
|
|
|
|
std::vector<aabb3f> boxes;
|
|
|
|
if(lua_istable(L, index)){
|
|
|
|
int n = lua_objlen(L, index);
|
|
|
|
// Check if it's a single box or a list of boxes
|
|
|
|
bool possibly_single_box = (n == 6);
|
|
|
|
for(int i = 1; i <= n && possibly_single_box; i++){
|
|
|
|
lua_rawgeti(L, index, i);
|
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
possibly_single_box = false;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
if(possibly_single_box){
|
|
|
|
// Read a single box
|
|
|
|
boxes.push_back(read_aabb3f(L, index, scale));
|
|
|
|
} else {
|
|
|
|
// Read a list of boxes
|
|
|
|
for(int i = 1; i <= n; i++){
|
|
|
|
lua_rawgeti(L, index, i);
|
|
|
|
boxes.push_back(read_aabb3f(L, -1, scale));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return boxes;
|
|
|
|
}
|
2012-01-21 00:11:44 +01:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
static NodeBox read_nodebox(lua_State *L, int index)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
2012-03-19 04:25:09 +01:00
|
|
|
NodeBox nodebox;
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
|
|
|
|
es_NodeBoxType, NODEBOX_REGULAR);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "fixed");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
nodebox.fixed = read_aabb3f_vector(L, -1, BS);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "wall_top");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
nodebox.wall_top = read_aabb3f(L, -1, BS);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "wall_bottom");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
nodebox.wall_bottom = read_aabb3f(L, -1, BS);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "wall_side");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
nodebox.wall_side = read_aabb3f(L, -1, BS);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return nodebox;
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
2012-02-28 18:45:23 +01:00
|
|
|
Groups
|
|
|
|
*/
|
|
|
|
static void read_groups(lua_State *L, int index,
|
|
|
|
std::map<std::string, int> &result)
|
|
|
|
{
|
2012-07-15 08:50:42 +02:00
|
|
|
if (!lua_istable(L,index))
|
|
|
|
return;
|
2012-02-28 18:45:23 +01:00
|
|
|
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 name = luaL_checkstring(L, -2);
|
|
|
|
int rating = luaL_checkinteger(L, -1);
|
|
|
|
result[name] = rating;
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-30 17:42:18 +02:00
|
|
|
/*
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
/*
|
|
|
|
ToolCapabilities
|
2012-01-12 06:10:39 +01:00
|
|
|
*/
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static ToolCapabilities read_tool_capabilities(
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_State *L, int table)
|
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
ToolCapabilities toolcap;
|
|
|
|
getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
|
|
|
|
getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
|
|
|
|
lua_getfield(L, table, "groupcaps");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table_groupcaps = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table_groupcaps) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
std::string groupname = luaL_checkstring(L, -2);
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table_groupcap = lua_gettop(L);
|
|
|
|
// This will be created
|
|
|
|
ToolGroupCap groupcap;
|
|
|
|
// Read simple parameters
|
|
|
|
getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
|
2012-03-29 12:35:20 +02:00
|
|
|
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;
|
|
|
|
}
|
2012-02-28 18:45:23 +01:00
|
|
|
// Read "times" table
|
|
|
|
lua_getfield(L, table_groupcap, "times");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table_times = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table_times) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
int rating = luaL_checkinteger(L, -2);
|
|
|
|
float time = luaL_checknumber(L, -1);
|
|
|
|
groupcap.times[rating] = time;
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
// Insert groupcap into toolcap
|
|
|
|
toolcap.groupcaps[groupname] = groupcap;
|
|
|
|
}
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return toolcap;
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void set_tool_capabilities(lua_State *L, int table,
|
|
|
|
const ToolCapabilities &toolcap)
|
2012-01-12 06:10:39 +01:00
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
setfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
|
|
|
|
setintfield(L, table, "max_drop_level", toolcap.max_drop_level);
|
|
|
|
// Create groupcaps table
|
|
|
|
lua_newtable(L);
|
|
|
|
// For each groupcap
|
|
|
|
for(std::map<std::string, ToolGroupCap>::const_iterator
|
|
|
|
i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
|
|
|
|
// Create groupcap table
|
|
|
|
lua_newtable(L);
|
|
|
|
const std::string &name = i->first;
|
|
|
|
const ToolGroupCap &groupcap = i->second;
|
|
|
|
// Create subtable "times"
|
|
|
|
lua_newtable(L);
|
|
|
|
for(std::map<int, float>::const_iterator
|
|
|
|
i = groupcap.times.begin(); i != groupcap.times.end(); i++){
|
|
|
|
int rating = i->first;
|
|
|
|
float time = i->second;
|
|
|
|
lua_pushinteger(L, rating);
|
|
|
|
lua_pushnumber(L, time);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
// Set subtable "times"
|
|
|
|
lua_setfield(L, -2, "times");
|
|
|
|
// Set simple parameters
|
|
|
|
setintfield(L, -1, "maxlevel", groupcap.maxlevel);
|
2012-03-29 12:35:20 +02:00
|
|
|
setintfield(L, -1, "uses", groupcap.uses);
|
2012-02-28 18:45:23 +01:00
|
|
|
// Insert groupcap table into groupcaps table
|
|
|
|
lua_setfield(L, -2, name.c_str());
|
|
|
|
}
|
|
|
|
// Set groupcaps table
|
|
|
|
lua_setfield(L, -2, "groupcaps");
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void push_tool_capabilities(lua_State *L,
|
|
|
|
const ToolCapabilities &prop)
|
2012-01-12 06:10:39 +01:00
|
|
|
{
|
|
|
|
lua_newtable(L);
|
2012-02-28 18:45:23 +01:00
|
|
|
set_tool_capabilities(L, -1, prop);
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
/*
|
2012-02-28 18:45:23 +01:00
|
|
|
DigParams
|
2012-01-21 00:11:44 +01:00
|
|
|
*/
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void set_dig_params(lua_State *L, int table,
|
|
|
|
const DigParams ¶ms)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
setboolfield(L, table, "diggable", params.diggable);
|
|
|
|
setfloatfield(L, table, "time", params.time);
|
|
|
|
setintfield(L, table, "wear", params.wear);
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void push_dig_params(lua_State *L,
|
|
|
|
const DigParams ¶ms)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
|
|
|
lua_newtable(L);
|
2012-02-28 18:45:23 +01:00
|
|
|
set_dig_params(L, -1, params);
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-02-28 18:45:23 +01:00
|
|
|
HitParams
|
2012-01-21 00:11:44 +01:00
|
|
|
*/
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void set_hit_params(lua_State *L, int table,
|
|
|
|
const HitParams ¶ms)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
setintfield(L, table, "hp", params.hp);
|
|
|
|
setintfield(L, table, "wear", params.wear);
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
static void push_hit_params(lua_State *L,
|
|
|
|
const HitParams ¶ms)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
|
|
|
lua_newtable(L);
|
2012-02-28 18:45:23 +01:00
|
|
|
set_hit_params(L, -1, params);
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
PointedThing
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void push_pointed_thing(lua_State *L, const PointedThing& pointed)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
if(pointed.type == POINTEDTHING_NODE)
|
|
|
|
{
|
|
|
|
lua_pushstring(L, "node");
|
|
|
|
lua_setfield(L, -2, "type");
|
|
|
|
push_v3s16(L, pointed.node_undersurface);
|
|
|
|
lua_setfield(L, -2, "under");
|
|
|
|
push_v3s16(L, pointed.node_abovesurface);
|
|
|
|
lua_setfield(L, -2, "above");
|
|
|
|
}
|
|
|
|
else if(pointed.type == POINTEDTHING_OBJECT)
|
|
|
|
{
|
|
|
|
lua_pushstring(L, "object");
|
|
|
|
lua_setfield(L, -2, "type");
|
|
|
|
objectref_get(L, pointed.object_id);
|
|
|
|
lua_setfield(L, -2, "ref");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pushstring(L, "nothing");
|
|
|
|
lua_setfield(L, -2, "type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 19:23:03 +01:00
|
|
|
/*
|
|
|
|
SimpleSoundSpec
|
|
|
|
*/
|
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
static void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
|
2012-03-23 19:23:03 +01:00
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
if(lua_isnil(L, index)){
|
|
|
|
} else if(lua_istable(L, index)){
|
|
|
|
getstringfield(L, index, "name", spec.name);
|
|
|
|
getfloatfield(L, index, "gain", spec.gain);
|
|
|
|
} else if(lua_isstring(L, index)){
|
|
|
|
spec.name = lua_tostring(L, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-30 12:26:40 +02:00
|
|
|
/*
|
|
|
|
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))
|
2012-03-19 04:25:09 +01:00
|
|
|
prop->collisionbox = read_aabb3f(L, -1, 1.0);
|
2012-03-30 12:26:40 +02:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
getstringfield(L, -1, "visual", prop->visual);
|
2012-10-23 19:03:06 +02:00
|
|
|
|
|
|
|
getstringfield(L, -1, "mesh", prop->mesh);
|
2012-03-30 12:26:40 +02:00
|
|
|
|
|
|
|
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);
|
2012-10-27 00:49:01 +02:00
|
|
|
|
|
|
|
lua_getfield(L, -1, "colors");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
prop->colors.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->colors.push_back(readARGB8(L, -1));
|
|
|
|
else
|
|
|
|
prop->colors.push_back(video::SColor(255, 255, 255, 255));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2012-03-30 12:26:40 +02:00
|
|
|
|
|
|
|
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);
|
2012-04-04 12:16:09 +02:00
|
|
|
getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
|
2012-03-30 12:26:40 +02:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
ItemDefinition
|
|
|
|
*/
|
|
|
|
|
2012-06-10 11:46:48 +02:00
|
|
|
static ItemDefinition read_item_definition(lua_State *L, int index,
|
|
|
|
ItemDefinition default_def = ItemDefinition())
|
2012-01-12 06:10:39 +01:00
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
|
|
|
|
// Read the item definition
|
2012-06-10 11:46:48 +02:00
|
|
|
ItemDefinition def = default_def;
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
def.type = (ItemType)getenumfield(L, index, "type",
|
|
|
|
es_ItemType, ITEM_NONE);
|
|
|
|
getstringfield(L, index, "name", def.name);
|
|
|
|
getstringfield(L, index, "description", def.description);
|
|
|
|
getstringfield(L, index, "inventory_image", def.inventory_image);
|
|
|
|
getstringfield(L, index, "wield_image", def.wield_image);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "wield_scale");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
def.wield_scale = check_v3f(L, -1);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
|
|
|
|
if(def.stack_max == 0)
|
|
|
|
def.stack_max = 1;
|
|
|
|
|
|
|
|
lua_getfield(L, index, "on_use");
|
|
|
|
def.usable = lua_isfunction(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
warn_if_field_exists(L, index, "tool_digging_properties",
|
|
|
|
"deprecated: use tool_capabilities");
|
|
|
|
|
|
|
|
lua_getfield(L, index, "tool_capabilities");
|
2012-01-12 06:10:39 +01:00
|
|
|
if(lua_istable(L, -1)){
|
2012-02-28 18:45:23 +01:00
|
|
|
def.tool_capabilities = new ToolCapabilities(
|
|
|
|
read_tool_capabilities(L, -1));
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
// If name is "" (hand), ensure there are ToolCapabilities
|
2012-01-12 06:10:39 +01:00
|
|
|
// because it will be looked up there whenever any other item has
|
2012-02-28 18:45:23 +01:00
|
|
|
// no ToolCapabilities
|
|
|
|
if(def.name == "" && def.tool_capabilities == NULL){
|
|
|
|
def.tool_capabilities = new ToolCapabilities();
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
lua_getfield(L, index, "groups");
|
|
|
|
read_groups(L, -1, def.groups);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2012-06-10 11:46:48 +02:00
|
|
|
// Client shall immediately place this node when player places the item.
|
|
|
|
// Server will update the precise end result a moment later.
|
|
|
|
// "" = no prediction
|
|
|
|
getstringfield(L, index, "node_placement_prediction",
|
|
|
|
def.node_placement_prediction);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2012-06-16 02:40:45 +02:00
|
|
|
/*
|
|
|
|
TileDef
|
|
|
|
*/
|
|
|
|
|
|
|
|
static TileDef read_tiledef(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
|
|
|
|
TileDef tiledef;
|
|
|
|
|
|
|
|
// key at index -2 and value at index
|
|
|
|
if(lua_isstring(L, index)){
|
|
|
|
// "default_lava.png"
|
|
|
|
tiledef.name = lua_tostring(L, index);
|
|
|
|
}
|
|
|
|
else if(lua_istable(L, index))
|
|
|
|
{
|
|
|
|
// {name="default_lava.png", animation={}}
|
|
|
|
tiledef.name = "";
|
|
|
|
getstringfield(L, index, "name", tiledef.name);
|
|
|
|
getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
|
|
|
|
tiledef.backface_culling = getboolfield_default(
|
|
|
|
L, index, "backface_culling", true);
|
|
|
|
// animation = {}
|
|
|
|
lua_getfield(L, index, "animation");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
// {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
|
|
|
|
tiledef.animation.type = (TileAnimationType)
|
|
|
|
getenumfield(L, -1, "type", es_TileAnimationType,
|
|
|
|
TAT_NONE);
|
|
|
|
tiledef.animation.aspect_w =
|
|
|
|
getintfield_default(L, -1, "aspect_w", 16);
|
|
|
|
tiledef.animation.aspect_h =
|
|
|
|
getintfield_default(L, -1, "aspect_h", 16);
|
|
|
|
tiledef.animation.length =
|
|
|
|
getfloatfield_default(L, -1, "length", 1.0);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tiledef;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
ContentFeatures
|
|
|
|
*/
|
|
|
|
|
|
|
|
static ContentFeatures read_content_features(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
|
|
|
|
ContentFeatures f;
|
2012-06-05 22:51:37 +02:00
|
|
|
|
|
|
|
/* Cache existence of some callbacks */
|
|
|
|
lua_getfield(L, index, "on_construct");
|
|
|
|
if(!lua_isnil(L, -1)) f.has_on_construct = true;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "on_destruct");
|
|
|
|
if(!lua_isnil(L, -1)) f.has_on_destruct = true;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, index, "after_destruct");
|
|
|
|
if(!lua_isnil(L, -1)) f.has_after_destruct = true;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
/* Name */
|
2012-01-12 06:10:39 +01:00
|
|
|
getstringfield(L, index, "name", f.name);
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
/* Groups */
|
|
|
|
lua_getfield(L, index, "groups");
|
|
|
|
read_groups(L, -1, f.groups);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/* Visual definition */
|
|
|
|
|
|
|
|
f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
|
|
|
|
NDT_NORMAL);
|
|
|
|
getfloatfield(L, index, "visual_scale", f.visual_scale);
|
2012-06-16 02:40:45 +02:00
|
|
|
|
|
|
|
// tiles = {}
|
|
|
|
lua_getfield(L, index, "tiles");
|
|
|
|
// If nil, try the deprecated name "tile_images" instead
|
|
|
|
if(lua_isnil(L, -1)){
|
|
|
|
lua_pop(L, 1);
|
|
|
|
warn_if_field_exists(L, index, "tile_images",
|
|
|
|
"Deprecated; new name is \"tiles\".");
|
|
|
|
lua_getfield(L, index, "tile_images");
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
int i = 0;
|
|
|
|
while(lua_next(L, table) != 0){
|
2012-06-16 02:40:45 +02:00
|
|
|
// Read tiledef from value
|
|
|
|
f.tiledef[i] = read_tiledef(L, -1);
|
2012-01-12 06:10:39 +01:00
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
i++;
|
|
|
|
if(i==6){
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy last value to all remaining textures
|
|
|
|
if(i >= 1){
|
2012-06-16 02:40:45 +02:00
|
|
|
TileDef lasttile = f.tiledef[i-1];
|
2012-01-12 06:10:39 +01:00
|
|
|
while(i < 6){
|
2012-06-16 02:40:45 +02:00
|
|
|
f.tiledef[i] = lasttile;
|
2012-01-12 06:10:39 +01:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2012-06-16 02:40:45 +02:00
|
|
|
|
|
|
|
// special_tiles = {}
|
|
|
|
lua_getfield(L, index, "special_tiles");
|
|
|
|
// If nil, try the deprecated name "special_materials" instead
|
|
|
|
if(lua_isnil(L, -1)){
|
|
|
|
lua_pop(L, 1);
|
|
|
|
warn_if_field_exists(L, index, "special_materials",
|
|
|
|
"Deprecated; new name is \"special_tiles\".");
|
|
|
|
lua_getfield(L, index, "special_materials");
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
int i = 0;
|
|
|
|
while(lua_next(L, table) != 0){
|
2012-06-16 02:40:45 +02:00
|
|
|
// Read tiledef from value
|
|
|
|
f.tiledef_special[i] = read_tiledef(L, -1);
|
2012-01-12 06:10:39 +01:00
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
i++;
|
|
|
|
if(i==6){
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
f.alpha = getintfield_default(L, index, "alpha", 255);
|
|
|
|
|
|
|
|
/* Other stuff */
|
|
|
|
|
|
|
|
lua_getfield(L, index, "post_effect_color");
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
f.post_effect_color = readARGB8(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
|
|
|
|
es_ContentParamType, CPT_NONE);
|
2012-01-21 00:11:44 +01:00
|
|
|
f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
|
|
|
|
es_ContentParamType2, CPT2_NONE);
|
|
|
|
|
|
|
|
// Warn about some deprecated fields
|
|
|
|
warn_if_field_exists(L, index, "wall_mounted",
|
|
|
|
"deprecated: use paramtype2 = 'wallmounted'");
|
|
|
|
warn_if_field_exists(L, index, "light_propagates",
|
|
|
|
"deprecated: determined from paramtype");
|
|
|
|
warn_if_field_exists(L, index, "dug_item",
|
2012-01-22 15:57:49 +01:00
|
|
|
"deprecated: use 'drop' field");
|
2012-01-21 00:11:44 +01:00
|
|
|
warn_if_field_exists(L, index, "extra_dug_item",
|
2012-01-22 15:57:49 +01:00
|
|
|
"deprecated: use 'drop' field");
|
2012-01-21 00:11:44 +01:00
|
|
|
warn_if_field_exists(L, index, "extra_dug_item_rarity",
|
2012-01-22 15:57:49 +01:00
|
|
|
"deprecated: use 'drop' field");
|
2012-03-19 01:08:04 +01:00
|
|
|
warn_if_field_exists(L, index, "metadata_name",
|
|
|
|
"deprecated: use on_add and metadata callbacks");
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
// True for all ground-like things like stone and mud, false for eg. trees
|
|
|
|
getboolfield(L, index, "is_ground_content", f.is_ground_content);
|
|
|
|
f.light_propagates = (f.param_type == CPT_LIGHT);
|
|
|
|
getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
|
|
|
|
// This is used for collision detection.
|
|
|
|
// Also for general solidness queries.
|
|
|
|
getboolfield(L, index, "walkable", f.walkable);
|
|
|
|
// Player can point to these
|
|
|
|
getboolfield(L, index, "pointable", f.pointable);
|
|
|
|
// Player can dig these
|
|
|
|
getboolfield(L, index, "diggable", f.diggable);
|
|
|
|
// Player can climb these
|
|
|
|
getboolfield(L, index, "climbable", f.climbable);
|
|
|
|
// Player can build on these
|
|
|
|
getboolfield(L, index, "buildable_to", f.buildable_to);
|
|
|
|
// Whether the node is non-liquid, source liquid or flowing liquid
|
|
|
|
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
|
|
|
|
es_LiquidType, LIQUID_NONE);
|
|
|
|
// If the content is liquid, this is the flowing version of the liquid.
|
|
|
|
getstringfield(L, index, "liquid_alternative_flowing",
|
|
|
|
f.liquid_alternative_flowing);
|
|
|
|
// If the content is liquid, this is the source version of the liquid.
|
|
|
|
getstringfield(L, index, "liquid_alternative_source",
|
|
|
|
f.liquid_alternative_source);
|
|
|
|
// Viscosity for fluid flow, ranging from 1 to 7, with
|
|
|
|
// 1 giving almost instantaneous propagation and 7 being
|
|
|
|
// the slowest possible
|
|
|
|
f.liquid_viscosity = getintfield_default(L, index,
|
|
|
|
"liquid_viscosity", f.liquid_viscosity);
|
2012-09-07 18:48:12 +02:00
|
|
|
getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
|
2012-01-12 06:10:39 +01:00
|
|
|
// Amount of light the node emits
|
|
|
|
f.light_source = getintfield_default(L, index,
|
|
|
|
"light_source", f.light_source);
|
|
|
|
f.damage_per_second = getintfield_default(L, index,
|
|
|
|
"damage_per_second", f.damage_per_second);
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_getfield(L, index, "node_box");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
f.node_box = read_nodebox(L, -1);
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
lua_getfield(L, index, "selection_box");
|
|
|
|
if(lua_istable(L, -1))
|
|
|
|
f.selection_box = read_nodebox(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
// Set to true if paramtype used to be 'facedir_simple'
|
|
|
|
getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
|
|
|
|
// Set to true if wall_mounted used to be set to true
|
|
|
|
getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
|
2012-03-23 19:23:03 +01:00
|
|
|
|
|
|
|
// Sound table
|
|
|
|
lua_getfield(L, index, "sounds");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
lua_getfield(L, -1, "footstep");
|
2012-03-24 02:28:08 +01:00
|
|
|
read_soundspec(L, -1, f.sound_footstep);
|
|
|
|
lua_pop(L, 1);
|
2012-03-24 10:10:28 +01:00
|
|
|
lua_getfield(L, -1, "dig");
|
|
|
|
read_soundspec(L, -1, f.sound_dig);
|
|
|
|
lua_pop(L, 1);
|
2012-03-24 02:28:08 +01:00
|
|
|
lua_getfield(L, -1, "dug");
|
|
|
|
read_soundspec(L, -1, f.sound_dug);
|
2012-03-23 19:23:03 +01:00
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2012-01-21 00:11:44 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Inventory stuff
|
|
|
|
*/
|
|
|
|
|
|
|
|
static ItemStack read_item(lua_State *L, int index);
|
2012-06-02 11:19:44 +02:00
|
|
|
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);
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
|
|
|
|
lua_State *L, int tableindex, 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
|
2012-06-02 11:19:44 +02:00
|
|
|
std::vector<ItemStack> items = read_items(L, tableindex);
|
2012-01-12 06:10:39 +01:00
|
|
|
int listsize = (forcesize != -1) ? forcesize : items.size();
|
|
|
|
InventoryList *invlist = inv->addList(name, listsize);
|
|
|
|
int index = 0;
|
|
|
|
for(std::vector<ItemStack>::const_iterator
|
|
|
|
i = items.begin(); i != items.end(); i++){
|
|
|
|
if(forcesize != -1 && index == forcesize)
|
|
|
|
break;
|
|
|
|
invlist->changeItem(index, *i);
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
while(forcesize != -1 && index < forcesize){
|
|
|
|
invlist->deleteItem(index);
|
|
|
|
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;
|
|
|
|
}
|
2012-06-02 11:19:44 +02:00
|
|
|
std::vector<ItemStack> items;
|
|
|
|
for(u32 i=0; i<invlist->getSize(); i++)
|
|
|
|
items.push_back(invlist->getItem(i));
|
|
|
|
push_items(L, items);
|
2012-01-12 06:10:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Helpful macros for userdata classes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define method(class, name) {#name, class::l_##name}
|
|
|
|
|
|
|
|
/*
|
|
|
|
LuaItemStack
|
|
|
|
*/
|
|
|
|
|
|
|
|
class LuaItemStack
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
ItemStack m_stack;
|
|
|
|
|
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
|
|
|
|
|
|
|
// Exported functions
|
|
|
|
|
|
|
|
// garbage collector
|
|
|
|
static int gc_object(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1));
|
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// is_empty(self) -> true/false
|
|
|
|
static int l_is_empty(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushboolean(L, item.empty());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_name(self) -> string
|
|
|
|
static int l_get_name(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushstring(L, item.name.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_count(self) -> number
|
|
|
|
static int l_get_count(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushinteger(L, item.count);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_wear(self) -> number
|
|
|
|
static int l_get_wear(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushinteger(L, item.wear);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_metadata(self) -> string
|
|
|
|
static int l_get_metadata(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear(self) -> true
|
|
|
|
static int l_clear(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
o->m_stack.clear();
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// replace(self, itemstack or itemstring or table or nil) -> true
|
|
|
|
static int l_replace(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
o->m_stack = read_item(L, 2);
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// to_string(self) -> string
|
|
|
|
static int l_to_string(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
std::string itemstring = o->m_stack.getItemString();
|
|
|
|
lua_pushstring(L, itemstring.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// to_table(self) -> table or nil
|
|
|
|
static int l_to_table(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
const ItemStack &item = o->m_stack;
|
|
|
|
if(item.empty())
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, item.name.c_str());
|
|
|
|
lua_setfield(L, -2, "name");
|
|
|
|
lua_pushinteger(L, item.count);
|
|
|
|
lua_setfield(L, -2, "count");
|
|
|
|
lua_pushinteger(L, item.wear);
|
|
|
|
lua_setfield(L, -2, "wear");
|
|
|
|
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
|
|
|
|
lua_setfield(L, -2, "metadata");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_stack_max(self) -> number
|
|
|
|
static int l_get_stack_max(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushinteger(L, item.getStackMax(get_server(L)->idef()));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_free_space(self) -> number
|
|
|
|
static int l_get_free_space(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
lua_pushinteger(L, item.freeSpace(get_server(L)->idef()));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// is_known(self) -> true/false
|
|
|
|
// Checks if the item is defined.
|
|
|
|
static int l_is_known(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
bool is_known = item.isKnown(get_server(L)->idef());
|
|
|
|
lua_pushboolean(L, is_known);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_definition(self) -> table
|
|
|
|
// Returns the item definition table from minetest.registered_items,
|
|
|
|
// or a fallback one (name="unknown")
|
|
|
|
static int l_get_definition(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
|
|
|
|
// Get minetest.registered_items[name]
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_items");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_getfield(L, -1, item.name.c_str());
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "unknown");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
// get_tool_capabilities(self) -> table
|
2012-01-12 06:10:39 +01:00
|
|
|
// Returns the effective tool digging properties.
|
|
|
|
// Returns those of the hand ("") if this item has none associated.
|
2012-02-28 18:45:23 +01:00
|
|
|
static int l_get_tool_capabilities(lua_State *L)
|
2012-01-12 06:10:39 +01:00
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
2012-02-28 18:45:23 +01:00
|
|
|
const ToolCapabilities &prop =
|
|
|
|
item.getToolCapabilities(get_server(L)->idef());
|
|
|
|
push_tool_capabilities(L, prop);
|
2012-01-12 06:10:39 +01:00
|
|
|
return 1;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// add_wear(self, amount) -> true/false
|
|
|
|
// The range for "amount" is [0,65535]. Wear is only added if the item
|
|
|
|
// is a tool. Adding wear might destroy the item.
|
|
|
|
// Returns true if the item is (or was) a tool.
|
|
|
|
static int l_add_wear(lua_State *L)
|
2011-12-06 16:23:58 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
int amount = lua_tointeger(L, 2);
|
|
|
|
bool result = item.addWear(amount, get_server(L)->idef());
|
|
|
|
lua_pushboolean(L, result);
|
2011-12-06 16:23:58 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// add_item(self, itemstack or itemstring or table or nil) -> itemstack
|
|
|
|
// Returns leftover item stack
|
|
|
|
static int l_add_item(lua_State *L)
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
ItemStack newitem = read_item(L, 2);
|
|
|
|
ItemStack leftover = item.addItem(newitem, get_server(L)->idef());
|
|
|
|
create(L, leftover);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
2011-11-28 01:16:51 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
|
|
|
|
// First return value is true iff the new item fits fully into the stack
|
|
|
|
// Second return value is the would-be-left-over item stack
|
|
|
|
static int l_item_fits(lua_State *L)
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
ItemStack newitem = read_item(L, 2);
|
|
|
|
ItemStack restitem;
|
|
|
|
bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef());
|
|
|
|
lua_pushboolean(L, fits); // first return value
|
|
|
|
create(L, restitem); // second return value
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// take_item(self, takecount=1) -> itemstack
|
|
|
|
static int l_take_item(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
u32 takecount = 1;
|
|
|
|
if(!lua_isnone(L, 2))
|
2012-06-01 23:33:51 +02:00
|
|
|
takecount = luaL_checkinteger(L, 2);
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack taken = item.takeItem(takecount);
|
|
|
|
create(L, taken);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
2011-11-28 01:16:51 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// peek_item(self, peekcount=1) -> itemstack
|
|
|
|
static int l_peek_item(lua_State *L)
|
2011-12-06 16:23:58 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack *o = checkobject(L, 1);
|
|
|
|
ItemStack &item = o->m_stack;
|
|
|
|
u32 peekcount = 1;
|
|
|
|
if(!lua_isnone(L, 2))
|
|
|
|
peekcount = lua_tointeger(L, 2);
|
|
|
|
ItemStack peekaboo = item.peekItem(peekcount);
|
|
|
|
create(L, peekaboo);
|
|
|
|
return 1;
|
2011-12-06 16:23:58 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
public:
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack(const ItemStack &item):
|
2011-12-06 14:55:05 +01:00
|
|
|
m_stack(item)
|
2011-12-03 17:18:59 +01:00
|
|
|
{
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
~LuaItemStack()
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
const ItemStack& getItem() const
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
return m_stack;
|
2011-11-28 01:16:51 +01:00
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack& getItem()
|
2011-11-28 01:16:51 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
return m_stack;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// LuaItemStack(itemstack or itemstring or table or nil)
|
|
|
|
// Creates an LuaItemStack and leaves it on top of stack
|
2011-12-06 14:55:05 +01:00
|
|
|
static int create_object(lua_State *L)
|
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack item = read_item(L, 1);
|
|
|
|
LuaItemStack *o = new LuaItemStack(item);
|
2011-12-06 14:55:05 +01:00
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Not callable from Lua
|
2012-01-12 06:10:39 +01:00
|
|
|
static int create(lua_State *L, const ItemStack &item)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack *o = new LuaItemStack(item);
|
2011-12-06 14:55:05 +01:00
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static LuaItemStack* 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 *(LuaItemStack**)ud; // unbox pointer
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void Register(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
int methodtable = lua_gettop(L);
|
|
|
|
luaL_newmetatable(L, className);
|
|
|
|
int metatable = lua_gettop(L);
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__metatable");
|
|
|
|
lua_pushvalue(L, methodtable);
|
|
|
|
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__index");
|
|
|
|
lua_pushvalue(L, methodtable);
|
|
|
|
lua_settable(L, metatable);
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__gc");
|
|
|
|
lua_pushcfunction(L, gc_object);
|
|
|
|
lua_settable(L, metatable);
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pop(L, 1); // drop metatable
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
luaL_openlib(L, 0, methods, 0); // fill methodtable
|
|
|
|
lua_pop(L, 1); // drop methodtable
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_register(L, className, create_object);
|
|
|
|
}
|
|
|
|
};
|
2012-01-12 06:10:39 +01:00
|
|
|
const char LuaItemStack::className[] = "ItemStack";
|
|
|
|
const luaL_reg LuaItemStack::methods[] = {
|
|
|
|
method(LuaItemStack, is_empty),
|
|
|
|
method(LuaItemStack, get_name),
|
|
|
|
method(LuaItemStack, get_count),
|
|
|
|
method(LuaItemStack, get_wear),
|
|
|
|
method(LuaItemStack, get_metadata),
|
|
|
|
method(LuaItemStack, clear),
|
|
|
|
method(LuaItemStack, replace),
|
|
|
|
method(LuaItemStack, to_string),
|
|
|
|
method(LuaItemStack, to_table),
|
|
|
|
method(LuaItemStack, get_stack_max),
|
|
|
|
method(LuaItemStack, get_free_space),
|
|
|
|
method(LuaItemStack, is_known),
|
|
|
|
method(LuaItemStack, get_definition),
|
2012-02-28 18:45:23 +01:00
|
|
|
method(LuaItemStack, get_tool_capabilities),
|
2012-01-12 06:10:39 +01:00
|
|
|
method(LuaItemStack, add_wear),
|
|
|
|
method(LuaItemStack, add_item),
|
|
|
|
method(LuaItemStack, item_fits),
|
|
|
|
method(LuaItemStack, take_item),
|
|
|
|
method(LuaItemStack, peek_item),
|
2011-12-06 14:55:05 +01:00
|
|
|
{0,0}
|
|
|
|
};
|
2011-11-28 01:16:51 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
static ItemStack read_item(lua_State *L, int index)
|
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
|
|
|
|
if(lua_isnil(L, index))
|
|
|
|
{
|
|
|
|
return ItemStack();
|
|
|
|
}
|
|
|
|
else if(lua_isuserdata(L, index))
|
|
|
|
{
|
|
|
|
// Convert from LuaItemStack
|
|
|
|
LuaItemStack *o = LuaItemStack::checkobject(L, index);
|
|
|
|
return o->getItem();
|
|
|
|
}
|
|
|
|
else if(lua_isstring(L, index))
|
|
|
|
{
|
|
|
|
// Convert from itemstring
|
|
|
|
std::string itemstring = lua_tostring(L, index);
|
|
|
|
IItemDefManager *idef = get_server(L)->idef();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ItemStack item;
|
|
|
|
item.deSerialize(itemstring, idef);
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
catch(SerializationError &e)
|
|
|
|
{
|
|
|
|
infostream<<"WARNING: unable to create item from itemstring"
|
|
|
|
<<": "<<itemstring<<std::endl;
|
|
|
|
return ItemStack();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(lua_istable(L, index))
|
|
|
|
{
|
|
|
|
// Convert from table
|
|
|
|
IItemDefManager *idef = get_server(L)->idef();
|
|
|
|
std::string name = getstringfield_default(L, index, "name", "");
|
|
|
|
int count = getintfield_default(L, index, "count", 1);
|
|
|
|
int wear = getintfield_default(L, index, "wear", 0);
|
|
|
|
std::string metadata = getstringfield_default(L, index, "metadata", "");
|
|
|
|
return ItemStack(name, count, wear, metadata, idef);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-02 11:19:44 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
/*
|
|
|
|
InvRef
|
|
|
|
*/
|
|
|
|
|
|
|
|
class InvRef
|
2011-11-15 01:03:28 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
private:
|
|
|
|
InventoryLocation m_loc;
|
2011-11-15 01:03:28 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
|
|
|
|
|
|
|
static InvRef *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 *(InvRef**)ud; // unbox pointer
|
|
|
|
}
|
2011-11-15 01:03:28 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static Inventory* getinv(lua_State *L, InvRef *ref)
|
|
|
|
{
|
|
|
|
return get_server(L)->getInventory(ref->m_loc);
|
|
|
|
}
|
2011-11-15 01:03:28 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static InventoryList* getlist(lua_State *L, InvRef *ref,
|
|
|
|
const char *listname)
|
|
|
|
{
|
|
|
|
Inventory *inv = getinv(L, ref);
|
|
|
|
if(!inv)
|
|
|
|
return NULL;
|
|
|
|
return inv->getList(listname);
|
|
|
|
}
|
2011-11-16 14:23:25 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void reportInventoryChange(lua_State *L, InvRef *ref)
|
|
|
|
{
|
|
|
|
// Inform other things that the inventory has changed
|
|
|
|
get_server(L)->setInventoryModified(ref->m_loc);
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Exported functions
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// garbage collector
|
|
|
|
static int gc_object(lua_State *L) {
|
|
|
|
InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
|
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-06-03 12:37:55 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_size(self, listname)
|
|
|
|
static int l_get_size(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
|
|
|
if(list){
|
|
|
|
lua_pushinteger(L, list->getSize());
|
|
|
|
} else {
|
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-08-19 23:29:56 +02:00
|
|
|
// get_width(self, listname)
|
|
|
|
static int l_get_width(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
|
|
|
if(list){
|
|
|
|
lua_pushinteger(L, list->getWidth());
|
|
|
|
} else {
|
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// set_size(self, listname, size)
|
|
|
|
static int l_set_size(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
int newsize = luaL_checknumber(L, 3);
|
|
|
|
Inventory *inv = getinv(L, ref);
|
|
|
|
if(newsize == 0){
|
|
|
|
inv->deleteList(listname);
|
2011-12-06 15:22:08 +01:00
|
|
|
reportInventoryChange(L, ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
InventoryList *list = inv->getList(listname);
|
|
|
|
if(list){
|
|
|
|
list->setSize(newsize);
|
|
|
|
} else {
|
|
|
|
list = inv->addList(listname, newsize);
|
|
|
|
}
|
2011-12-06 15:22:08 +01:00
|
|
|
reportInventoryChange(L, ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-08-19 23:29:56 +02:00
|
|
|
// set_width(self, listname, size)
|
|
|
|
static int l_set_width(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
int newwidth = luaL_checknumber(L, 3);
|
|
|
|
Inventory *inv = getinv(L, ref);
|
|
|
|
InventoryList *list = inv->getList(listname);
|
|
|
|
if(list){
|
|
|
|
list->setWidth(newwidth);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
reportInventoryChange(L, ref);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_stack(self, listname, i) -> itemstack
|
2011-12-06 14:55:05 +01:00
|
|
|
static int l_get_stack(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
2011-12-06 17:07:13 +01:00
|
|
|
int i = luaL_checknumber(L, 3) - 1;
|
2012-01-12 06:10:39 +01:00
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
|
|
|
ItemStack item;
|
|
|
|
if(list != NULL && i >= 0 && i < (int) list->getSize())
|
|
|
|
item = list->getItem(i);
|
|
|
|
LuaItemStack::create(L, item);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// set_stack(self, listname, i, stack) -> true/false
|
2011-12-06 14:55:05 +01:00
|
|
|
static int l_set_stack(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
2011-12-06 17:07:13 +01:00
|
|
|
int i = luaL_checknumber(L, 3) - 1;
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack newitem = read_item(L, 4);
|
2011-12-06 14:55:05 +01:00
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
2012-01-12 06:10:39 +01:00
|
|
|
if(list != NULL && i >= 0 && i < (int) list->getSize()){
|
|
|
|
list->changeItem(i, newitem);
|
|
|
|
reportInventoryChange(L, ref);
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
} else {
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushboolean(L, false);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2011-12-06 15:22:08 +01:00
|
|
|
// get_list(self, listname) -> list or nil
|
|
|
|
static int l_get_list(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
Inventory *inv = getinv(L, ref);
|
|
|
|
inventory_get_list_to_lua(inv, listname, L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set_list(self, listname, list)
|
|
|
|
static int l_set_list(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
Inventory *inv = getinv(L, ref);
|
|
|
|
InventoryList *list = inv->getList(listname);
|
|
|
|
if(list)
|
|
|
|
inventory_set_list_from_lua(inv, listname, L, 3,
|
2012-01-12 06:10:39 +01:00
|
|
|
list->getSize());
|
2011-12-06 15:22:08 +01:00
|
|
|
else
|
2012-01-12 06:10:39 +01:00
|
|
|
inventory_set_list_from_lua(inv, listname, L, 3);
|
2011-12-06 15:22:08 +01:00
|
|
|
reportInventoryChange(L, ref);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
|
|
|
|
// Returns the leftover stack
|
|
|
|
static int l_add_item(lua_State *L)
|
2011-12-06 17:07:13 +01:00
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack item = read_item(L, 3);
|
2011-12-06 17:07:13 +01:00
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
2012-01-12 06:10:39 +01:00
|
|
|
if(list){
|
|
|
|
ItemStack leftover = list->addItem(item);
|
|
|
|
if(leftover.count != item.count)
|
|
|
|
reportInventoryChange(L, ref);
|
|
|
|
LuaItemStack::create(L, leftover);
|
|
|
|
} else {
|
|
|
|
LuaItemStack::create(L, item);
|
2011-12-06 17:07:13 +01:00
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
|
|
|
|
// Returns true if the item completely fits into the list
|
|
|
|
static int l_room_for_item(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
ItemStack item = read_item(L, 3);
|
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
|
|
|
if(list){
|
|
|
|
lua_pushboolean(L, list->roomForItem(item));
|
2011-12-06 17:07:13 +01:00
|
|
|
} else {
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
|
|
|
|
// Returns true if the list contains the given count of the given item name
|
|
|
|
static int l_contains_item(lua_State *L)
|
2011-12-06 17:07:13 +01:00
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack item = read_item(L, 3);
|
2011-12-06 17:07:13 +01:00
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
2012-01-12 06:10:39 +01:00
|
|
|
if(list){
|
|
|
|
lua_pushboolean(L, list->containsItem(item));
|
|
|
|
} else {
|
2011-12-06 17:07:13 +01:00
|
|
|
lua_pushboolean(L, false);
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
|
|
|
|
// Returns the items that were actually removed
|
|
|
|
static int l_remove_item(lua_State *L)
|
|
|
|
{
|
|
|
|
InvRef *ref = checkobject(L, 1);
|
|
|
|
const char *listname = luaL_checkstring(L, 2);
|
|
|
|
ItemStack item = read_item(L, 3);
|
|
|
|
InventoryList *list = getlist(L, ref, listname);
|
|
|
|
if(list){
|
|
|
|
ItemStack removed = list->removeItem(item);
|
|
|
|
if(!removed.empty())
|
|
|
|
reportInventoryChange(L, ref);
|
|
|
|
LuaItemStack::create(L, removed);
|
2011-12-06 17:07:13 +01:00
|
|
|
} else {
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack::create(L, ItemStack());
|
2011-12-06 17:07:13 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
public:
|
|
|
|
InvRef(const InventoryLocation &loc):
|
|
|
|
m_loc(loc)
|
|
|
|
{
|
|
|
|
}
|
2011-11-16 14:23:25 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
~InvRef()
|
|
|
|
{
|
|
|
|
}
|
2011-11-26 01:26:19 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Creates an InvRef 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, const InventoryLocation &loc)
|
|
|
|
{
|
|
|
|
InvRef *o = new InvRef(loc);
|
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
}
|
|
|
|
static void createPlayer(lua_State *L, Player *player)
|
|
|
|
{
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setPlayer(player->getName());
|
|
|
|
create(L, loc);
|
|
|
|
}
|
|
|
|
static void createNodeMeta(lua_State *L, v3s16 p)
|
|
|
|
{
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setNodeMeta(p);
|
|
|
|
create(L, loc);
|
|
|
|
}
|
2011-11-26 01:26:19 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void Register(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
int methodtable = lua_gettop(L);
|
|
|
|
luaL_newmetatable(L, className);
|
|
|
|
int metatable = lua_gettop(L);
|
2011-11-26 01:26:19 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__metatable");
|
|
|
|
lua_pushvalue(L, methodtable);
|
|
|
|
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__index");
|
|
|
|
lua_pushvalue(L, methodtable);
|
|
|
|
lua_settable(L, metatable);
|
2011-11-16 14:23:25 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushliteral(L, "__gc");
|
|
|
|
lua_pushcfunction(L, gc_object);
|
|
|
|
lua_settable(L, metatable);
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pop(L, 1); // drop metatable
|
2011-11-25 15:34:12 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
luaL_openlib(L, 0, methods, 0); // fill methodtable
|
|
|
|
lua_pop(L, 1); // drop methodtable
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Cannot be created from Lua
|
|
|
|
//lua_register(L, className, create_object);
|
2011-11-16 14:23:25 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
};
|
|
|
|
const char InvRef::className[] = "InvRef";
|
|
|
|
const luaL_reg InvRef::methods[] = {
|
2012-06-03 12:37:55 +02:00
|
|
|
method(InvRef, is_empty),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(InvRef, get_size),
|
|
|
|
method(InvRef, set_size),
|
2012-08-19 23:29:56 +02:00
|
|
|
method(InvRef, get_width),
|
|
|
|
method(InvRef, set_width),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(InvRef, get_stack),
|
|
|
|
method(InvRef, set_stack),
|
2011-12-06 15:22:08 +01:00
|
|
|
method(InvRef, get_list),
|
|
|
|
method(InvRef, set_list),
|
2012-01-12 06:10:39 +01:00
|
|
|
method(InvRef, add_item),
|
|
|
|
method(InvRef, room_for_item),
|
|
|
|
method(InvRef, contains_item),
|
|
|
|
method(InvRef, remove_item),
|
2011-12-06 14:55:05 +01:00
|
|
|
{0,0}
|
|
|
|
};
|
2011-11-16 14:23:25 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
/*
|
|
|
|
NodeMetaRef
|
|
|
|
*/
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
class NodeMetaRef
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
v3s16 m_p;
|
|
|
|
ServerEnvironment *m_env;
|
2011-11-15 01:03:28 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static NodeMetaRef *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 *(NodeMetaRef**)ud; // unbox pointer
|
|
|
|
}
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
|
2012-03-19 01:08:04 +01:00
|
|
|
if(meta == NULL && auto_create)
|
|
|
|
{
|
|
|
|
meta = new NodeMetadata(ref->m_env->getGameDef());
|
|
|
|
ref->m_env->getMap().setNodeMetadata(ref->m_p, meta);
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
return meta;
|
|
|
|
}
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void reportMetadataChange(NodeMetaRef *ref)
|
|
|
|
{
|
2012-07-26 21:06:45 +02:00
|
|
|
// NOTE: This same code is in rollback_interface.cpp
|
2011-12-06 14:55:05 +01:00
|
|
|
// Inform other things that the metadata has changed
|
|
|
|
v3s16 blockpos = getNodeBlockPos(ref->m_p);
|
|
|
|
MapEditEvent event;
|
|
|
|
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
|
|
|
event.p = blockpos;
|
|
|
|
ref->m_env->getMap().dispatchEvent(&event);
|
|
|
|
// Set the block to be saved
|
|
|
|
MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
|
|
|
|
if(block)
|
|
|
|
block->raiseModified(MOD_STATE_WRITE_NEEDED,
|
|
|
|
"NodeMetaRef::reportMetadataChange");
|
|
|
|
}
|
2011-11-25 13:58:42 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Exported functions
|
2011-11-25 15:34:12 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// garbage collector
|
|
|
|
static int gc_object(lua_State *L) {
|
|
|
|
NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
|
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-25 15:34:12 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// get_string(self, name)
|
|
|
|
static int l_get_string(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string name = luaL_checkstring(L, 2);
|
|
|
|
|
|
|
|
NodeMetadata *meta = getmeta(ref, false);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(meta == NULL){
|
2012-03-19 01:08:04 +01:00
|
|
|
lua_pushlstring(L, "", 0);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string str = meta->getString(name);
|
|
|
|
lua_pushlstring(L, str.c_str(), str.size());
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
2011-11-25 15:34:12 +01:00
|
|
|
}
|
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// set_string(self, name, var)
|
|
|
|
static int l_set_string(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string name = luaL_checkstring(L, 2);
|
|
|
|
size_t len = 0;
|
|
|
|
const char *s = lua_tolstring(L, 3, &len);
|
|
|
|
std::string str(s, len);
|
2011-11-15 01:03:28 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
NodeMetadata *meta = getmeta(ref, !str.empty());
|
|
|
|
if(meta == NULL || str == meta->getString(name))
|
|
|
|
return 0;
|
|
|
|
meta->setString(name, str);
|
2011-12-06 14:55:05 +01:00
|
|
|
reportMetadataChange(ref);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-12-03 22:50:31 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// get_int(self, name)
|
|
|
|
static int l_get_int(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string name = lua_tostring(L, 2);
|
2011-12-03 22:50:31 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
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));
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-12-03 23:22:34 +01:00
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// set_int(self, name, var)
|
|
|
|
static int l_set_int(lua_State *L)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
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);
|
2012-01-21 00:11:44 +01:00
|
|
|
reportMetadataChange(ref);
|
2012-03-19 01:08:04 +01:00
|
|
|
return 0;
|
2012-01-21 00:11:44 +01:00
|
|
|
}
|
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// get_float(self, name)
|
|
|
|
static int l_get_float(lua_State *L)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string name = lua_tostring(L, 2);
|
|
|
|
|
|
|
|
NodeMetadata *meta = getmeta(ref, false);
|
2012-01-21 00:11:44 +01:00
|
|
|
if(meta == NULL){
|
2012-03-19 01:08:04 +01:00
|
|
|
lua_pushnumber(L, 0);
|
2012-01-21 00:11:44 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2012-03-19 01:08:04 +01:00
|
|
|
std::string str = meta->getString(name);
|
|
|
|
lua_pushnumber(L, stof(str));
|
2012-01-21 00:11:44 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-19 01:08:04 +01:00
|
|
|
// set_float(self, name, var)
|
|
|
|
static int l_set_float(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
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);
|
2011-12-06 14:55:05 +01:00
|
|
|
reportMetadataChange(ref);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-12-03 23:22:34 +01:00
|
|
|
|
2011-12-06 16:23:58 +01:00
|
|
|
// get_inventory(self)
|
|
|
|
static int l_get_inventory(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
getmeta(ref, true); // try to ensure the metadata exists
|
2011-12-06 16:23:58 +01:00
|
|
|
InvRef::createNodeMeta(L, ref->m_p);
|
|
|
|
return 1;
|
|
|
|
}
|
2012-06-02 10:01:28 +02:00
|
|
|
|
|
|
|
// to_table(self)
|
|
|
|
static int l_to_table(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-03-19 01:08:04 +01:00
|
|
|
|
2012-06-02 10:01:28 +02:00
|
|
|
NodeMetadata *meta = getmeta(ref, true);
|
2012-03-19 01:08:04 +01:00
|
|
|
if(meta == NULL){
|
2012-06-02 10:01:28 +02:00
|
|
|
lua_pushnil(L);
|
2012-03-19 01:08:04 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2012-06-02 10:01:28 +02:00
|
|
|
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);
|
|
|
|
}
|
2012-03-19 01:08:04 +01:00
|
|
|
}
|
2012-06-02 10:01:28 +02:00
|
|
|
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");
|
2012-03-19 01:08:04 +01:00
|
|
|
return 1;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2011-11-17 01:28:46 +01:00
|
|
|
|
2012-06-02 10:01:28 +02:00
|
|
|
// from_table(self, table)
|
|
|
|
static int l_from_table(lua_State *L)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
|
|
|
NodeMetaRef *ref = checkobject(L, 1);
|
2012-06-02 10:01:28 +02:00
|
|
|
int base = 2;
|
|
|
|
|
|
|
|
if(lua_isnil(L, base)){
|
|
|
|
// No metadata
|
|
|
|
ref->m_env->getMap().removeNodeMetadata(ref->m_p);
|
|
|
|
lua_pushboolean(L, true);
|
2012-03-19 01:08:04 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-11-17 01:28:46 +01:00
|
|
|
|
2012-06-02 10:01:28 +02:00
|
|
|
// 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
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
reportMetadataChange(ref);
|
2012-06-02 10:01:28 +02:00
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2011-12-06 14:55:05 +01:00
|
|
|
NodeMetaRef(v3s16 p, ServerEnvironment *env):
|
|
|
|
m_p(p),
|
|
|
|
m_env(env)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
~NodeMetaRef()
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// 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)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
NodeMetaRef *o = new NodeMetaRef(p, env);
|
|
|
|
//infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
|
2011-12-06 14:21:56 +01:00
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Cannot be created from Lua
|
|
|
|
//lua_register(L, className, create_object);
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
};
|
2011-12-06 14:55:05 +01:00
|
|
|
const char NodeMetaRef::className[] = "NodeMetaRef";
|
|
|
|
const luaL_reg NodeMetaRef::methods[] = {
|
2012-03-19 01:08:04 +01:00
|
|
|
method(NodeMetaRef, get_string),
|
|
|
|
method(NodeMetaRef, set_string),
|
|
|
|
method(NodeMetaRef, get_int),
|
|
|
|
method(NodeMetaRef, set_int),
|
|
|
|
method(NodeMetaRef, get_float),
|
|
|
|
method(NodeMetaRef, set_float),
|
2011-12-06 16:23:58 +01:00
|
|
|
method(NodeMetaRef, get_inventory),
|
2012-06-02 10:01:28 +02:00
|
|
|
method(NodeMetaRef, to_table),
|
|
|
|
method(NodeMetaRef, from_table),
|
2011-12-06 14:21:56 +01:00
|
|
|
{0,0}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef
|
2011-12-06 14:21:56 +01:00
|
|
|
*/
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
class ObjectRef
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
|
|
|
private:
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *m_object;
|
2011-12-06 14:21:56 +01:00
|
|
|
|
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
2012-03-24 18:01:26 +01:00
|
|
|
public:
|
2011-12-06 14:55:05 +01:00
|
|
|
static ObjectRef *checkobject(lua_State *L, int narg)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
|
|
|
luaL_checktype(L, narg, LUA_TUSERDATA);
|
|
|
|
void *ud = luaL_checkudata(L, narg, className);
|
|
|
|
if(!ud) luaL_typerror(L, narg, className);
|
2011-12-06 14:55:05 +01:00
|
|
|
return *(ObjectRef**)ud; // unbox pointer
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static ServerActiveObject* getobject(ObjectRef *ref)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *co = ref->m_object;
|
|
|
|
return co;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
2012-03-24 18:01:26 +01:00
|
|
|
private:
|
2011-12-06 14:55:05 +01:00
|
|
|
static LuaEntitySAO* getluaobject(ObjectRef *ref)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *obj = getobject(ref);
|
|
|
|
if(obj == NULL)
|
2011-12-06 14:21:56 +01:00
|
|
|
return NULL;
|
2011-12-06 14:55:05 +01:00
|
|
|
if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
|
2011-12-06 14:21:56 +01:00
|
|
|
return NULL;
|
2011-12-06 14:55:05 +01:00
|
|
|
return (LuaEntitySAO*)obj;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-03-19 03:04:16 +01:00
|
|
|
static PlayerSAO* getplayersao(ObjectRef *ref)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *obj = getobject(ref);
|
|
|
|
if(obj == NULL)
|
|
|
|
return NULL;
|
|
|
|
if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
|
|
|
|
return NULL;
|
2012-03-19 03:04:16 +01:00
|
|
|
return (PlayerSAO*)obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Player* getplayer(ObjectRef *ref)
|
|
|
|
{
|
|
|
|
PlayerSAO *playersao = getplayersao(ref);
|
|
|
|
if(playersao == NULL)
|
|
|
|
return NULL;
|
|
|
|
return playersao->getPlayer();
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exported functions
|
|
|
|
|
|
|
|
// garbage collector
|
|
|
|
static int gc_object(lua_State *L) {
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
|
|
|
|
//infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
|
2011-12-06 14:21:56 +01:00
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// remove(self)
|
|
|
|
static int l_remove(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
|
2011-12-06 14:55:05 +01:00
|
|
|
co->m_removed = true;
|
2011-12-06 14:21:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// getpos(self)
|
|
|
|
// returns: {x=num, y=num, z=num}
|
|
|
|
static int l_getpos(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
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");
|
2011-12-06 14:21:56 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// setpos(self, pos)
|
|
|
|
static int l_setpos(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
//LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// pos
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
|
|
|
// Do it
|
|
|
|
co->setPos(pos);
|
|
|
|
return 0;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// moveto(self, pos, continuous=false)
|
|
|
|
static int l_moveto(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
//LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// pos
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
|
|
|
// continuous
|
|
|
|
bool continuous = lua_toboolean(L, 3);
|
|
|
|
// Do it
|
|
|
|
co->moveTo(pos, continuous);
|
|
|
|
return 0;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
2012-09-09 11:05:38 +02:00
|
|
|
// punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
2011-12-06 14:55:05 +01:00
|
|
|
static int l_punch(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-03-04 20:08:03 +01:00
|
|
|
ObjectRef *puncher_ref = checkobject(L, 2);
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *co = getobject(ref);
|
2012-03-04 20:08:03 +01:00
|
|
|
ServerActiveObject *puncher = getobject(puncher_ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(co == NULL) return 0;
|
2012-03-04 20:08:03 +01:00
|
|
|
if(puncher == NULL) return 0;
|
2012-09-09 11:05:38 +02:00
|
|
|
v3f dir;
|
|
|
|
if(lua_type(L, 5) != LUA_TTABLE)
|
|
|
|
dir = co->getBasePosition() - puncher->getBasePosition();
|
|
|
|
else
|
|
|
|
dir = read_v3f(L, 5);
|
2012-03-04 20:08:03 +01:00
|
|
|
float time_from_last_punch = 1000000;
|
2012-09-09 11:05:38 +02:00
|
|
|
if(lua_isnumber(L, 3))
|
|
|
|
time_from_last_punch = lua_tonumber(L, 3);
|
|
|
|
ToolCapabilities toolcap = read_tool_capabilities(L, 4);
|
|
|
|
dir.normalize();
|
2011-12-06 14:55:05 +01:00
|
|
|
// Do it
|
2012-09-09 11:05:38 +02:00
|
|
|
co->punch(dir, &toolcap, puncher, time_from_last_punch);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// right_click(self, clicker); clicker = an another ObjectRef
|
|
|
|
static int l_right_click(lua_State *L)
|
2011-12-06 14:21:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
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;
|
2011-12-06 14:21:56 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// set_hp(self, hp)
|
|
|
|
// hp = number of hitpoints (2 * number of hearts)
|
|
|
|
// returns: nil
|
|
|
|
static int l_set_hp(lua_State *L)
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-01-12 06:10:39 +01:00
|
|
|
luaL_checknumber(L, 2);
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2012-01-12 06:10:39 +01:00
|
|
|
int hp = lua_tonumber(L, 2);
|
2012-03-11 03:15:45 +01:00
|
|
|
/*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
|
|
|
|
<<" hp="<<hp<<std::endl;*/
|
2011-12-06 14:55:05 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
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);
|
2012-06-05 22:09:18 +02:00
|
|
|
if(co == NULL){
|
|
|
|
// Default hp is 1
|
|
|
|
lua_pushnumber(L, 1);
|
|
|
|
return 1;
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
int hp = co->getHP();
|
2012-03-11 03:15:45 +01:00
|
|
|
/*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
|
|
|
|
<<" hp="<<hp<<std::endl;*/
|
2012-01-12 06:10:39 +01:00
|
|
|
// Return
|
|
|
|
lua_pushnumber(L, hp);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
2011-11-28 02:06:21 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_inventory(self)
|
|
|
|
static int l_get_inventory(lua_State *L)
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
InventoryLocation loc = co->getInventoryLocation();
|
|
|
|
if(get_server(L)->getInventory(loc) != NULL)
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
else
|
2012-06-05 22:09:18 +02:00
|
|
|
lua_pushnil(L); // An object may have no inventory (nil)
|
2012-01-12 06:10:39 +01:00
|
|
|
return 1;
|
2011-11-28 02:06:21 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_wield_list(self)
|
|
|
|
static int l_get_wield_list(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushstring(L, co->getWieldList().c_str());
|
|
|
|
return 1;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_wield_index(self)
|
|
|
|
static int l_get_wield_index(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushinteger(L, co->getWieldIndex() + 1);
|
|
|
|
return 1;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_wielded_item(self)
|
|
|
|
static int l_get_wielded_item(lua_State *L)
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
2012-06-05 22:09:18 +02:00
|
|
|
if(co == NULL){
|
|
|
|
// Empty ItemStack
|
|
|
|
LuaItemStack::create(L, ItemStack());
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-28 02:06:21 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack::create(L, co->getWieldedItem());
|
|
|
|
return 1;
|
2011-11-28 02:06:21 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// set_wielded_item(self, itemstack or itemstring or table or nil)
|
|
|
|
static int l_set_wielded_item(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2012-01-12 06:10:39 +01:00
|
|
|
// Do it
|
|
|
|
ItemStack item = read_item(L, 2);
|
|
|
|
bool success = co->setWieldedItem(item);
|
|
|
|
lua_pushboolean(L, success);
|
2011-11-28 16:11:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-30 12:26:40 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-11-12 15:35:10 +01:00
|
|
|
// set_animation(self, frame_range, frame_speed, frame_blend)
|
|
|
|
static int l_set_animation(lua_State *L)
|
2012-10-26 17:03:24 +02:00
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
v2f frames = v2f(1, 1);
|
|
|
|
if(!lua_isnil(L, 2))
|
|
|
|
frames = read_v2f(L, 2);
|
|
|
|
float frame_speed = 15;
|
|
|
|
if(!lua_isnil(L, 3))
|
|
|
|
frame_speed = lua_tonumber(L, 3);
|
|
|
|
float frame_blend = 0;
|
|
|
|
if(!lua_isnil(L, 4))
|
|
|
|
frame_blend = lua_tonumber(L, 4);
|
2012-11-12 15:35:10 +01:00
|
|
|
co->setAnimation(frames, frame_speed, frame_blend);
|
2012-10-26 17:03:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-12 15:35:10 +01:00
|
|
|
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
|
|
|
|
static int l_set_bone_position(lua_State *L)
|
2012-10-26 17:03:24 +02:00
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
std::string bone = "";
|
|
|
|
if(!lua_isnil(L, 2))
|
|
|
|
bone = lua_tostring(L, 2);
|
|
|
|
v3f position = v3f(0, 0, 0);
|
|
|
|
if(!lua_isnil(L, 3))
|
|
|
|
position = read_v3f(L, 3);
|
|
|
|
v3f rotation = v3f(0, 0, 0);
|
|
|
|
if(!lua_isnil(L, 4))
|
|
|
|
rotation = read_v3f(L, 4);
|
2012-11-12 15:35:10 +01:00
|
|
|
co->setBonePosition(bone, position, rotation);
|
2012-10-26 17:03:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-12 15:35:10 +01:00
|
|
|
// set_attach(self, parent, bone, position, rotation)
|
|
|
|
static int l_set_attach(lua_State *L)
|
2012-10-27 00:49:01 +02:00
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ObjectRef *parent_ref = checkobject(L, 2);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
ServerActiveObject *parent = getobject(parent_ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
if(parent == NULL) return 0;
|
Update attachments at the ending of the addToScene function for parents. And with this... *drum roll* Client-side attachments are at last functional and stick visibly.
Fix the last segmentation fault (apparently). So far attachments seem to be fully functional, although removing the parent causes children to go to origin 0,0,0 and possibly still cause such a fault (though this should already be addressed)
Fix a bug in falling code where entities get stuck
Also check if the parent has been removed server-side, and detach the child if so. Fixes children going to origin 0,0,0 when their parent is removed.
Unset all attachment properties when permanently detaching (on both the client and server). Also store less data we don't need
Create a separate function for detaching, and also update lua api documentation
When a child is detached, update its position from the server to clients. This WILL cause it to get positioned slightly differently client side, as the server attachment system only copies parent origin and knows not about mesh / bone transformation. This prevents different clients seeing the object detached in different spots which is most correct
Update the position of attached players to clients. An attached player will see himself move, but this is currently VERY ugly and laggy as it is done by the server (it probably must stay this way too)
Use a different approach for locally attached players. This allows for smooth positio transitions to work, as well at the player turning around freely. Still buggy however
2012-11-07 17:42:38 +01:00
|
|
|
// Do it
|
2012-10-27 00:49:01 +02:00
|
|
|
std::string bone = "";
|
|
|
|
if(!lua_isnil(L, 3))
|
|
|
|
bone = lua_tostring(L, 3);
|
|
|
|
v3f position = v3f(0, 0, 0);
|
|
|
|
if(!lua_isnil(L, 4))
|
|
|
|
position = read_v3f(L, 4);
|
|
|
|
v3f rotation = v3f(0, 0, 0);
|
|
|
|
if(!lua_isnil(L, 5))
|
|
|
|
rotation = read_v3f(L, 5);
|
Update attachments at the ending of the addToScene function for parents. And with this... *drum roll* Client-side attachments are at last functional and stick visibly.
Fix the last segmentation fault (apparently). So far attachments seem to be fully functional, although removing the parent causes children to go to origin 0,0,0 and possibly still cause such a fault (though this should already be addressed)
Fix a bug in falling code where entities get stuck
Also check if the parent has been removed server-side, and detach the child if so. Fixes children going to origin 0,0,0 when their parent is removed.
Unset all attachment properties when permanently detaching (on both the client and server). Also store less data we don't need
Create a separate function for detaching, and also update lua api documentation
When a child is detached, update its position from the server to clients. This WILL cause it to get positioned slightly differently client side, as the server attachment system only copies parent origin and knows not about mesh / bone transformation. This prevents different clients seeing the object detached in different spots which is most correct
Update the position of attached players to clients. An attached player will see himself move, but this is currently VERY ugly and laggy as it is done by the server (it probably must stay this way too)
Use a different approach for locally attached players. This allows for smooth positio transitions to work, as well at the player turning around freely. Still buggy however
2012-11-07 17:42:38 +01:00
|
|
|
co->setAttachment(parent->getId(), bone, position, rotation);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-10-27 00:49:01 +02:00
|
|
|
|
2012-11-12 15:35:10 +01:00
|
|
|
// set_detach(self)
|
|
|
|
static int l_set_detach(lua_State *L)
|
Update attachments at the ending of the addToScene function for parents. And with this... *drum roll* Client-side attachments are at last functional and stick visibly.
Fix the last segmentation fault (apparently). So far attachments seem to be fully functional, although removing the parent causes children to go to origin 0,0,0 and possibly still cause such a fault (though this should already be addressed)
Fix a bug in falling code where entities get stuck
Also check if the parent has been removed server-side, and detach the child if so. Fixes children going to origin 0,0,0 when their parent is removed.
Unset all attachment properties when permanently detaching (on both the client and server). Also store less data we don't need
Create a separate function for detaching, and also update lua api documentation
When a child is detached, update its position from the server to clients. This WILL cause it to get positioned slightly differently client side, as the server attachment system only copies parent origin and knows not about mesh / bone transformation. This prevents different clients seeing the object detached in different spots which is most correct
Update the position of attached players to clients. An attached player will see himself move, but this is currently VERY ugly and laggy as it is done by the server (it probably must stay this way too)
Use a different approach for locally attached players. This allows for smooth positio transitions to work, as well at the player turning around freely. Still buggy however
2012-11-07 17:42:38 +01:00
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
ServerActiveObject *co = getobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
|
2012-10-27 00:49:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-30 12:26:40 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
/* LuaEntitySAO-only */
|
|
|
|
|
|
|
|
// setvelocity(self, {x=num, y=num, z=num})
|
|
|
|
static int l_setvelocity(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
co->setVelocity(pos);
|
|
|
|
return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
|
|
|
|
2012-01-02 15:19:52 +01:00
|
|
|
// getvelocity(self)
|
|
|
|
static int l_getvelocity(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
v3f v = co->getVelocity();
|
|
|
|
pushFloatPos(L, v);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// setacceleration(self, {x=num, y=num, z=num})
|
|
|
|
static int l_setacceleration(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// pos
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
co->setAcceleration(pos);
|
2011-11-28 16:11:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// getacceleration(self)
|
|
|
|
static int l_getacceleration(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
v3f v = co->getAcceleration();
|
|
|
|
pushFloatPos(L, v);
|
2011-11-28 16:11:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-02 15:19:52 +01:00
|
|
|
// setyaw(self, radians)
|
|
|
|
static int l_setyaw(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
|
|
|
|
// Do it
|
|
|
|
co->setYaw(yaw);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// getyaw(self)
|
|
|
|
static int l_getyaw(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
float yaw = co->getYaw() * core::DEGTORAD;
|
|
|
|
lua_pushnumber(L, yaw);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// settexturemod(self, mod)
|
|
|
|
static int l_settexturemod(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
std::string mod = luaL_checkstring(L, 2);
|
|
|
|
co->setTextureMod(mod);
|
2011-11-28 16:11:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// 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)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
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);
|
2011-11-28 16:11:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-02 16:33:03 +01:00
|
|
|
// DEPRECATED
|
2012-01-02 12:12:56 +01:00
|
|
|
// get_entity_name(self)
|
|
|
|
static int l_get_entity_name(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
std::string name = co->getName();
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushstring(L, name.c_str());
|
|
|
|
return 1;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
// get_luaentity(self)
|
|
|
|
static int l_get_luaentity(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaEntitySAO *co = getluaobject(ref);
|
|
|
|
if(co == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
luaentity_get(L, co->getId());
|
2011-11-28 16:11:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
/* Player-only */
|
2012-06-02 14:47:36 +02:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
// get_player_name(self)
|
|
|
|
static int l_get_player_name(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-03-19 03:04:16 +01:00
|
|
|
Player *player = getplayer(ref);
|
2012-01-12 06:10:39 +01:00
|
|
|
if(player == NULL){
|
2012-06-02 14:47:36 +02:00
|
|
|
lua_pushlstring(L, "", 0);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushstring(L, player->getName());
|
2011-11-28 16:11:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_look_dir(self)
|
|
|
|
static int l_get_look_dir(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-03-19 03:04:16 +01:00
|
|
|
Player *player = getplayer(ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(player == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
float pitch = player->getRadPitch();
|
|
|
|
float yaw = player->getRadYaw();
|
|
|
|
v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
|
|
|
|
push_v3f(L, v);
|
|
|
|
return 1;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_look_pitch(self)
|
|
|
|
static int l_get_look_pitch(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-03-19 03:04:16 +01:00
|
|
|
Player *player = getplayer(ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(player == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushnumber(L, player->getRadPitch());
|
|
|
|
return 1;
|
2011-11-28 16:11:14 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_look_yaw(self)
|
|
|
|
static int l_get_look_yaw(lua_State *L)
|
2011-11-28 16:11:14 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
2012-03-19 03:04:16 +01:00
|
|
|
Player *player = getplayer(ref);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(player == NULL) return 0;
|
2011-11-28 16:11:14 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushnumber(L, player->getRadYaw());
|
2011-11-28 16:11:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-07-19 13:09:16 +02:00
|
|
|
// set_inventory_formspec(self, formspec)
|
|
|
|
static int l_set_inventory_formspec(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
Player *player = getplayer(ref);
|
|
|
|
if(player == NULL) return 0;
|
|
|
|
std::string formspec = luaL_checkstring(L, 2);
|
|
|
|
|
|
|
|
player->inventory_formspec = formspec;
|
|
|
|
get_server(L)->reportInventoryFormspecModified(player->getName());
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_inventory_formspec(self) -> formspec
|
|
|
|
static int l_get_inventory_formspec(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
Player *player = getplayer(ref);
|
|
|
|
if(player == NULL) return 0;
|
|
|
|
|
|
|
|
std::string formspec = player->inventory_formspec;
|
|
|
|
lua_pushlstring(L, formspec.c_str(), formspec.size());
|
|
|
|
return 1;
|
|
|
|
}
|
2012-11-22 20:01:31 +01:00
|
|
|
|
|
|
|
// get_player_control(self)
|
|
|
|
static int l_get_player_control(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
Player *player = getplayer(ref);
|
|
|
|
if(player == NULL){
|
|
|
|
lua_pushlstring(L, "", 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Do it
|
|
|
|
PlayerControl control = player->getPlayerControl();
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushboolean(L, control.up);
|
|
|
|
lua_setfield(L, -2, "up");
|
|
|
|
lua_pushboolean(L, control.down);
|
|
|
|
lua_setfield(L, -2, "down");
|
|
|
|
lua_pushboolean(L, control.left);
|
|
|
|
lua_setfield(L, -2, "left");
|
|
|
|
lua_pushboolean(L, control.right);
|
|
|
|
lua_setfield(L, -2, "right");
|
|
|
|
lua_pushboolean(L, control.jump);
|
|
|
|
lua_setfield(L, -2, "jump");
|
|
|
|
lua_pushboolean(L, control.aux1);
|
|
|
|
lua_setfield(L, -2, "aux1");
|
|
|
|
lua_pushboolean(L, control.sneak);
|
|
|
|
lua_setfield(L, -2, "sneak");
|
|
|
|
lua_pushboolean(L, control.LMB);
|
|
|
|
lua_setfield(L, -2, "LMB");
|
|
|
|
lua_pushboolean(L, control.RMB);
|
|
|
|
lua_setfield(L, -2, "RMB");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_player_control_bits(self)
|
|
|
|
static int l_get_player_control_bits(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *ref = checkobject(L, 1);
|
|
|
|
Player *player = getplayer(ref);
|
|
|
|
if(player == NULL){
|
|
|
|
lua_pushlstring(L, "", 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Do it
|
|
|
|
lua_pushnumber(L, player->keyPressed);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-11-28 02:06:21 +01:00
|
|
|
public:
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef(ServerActiveObject *object):
|
|
|
|
m_object(object)
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
//infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
|
2011-11-28 02:06:21 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
~ObjectRef()
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
/*if(m_object)
|
|
|
|
infostream<<"ObjectRef destructing for id="
|
|
|
|
<<m_object->getId()<<std::endl;
|
|
|
|
else
|
|
|
|
infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
|
2011-11-28 02:06:21 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Creates an ObjectRef and leaves it on top of stack
|
2011-11-28 02:06:21 +01:00
|
|
|
// Not callable from Lua; all references are created on the C side.
|
2011-12-06 14:55:05 +01:00
|
|
|
static void create(lua_State *L, ServerActiveObject *object)
|
2011-11-28 02:06:21 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef *o = new ObjectRef(object);
|
|
|
|
//infostream<<"ObjectRef::create: o="<<o<<std::endl;
|
2011-11-28 02:06:21 +01:00
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void set_null(lua_State *L)
|
|
|
|
{
|
|
|
|
ObjectRef *o = checkobject(L, -1);
|
|
|
|
o->m_object = NULL;
|
|
|
|
}
|
|
|
|
|
2011-11-28 02:06:21 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2011-12-06 14:55:05 +01:00
|
|
|
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, set_hp),
|
|
|
|
method(ObjectRef, get_hp),
|
2012-01-12 06:10:39 +01:00
|
|
|
method(ObjectRef, get_inventory),
|
|
|
|
method(ObjectRef, get_wield_list),
|
|
|
|
method(ObjectRef, get_wield_index),
|
|
|
|
method(ObjectRef, get_wielded_item),
|
|
|
|
method(ObjectRef, set_wielded_item),
|
2012-03-30 12:26:40 +02:00
|
|
|
method(ObjectRef, set_armor_groups),
|
2012-11-12 15:35:10 +01:00
|
|
|
method(ObjectRef, set_animation),
|
|
|
|
method(ObjectRef, set_bone_position),
|
|
|
|
method(ObjectRef, set_attach),
|
|
|
|
method(ObjectRef, set_detach),
|
2012-03-30 12:26:40 +02:00
|
|
|
method(ObjectRef, set_properties),
|
2011-12-06 14:55:05 +01:00
|
|
|
// LuaEntitySAO-only
|
|
|
|
method(ObjectRef, setvelocity),
|
2012-01-02 15:19:52 +01:00
|
|
|
method(ObjectRef, getvelocity),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(ObjectRef, setacceleration),
|
|
|
|
method(ObjectRef, getacceleration),
|
2012-01-02 15:19:52 +01:00
|
|
|
method(ObjectRef, setyaw),
|
|
|
|
method(ObjectRef, getyaw),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(ObjectRef, settexturemod),
|
|
|
|
method(ObjectRef, setsprite),
|
2012-01-02 12:12:56 +01:00
|
|
|
method(ObjectRef, get_entity_name),
|
2012-01-02 15:08:59 +01:00
|
|
|
method(ObjectRef, get_luaentity),
|
2011-12-06 14:55:05 +01:00
|
|
|
// Player-only
|
2012-06-18 23:50:07 +02:00
|
|
|
method(ObjectRef, is_player),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(ObjectRef, get_player_name),
|
|
|
|
method(ObjectRef, get_look_dir),
|
|
|
|
method(ObjectRef, get_look_pitch),
|
|
|
|
method(ObjectRef, get_look_yaw),
|
2012-07-19 13:09:16 +02:00
|
|
|
method(ObjectRef, set_inventory_formspec),
|
|
|
|
method(ObjectRef, get_inventory_formspec),
|
2012-11-22 20:01:31 +01:00
|
|
|
method(ObjectRef, get_player_control),
|
|
|
|
method(ObjectRef, get_player_control_bits),
|
2011-11-28 02:06:21 +01:00
|
|
|
{0,0}
|
|
|
|
};
|
|
|
|
|
2012-06-05 22:09:18 +02:00
|
|
|
// Creates a new anonymous reference if cobj=NULL or id=0
|
2011-12-06 14:55:05 +01:00
|
|
|
static void objectref_get_or_create(lua_State *L,
|
|
|
|
ServerActiveObject *cobj)
|
|
|
|
{
|
2012-06-05 22:09:18 +02:00
|
|
|
if(cobj == NULL || cobj->getId() == 0){
|
2011-12-06 14:55:05 +01:00
|
|
|
ObjectRef::create(L, cobj);
|
|
|
|
} else {
|
|
|
|
objectref_get(L, cobj->getId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-31 21:52:25 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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}
|
|
|
|
};
|
|
|
|
|
2012-07-17 15:00:04 +02:00
|
|
|
/*
|
|
|
|
NodeTimerRef
|
|
|
|
*/
|
|
|
|
|
|
|
|
class NodeTimerRef
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
v3s16 m_p;
|
|
|
|
ServerEnvironment *m_env;
|
|
|
|
|
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
|
|
|
|
|
|
|
static int gc_object(lua_State *L) {
|
|
|
|
NodeTimerRef *o = *(NodeTimerRef **)(lua_touserdata(L, 1));
|
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NodeTimerRef *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 *(NodeTimerRef**)ud; // unbox pointer
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_set(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
f32 t = luaL_checknumber(L,2);
|
|
|
|
f32 e = luaL_checknumber(L,3);
|
|
|
|
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_start(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
f32 t = luaL_checknumber(L,2);
|
|
|
|
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_stop(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
env->getMap().removeNodeTimer(o->m_p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_is_started(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
|
|
|
|
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
|
|
|
|
lua_pushboolean(L,(t.timeout != 0));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_get_timeout(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
|
|
|
|
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
|
|
|
|
lua_pushnumber(L,t.timeout);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_get_elapsed(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
|
|
|
|
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
|
|
|
|
lua_pushnumber(L,t.elapsed);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
NodeTimerRef(v3s16 p, ServerEnvironment *env):
|
|
|
|
m_p(p),
|
|
|
|
m_env(env)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~NodeTimerRef()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates an NodeTimerRef 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)
|
|
|
|
{
|
|
|
|
NodeTimerRef *o = new NodeTimerRef(p, env);
|
|
|
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
|
|
|
luaL_getmetatable(L, className);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_null(lua_State *L)
|
|
|
|
{
|
|
|
|
NodeTimerRef *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 NodeTimerRef::className[] = "NodeTimerRef";
|
|
|
|
const luaL_reg NodeTimerRef::methods[] = {
|
|
|
|
method(NodeTimerRef, start),
|
|
|
|
method(NodeTimerRef, set),
|
|
|
|
method(NodeTimerRef, stop),
|
|
|
|
method(NodeTimerRef, is_started),
|
|
|
|
method(NodeTimerRef, get_timeout),
|
|
|
|
method(NodeTimerRef, get_elapsed),
|
|
|
|
{0,0}
|
|
|
|
};
|
|
|
|
|
2011-11-28 02:06:21 +01:00
|
|
|
/*
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef
|
2011-11-28 02:06:21 +01:00
|
|
|
*/
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
class EnvRef
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
private:
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerEnvironment *m_env;
|
2011-11-11 18:33:17 +01:00
|
|
|
|
|
|
|
static const char className[];
|
|
|
|
static const luaL_reg methods[];
|
|
|
|
|
2012-04-06 21:44:42 +02:00
|
|
|
static int gc_object(lua_State *L) {
|
|
|
|
EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
|
|
|
|
delete o;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static EnvRef *checkobject(lua_State *L, int narg)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
luaL_checktype(L, narg, LUA_TUSERDATA);
|
|
|
|
void *ud = luaL_checkudata(L, narg, className);
|
|
|
|
if(!ud) luaL_typerror(L, narg, className);
|
2011-12-06 14:55:05 +01:00
|
|
|
return *(EnvRef**)ud; // unbox pointer
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
|
2011-11-11 18:33:17 +01:00
|
|
|
// Exported functions
|
2011-11-12 16:37:14 +01:00
|
|
|
|
2012-03-28 21:50:08 +02:00
|
|
|
// EnvRef:set_node(pos, node)
|
2011-12-06 14:55:05 +01:00
|
|
|
// pos = {x=num, y=num, z=num}
|
2012-03-28 21:50:08 +02:00
|
|
|
static int l_set_node(lua_State *L)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2012-06-05 22:51:37 +02:00
|
|
|
INodeDefManager *ndef = env->getGameDef()->ndef();
|
|
|
|
// parameters
|
2011-12-06 14:55:05 +01:00
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
2012-06-05 22:51:37 +02:00
|
|
|
MapNode n = readnode(L, 3, ndef);
|
2011-12-06 14:55:05 +01:00
|
|
|
// Do it
|
2012-06-01 16:24:54 +02:00
|
|
|
MapNode n_old = env->getMap().getNodeNoEx(pos);
|
2012-06-05 22:51:37 +02:00
|
|
|
// Call destructor
|
|
|
|
if(ndef->get(n_old).has_on_destruct)
|
|
|
|
scriptapi_node_on_destruct(L, pos, n_old);
|
2012-06-01 16:24:54 +02:00
|
|
|
// Replace node
|
2011-12-06 14:55:05 +01:00
|
|
|
bool succeeded = env->getMap().addNodeWithEvent(pos, n);
|
2012-06-05 22:51:37 +02:00
|
|
|
if(succeeded){
|
|
|
|
// Call post-destructor
|
|
|
|
if(ndef->get(n_old).has_after_destruct)
|
|
|
|
scriptapi_node_after_destruct(L, pos, n_old);
|
|
|
|
// Call constructor
|
|
|
|
if(ndef->get(n).has_on_construct)
|
|
|
|
scriptapi_node_on_construct(L, pos, n);
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushboolean(L, succeeded);
|
|
|
|
return 1;
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-03-28 21:50:08 +02:00
|
|
|
static int l_add_node(lua_State *L)
|
|
|
|
{
|
|
|
|
return l_set_node(L);
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:remove_node(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_remove_node(lua_State *L)
|
2011-11-12 01:25:30 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2012-06-05 22:51:37 +02:00
|
|
|
INodeDefManager *ndef = env->getGameDef()->ndef();
|
|
|
|
// parameters
|
2011-12-06 14:55:05 +01:00
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
|
|
|
// Do it
|
2012-06-05 22:51:37 +02:00
|
|
|
MapNode n_old = env->getMap().getNodeNoEx(pos);
|
2012-06-01 16:24:54 +02:00
|
|
|
// Call destructor
|
2012-06-05 22:51:37 +02:00
|
|
|
if(ndef->get(n_old).has_on_destruct)
|
|
|
|
scriptapi_node_on_destruct(L, pos, n_old);
|
2012-06-01 16:24:54 +02:00
|
|
|
// Replace with air
|
2012-06-05 22:09:18 +02:00
|
|
|
// This is slightly optimized compared to addNodeWithEvent(air)
|
2011-12-06 14:55:05 +01:00
|
|
|
bool succeeded = env->getMap().removeNodeWithEvent(pos);
|
2012-06-05 22:51:37 +02:00
|
|
|
if(succeeded){
|
|
|
|
// Call post-destructor
|
|
|
|
if(ndef->get(n_old).has_after_destruct)
|
|
|
|
scriptapi_node_after_destruct(L, pos, n_old);
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushboolean(L, succeeded);
|
2012-06-01 16:24:54 +02:00
|
|
|
// Air doesn't require constructor
|
2011-11-12 01:25:30 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// EnvRef:get_node(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_get_node(lua_State *L)
|
2011-11-12 10:59:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2011-11-12 10:59:56 +01:00
|
|
|
// pos
|
2011-12-06 14:55:05 +01:00
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
2011-11-12 10:59:56 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
MapNode n = env->getMap().getNodeNoEx(pos);
|
|
|
|
// Return node
|
|
|
|
pushnode(L, n, env->getGameDef()->ndef());
|
|
|
|
return 1;
|
2011-11-12 10:59:56 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// EnvRef:get_node_or_nil(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_get_node_or_nil(lua_State *L)
|
2011-11-12 10:59:56 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2011-11-12 10:59:56 +01:00
|
|
|
// pos
|
2011-12-06 14:55:05 +01:00
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
2011-11-12 10:59:56 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
try{
|
|
|
|
MapNode n = env->getMap().getNode(pos);
|
|
|
|
// Return node
|
|
|
|
pushnode(L, n, env->getGameDef()->ndef());
|
|
|
|
return 1;
|
|
|
|
} catch(InvalidPositionException &e)
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-12 10:59:56 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:get_node_light(pos, timeofday)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
// timeofday: nil = current time, 0 = night, 0.5 = day
|
|
|
|
static int l_get_node_light(lua_State *L)
|
2011-11-30 19:54:54 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2011-11-30 19:54:54 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
|
|
|
u32 time_of_day = env->getTimeOfDay();
|
|
|
|
if(lua_isnumber(L, 3))
|
|
|
|
time_of_day = 24000.0 * lua_tonumber(L, 3);
|
|
|
|
time_of_day %= 24000;
|
2012-12-02 17:02:04 +01:00
|
|
|
u32 dnr = time_to_daynight_ratio(time_of_day, true);
|
2011-12-06 14:55:05 +01:00
|
|
|
MapNode n = env->getMap().getNodeNoEx(pos);
|
|
|
|
try{
|
|
|
|
MapNode n = env->getMap().getNode(pos);
|
|
|
|
INodeDefManager *ndef = env->getGameDef()->ndef();
|
|
|
|
lua_pushinteger(L, n.getLightBlend(dnr, ndef));
|
|
|
|
return 1;
|
|
|
|
} catch(InvalidPositionException &e)
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-30 19:54:54 +01:00
|
|
|
}
|
|
|
|
|
2012-06-05 22:09:18 +02:00
|
|
|
// EnvRef:place_node(pos, node)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_place_node(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
|
|
|
MapNode n = readnode(L, 3, env->getGameDef()->ndef());
|
|
|
|
|
|
|
|
// Don't attempt to load non-loaded area as of now
|
|
|
|
MapNode n_old = env->getMap().getNodeNoEx(pos);
|
|
|
|
if(n_old.getContent() == CONTENT_IGNORE){
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Create item to place
|
|
|
|
INodeDefManager *ndef = get_server(L)->ndef();
|
|
|
|
IItemDefManager *idef = get_server(L)->idef();
|
|
|
|
ItemStack item(ndef->get(n).name, 1, 0, "", idef);
|
|
|
|
// Make pointed position
|
|
|
|
PointedThing pointed;
|
|
|
|
pointed.type = POINTEDTHING_NODE;
|
|
|
|
pointed.node_abovesurface = pos;
|
|
|
|
pointed.node_undersurface = pos + v3s16(0,-1,0);
|
|
|
|
// Place it with a NULL placer (appears in Lua as a non-functional
|
|
|
|
// ObjectRef)
|
|
|
|
bool success = scriptapi_item_on_place(L, item, NULL, pointed);
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnvRef:dig_node(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_dig_node(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
|
|
|
|
|
|
|
// Don't attempt to load non-loaded area as of now
|
|
|
|
MapNode n = env->getMap().getNodeNoEx(pos);
|
|
|
|
if(n.getContent() == CONTENT_IGNORE){
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Dig it out with a NULL digger (appears in Lua as a
|
|
|
|
// non-functional ObjectRef)
|
|
|
|
bool success = scriptapi_node_on_dig(L, pos, n, NULL);
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnvRef:punch_node(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_punch_node(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
v3s16 pos = read_v3s16(L, 2);
|
|
|
|
|
|
|
|
// Don't attempt to load non-loaded area as of now
|
|
|
|
MapNode n = env->getMap().getNodeNoEx(pos);
|
|
|
|
if(n.getContent() == CONTENT_IGNORE){
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Punch it with a NULL puncher (appears in Lua as a non-functional
|
|
|
|
// ObjectRef)
|
|
|
|
bool success = scriptapi_node_on_punch(L, pos, n, NULL);
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-07-17 15:00:04 +02:00
|
|
|
// 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 = read_v3s16(L, 2);
|
|
|
|
NodeMetaRef::create(L, p, env);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnvRef:get_node_timer(pos)
|
|
|
|
static int l_get_node_timer(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
v3s16 p = read_v3s16(L, 2);
|
|
|
|
NodeTimerRef::create(L, p, env);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
|
2011-12-06 14:55:05 +01:00
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_add_entity(lua_State *L)
|
2011-11-30 19:54:54 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
//infostream<<"EnvRef::l_add_entity()"<<std::endl;
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// pos
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
|
|
|
// content
|
|
|
|
const char *name = luaL_checkstring(L, 3);
|
2011-11-30 19:54:54 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
|
2012-01-02 11:48:25 +01:00
|
|
|
int objectid = env->addActiveObject(obj);
|
|
|
|
// If failed to add, return nothing (reads as nil)
|
|
|
|
if(objectid == 0)
|
|
|
|
return 0;
|
|
|
|
// Return ObjectRef
|
|
|
|
objectref_get_or_create(L, obj);
|
|
|
|
return 1;
|
2011-11-30 19:54:54 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
|
2011-12-06 14:55:05 +01:00
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_add_item(lua_State *L)
|
2011-11-21 10:15:15 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
//infostream<<"EnvRef::l_add_item()"<<std::endl;
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// pos
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
2012-01-12 06:10:39 +01:00
|
|
|
// item
|
|
|
|
ItemStack item = read_item(L, 3);
|
|
|
|
if(item.empty() || !item.isKnown(get_server(L)->idef()))
|
|
|
|
return 0;
|
2012-04-01 15:06:01 +02:00
|
|
|
// 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
|
2012-03-04 20:08:03 +01:00
|
|
|
ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
|
2012-01-12 06:10:39 +01:00
|
|
|
int objectid = env->addActiveObject(obj);
|
|
|
|
// If failed to add, return nothing (reads as nil)
|
|
|
|
if(objectid == 0)
|
|
|
|
return 0;
|
|
|
|
// Return ObjectRef
|
|
|
|
objectref_get_or_create(L, obj);
|
2012-04-01 15:06:01 +02:00
|
|
|
return 1;*/
|
2011-11-21 10:15:15 +01:00
|
|
|
}
|
2011-11-30 19:36:07 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:add_rat(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_add_rat(lua_State *L)
|
2011-11-27 03:31:05 +01:00
|
|
|
{
|
2012-03-04 20:08:03 +01:00
|
|
|
infostream<<"EnvRef::l_add_rat(): C++ mobs have been removed."
|
|
|
|
<<" Doing nothing."<<std::endl;
|
2011-11-30 19:36:07 +01:00
|
|
|
return 0;
|
2011-11-27 03:31:05 +01:00
|
|
|
}
|
2011-11-30 19:36:07 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:add_firefly(pos)
|
|
|
|
// pos = {x=num, y=num, z=num}
|
|
|
|
static int l_add_firefly(lua_State *L)
|
2011-11-12 16:37:14 +01:00
|
|
|
{
|
2012-03-04 20:08:03 +01:00
|
|
|
infostream<<"EnvRef::l_add_firefly(): C++ mobs have been removed."
|
|
|
|
<<" Doing nothing."<<std::endl;
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0;
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:get_player_by_name(name)
|
|
|
|
static int l_get_player_by_name(lua_State *L)
|
2011-11-30 19:36:07 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
2011-11-30 19:36:07 +01:00
|
|
|
// Do it
|
2011-12-06 14:55:05 +01:00
|
|
|
const char *name = luaL_checkstring(L, 2);
|
2012-03-19 03:04:16 +01:00
|
|
|
Player *player = env->getPlayer(name);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(player == NULL){
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
2012-03-19 03:04:16 +01:00
|
|
|
PlayerSAO *sao = player->getPlayerSAO();
|
|
|
|
if(sao == NULL){
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
// Put player on stack
|
2012-03-19 03:04:16 +01:00
|
|
|
objectref_get_or_create(L, sao);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
2011-11-30 19:36:07 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// EnvRef:get_objects_inside_radius(pos, radius)
|
|
|
|
static int l_get_objects_inside_radius(lua_State *L)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
// Get the table insert function
|
|
|
|
lua_getglobal(L, "table");
|
|
|
|
lua_getfield(L, -1, "insert");
|
|
|
|
int table_insert = lua_gettop(L);
|
|
|
|
// Get environemnt
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
v3f pos = checkFloatPos(L, 2);
|
|
|
|
float radius = luaL_checknumber(L, 3) * BS;
|
|
|
|
std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
|
|
|
|
lua_newtable(L);
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
for(std::set<u16>::const_iterator
|
|
|
|
i = ids.begin(); i != ids.end(); i++){
|
|
|
|
ServerActiveObject *obj = env->getActiveObject(*i);
|
|
|
|
// Insert object reference into table
|
|
|
|
lua_pushvalue(L, table_insert);
|
|
|
|
lua_pushvalue(L, table);
|
|
|
|
objectref_get_or_create(L, obj);
|
|
|
|
if(lua_pcall(L, 2, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-24 11:01:59 +01:00
|
|
|
// EnvRef:set_timeofday(val)
|
|
|
|
// val = 0...1
|
|
|
|
static int l_set_timeofday(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
float timeofday_f = luaL_checknumber(L, 2);
|
|
|
|
assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
|
|
|
|
int timeofday_mh = (int)(timeofday_f * 24000.0);
|
|
|
|
// This should be set directly in the environment but currently
|
|
|
|
// such changes aren't immediately sent to the clients, so call
|
|
|
|
// the server instead.
|
|
|
|
//env->setTimeOfDay(timeofday_mh);
|
|
|
|
get_server(L)->setTimeOfDay(timeofday_mh);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnvRef:get_timeofday() -> 0...1
|
|
|
|
static int l_get_timeofday(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
// Do it
|
|
|
|
int timeofday_mh = env->getTimeOfDay();
|
|
|
|
float timeofday_f = (float)timeofday_mh / 24000.0;
|
|
|
|
lua_pushnumber(L, timeofday_f);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-31 21:52:25 +02:00
|
|
|
|
2012-04-06 21:44:42 +02:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-04-08 13:37:12 +02:00
|
|
|
// 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 = 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;
|
|
|
|
}
|
|
|
|
|
2012-03-31 21:52:25 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-07-28 21:27:31 +02:00
|
|
|
// EnvRef:clear_objects()
|
|
|
|
// clear all objects in the environment
|
|
|
|
static int l_clear_objects(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
o->m_env->clearAllObjects();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-29 16:20:09 +01:00
|
|
|
static int l_spawn_tree(lua_State *L)
|
|
|
|
{
|
|
|
|
EnvRef *o = checkobject(L, 1);
|
|
|
|
ServerEnvironment *env = o->m_env;
|
|
|
|
if(env == NULL) return 0;
|
|
|
|
v3s16 p0 = read_v3s16(L, 2);
|
|
|
|
|
|
|
|
treegen::TreeDef tree_def;
|
|
|
|
std::string trunk,leaves,fruit;
|
|
|
|
INodeDefManager *ndef = env->getGameDef()->ndef();
|
|
|
|
|
|
|
|
if(lua_istable(L, 3))
|
|
|
|
{
|
|
|
|
getstringfield(L, 3, "axiom", tree_def.initial_axiom);
|
|
|
|
getstringfield(L, 3, "rules_a", tree_def.rules_a);
|
|
|
|
getstringfield(L, 3, "rules_b", tree_def.rules_b);
|
|
|
|
getstringfield(L, 3, "rules_c", tree_def.rules_a);
|
|
|
|
getstringfield(L, 3, "rules_d", tree_def.rules_b);
|
|
|
|
getstringfield(L, 3, "trunk", trunk);
|
|
|
|
tree_def.trunknode=ndef->getId(trunk);
|
|
|
|
getstringfield(L, 3, "leaves", leaves);
|
|
|
|
tree_def.leavesnode=ndef->getId(leaves);
|
|
|
|
getintfield(L, 3, "angle", tree_def.angle);
|
|
|
|
getintfield(L, 3, "iterations", tree_def.iterations);
|
|
|
|
getintfield(L, 3, "random_level", tree_def.iterations_random_level);
|
|
|
|
getboolfield(L, 3, "thin_trunks", tree_def.thin_trunks);
|
|
|
|
getboolfield(L, 3, "fruit_tree", tree_def.fruit_tree);
|
|
|
|
if (tree_def.fruit_tree)
|
|
|
|
{
|
|
|
|
getstringfield(L, 3, "fruit", fruit);
|
|
|
|
tree_def.fruitnode=ndef->getId(fruit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
treegen::spawn_ltree (env, p0, ndef, tree_def);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
public:
|
|
|
|
EnvRef(ServerEnvironment *env):
|
|
|
|
m_env(env)
|
2011-11-30 19:36:07 +01:00
|
|
|
{
|
2012-03-11 03:15:45 +01:00
|
|
|
//infostream<<"EnvRef created"<<std::endl;
|
2011-11-30 19:36:07 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
~EnvRef()
|
2011-11-30 19:36:07 +01:00
|
|
|
{
|
2012-03-11 03:15:45 +01:00
|
|
|
//infostream<<"EnvRef destructing"<<std::endl;
|
2011-11-30 19:36:07 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
// 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)
|
2011-11-26 11:35:30 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
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);
|
2011-11-26 11:35:30 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
static void set_null(lua_State *L)
|
2011-11-27 03:31:05 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
EnvRef *o = checkobject(L, -1);
|
|
|
|
o->m_env = NULL;
|
2011-11-27 03:31:05 +01:00
|
|
|
}
|
2011-11-30 22:38:18 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static void Register(lua_State *L)
|
2011-11-30 22:38:18 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
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);
|
2011-11-30 22:38:18 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
};
|
|
|
|
const char EnvRef::className[] = "EnvRef";
|
|
|
|
const luaL_reg EnvRef::methods[] = {
|
2012-03-28 21:50:08 +02:00
|
|
|
method(EnvRef, set_node),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(EnvRef, add_node),
|
|
|
|
method(EnvRef, remove_node),
|
|
|
|
method(EnvRef, get_node),
|
|
|
|
method(EnvRef, get_node_or_nil),
|
|
|
|
method(EnvRef, get_node_light),
|
2012-06-05 22:09:18 +02:00
|
|
|
method(EnvRef, place_node),
|
|
|
|
method(EnvRef, dig_node),
|
|
|
|
method(EnvRef, punch_node),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(EnvRef, add_entity),
|
|
|
|
method(EnvRef, add_item),
|
|
|
|
method(EnvRef, add_rat),
|
|
|
|
method(EnvRef, add_firefly),
|
|
|
|
method(EnvRef, get_meta),
|
2012-07-17 15:00:04 +02:00
|
|
|
method(EnvRef, get_node_timer),
|
2011-12-06 14:55:05 +01:00
|
|
|
method(EnvRef, get_player_by_name),
|
|
|
|
method(EnvRef, get_objects_inside_radius),
|
2012-01-24 11:01:59 +01:00
|
|
|
method(EnvRef, set_timeofday),
|
|
|
|
method(EnvRef, get_timeofday),
|
2012-04-06 21:44:42 +02:00
|
|
|
method(EnvRef, find_node_near),
|
2012-04-08 13:37:12 +02:00
|
|
|
method(EnvRef, find_nodes_in_area),
|
2012-03-31 21:52:25 +02:00
|
|
|
method(EnvRef, get_perlin),
|
2012-07-28 21:27:31 +02:00
|
|
|
method(EnvRef, clear_objects),
|
2012-12-29 16:20:09 +01:00
|
|
|
method(EnvRef, spawn_tree),
|
2011-12-06 14:55:05 +01:00
|
|
|
{0,0}
|
|
|
|
};
|
|
|
|
|
2012-03-27 23:38:20 +02:00
|
|
|
/*
|
|
|
|
LuaPseudoRandom
|
|
|
|
*/
|
|
|
|
|
2012-03-31 21:52:25 +02:00
|
|
|
|
2012-03-27 23:38:20 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-03-28 20:16:47 +02:00
|
|
|
// next(self, min=0, max=32767) -> get next value
|
2012-03-27 23:38:20 +02:00
|
|
|
static int l_next(lua_State *L)
|
|
|
|
{
|
|
|
|
LuaPseudoRandom *o = checkobject(L, 1);
|
2012-03-28 20:16:47 +02:00
|
|
|
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);
|
2012-07-27 18:03:15 +02:00
|
|
|
if(max < min){
|
|
|
|
errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
|
|
|
|
throw LuaError(L, "PseudoRandom.next(): max < min");
|
|
|
|
}
|
2012-03-28 20:16:47 +02:00
|
|
|
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.");
|
2012-03-27 23:38:20 +02:00
|
|
|
PseudoRandom &pseudo = o->m_pseudo;
|
2012-03-28 20:16:47 +02:00
|
|
|
int val = pseudo.next();
|
|
|
|
val = (val % (max-min+1)) + min;
|
|
|
|
lua_pushinteger(L, val);
|
2012-03-27 23:38:20 +02:00
|
|
|
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}
|
|
|
|
};
|
|
|
|
|
2012-03-31 21:52:25 +02:00
|
|
|
|
|
|
|
|
2012-03-27 23:38:20 +02:00
|
|
|
/*
|
|
|
|
LuaABM
|
|
|
|
*/
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
class LuaABM : public ActiveBlockModifier
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
lua_State *m_lua;
|
|
|
|
int m_id;
|
|
|
|
|
|
|
|
std::set<std::string> m_trigger_contents;
|
|
|
|
std::set<std::string> m_required_neighbors;
|
|
|
|
float m_trigger_interval;
|
|
|
|
u32 m_trigger_chance;
|
|
|
|
public:
|
|
|
|
LuaABM(lua_State *L, int id,
|
|
|
|
const std::set<std::string> &trigger_contents,
|
|
|
|
const std::set<std::string> &required_neighbors,
|
|
|
|
float trigger_interval, u32 trigger_chance):
|
|
|
|
m_lua(L),
|
|
|
|
m_id(id),
|
|
|
|
m_trigger_contents(trigger_contents),
|
|
|
|
m_required_neighbors(required_neighbors),
|
|
|
|
m_trigger_interval(trigger_interval),
|
|
|
|
m_trigger_chance(trigger_chance)
|
2011-11-30 22:38:18 +01:00
|
|
|
{
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
virtual std::set<std::string> getTriggerContents()
|
2011-11-30 22:38:18 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
return m_trigger_contents;
|
2011-11-30 22:38:18 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
virtual std::set<std::string> getRequiredNeighbors()
|
2011-12-01 22:33:48 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
return m_required_neighbors;
|
2011-12-01 22:33:48 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
virtual float getTriggerInterval()
|
2011-12-01 22:33:48 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
return m_trigger_interval;
|
2011-12-01 22:33:48 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
virtual u32 getTriggerChance()
|
2011-12-28 16:34:07 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
return m_trigger_chance;
|
2011-12-28 16:34:07 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
|
|
|
|
u32 active_object_count, u32 active_object_count_wider)
|
|
|
|
{
|
|
|
|
lua_State *L = m_lua;
|
|
|
|
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.registered_abms
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_abms");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
int registered_abms = lua_gettop(L);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Get minetest.registered_abms[m_id]
|
|
|
|
lua_pushnumber(L, m_id);
|
|
|
|
lua_gettable(L, registered_abms);
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
assert(0);
|
|
|
|
|
|
|
|
// Call action
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_getfield(L, -1, "action");
|
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
push_v3s16(L, p);
|
|
|
|
pushnode(L, n, env->getGameDef()->ndef());
|
|
|
|
lua_pushnumber(L, active_object_count);
|
|
|
|
lua_pushnumber(L, active_object_count_wider);
|
|
|
|
if(lua_pcall(L, 4, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
};
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-03-24 18:01:26 +01:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// debug(text)
|
|
|
|
// Writes a line to dstream
|
|
|
|
static int l_debug(lua_State *L)
|
|
|
|
{
|
|
|
|
std::string text = lua_tostring(L, 1);
|
|
|
|
dstream << text << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// log([level,] text)
|
|
|
|
// Writes a line to the logger.
|
|
|
|
// The one-argument version logs to infostream.
|
|
|
|
// The two-argument version accept a log level: error, action, info, or verbose.
|
|
|
|
static int l_log(lua_State *L)
|
|
|
|
{
|
|
|
|
std::string text;
|
|
|
|
LogMessageLevel level = LMT_INFO;
|
|
|
|
if(lua_isnone(L, 2))
|
|
|
|
{
|
|
|
|
text = lua_tostring(L, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string levelname = lua_tostring(L, 1);
|
|
|
|
text = lua_tostring(L, 2);
|
|
|
|
if(levelname == "error")
|
|
|
|
level = LMT_ERROR;
|
|
|
|
else if(levelname == "action")
|
|
|
|
level = LMT_ACTION;
|
|
|
|
else if(levelname == "verbose")
|
|
|
|
level = LMT_VERBOSE;
|
|
|
|
}
|
|
|
|
log_printline(level, text);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-07-28 21:27:31 +02:00
|
|
|
// request_shutdown()
|
|
|
|
static int l_request_shutdown(lua_State *L)
|
|
|
|
{
|
|
|
|
get_server(L)->requestShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_server_status()
|
|
|
|
static int l_get_server_status(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_pushstring(L, wide_to_narrow(get_server(L)->getStatusString()).c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// register_item_raw({lots of stuff})
|
|
|
|
static int l_register_item_raw(lua_State *L)
|
|
|
|
{
|
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
|
|
int table = 1;
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Get the writable item and node definition managers from the server
|
|
|
|
IWritableItemDefManager *idef =
|
|
|
|
get_server(L)->getWritableItemDefManager();
|
|
|
|
IWritableNodeDefManager *ndef =
|
|
|
|
get_server(L)->getWritableNodeDefManager();
|
|
|
|
|
|
|
|
// Check if name is defined
|
2012-06-10 11:46:48 +02:00
|
|
|
std::string name;
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_getfield(L, table, "name");
|
|
|
|
if(lua_isstring(L, -1)){
|
2012-06-10 11:46:48 +02:00
|
|
|
name = lua_tostring(L, -1);
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"register_item_raw: "<<name<<std::endl;
|
2012-01-12 06:10:39 +01:00
|
|
|
} else {
|
|
|
|
throw LuaError(L, "register_item_raw: name is not defined or not a string");
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Check if on_use is defined
|
|
|
|
|
2012-06-10 11:46:48 +02:00
|
|
|
ItemDefinition def;
|
|
|
|
// Set a distinctive default value to check if this is set
|
|
|
|
def.node_placement_prediction = "__default";
|
|
|
|
|
|
|
|
// Read the item definition
|
|
|
|
def = read_item_definition(L, table, def);
|
|
|
|
|
|
|
|
// Default to having client-side placement prediction for nodes
|
|
|
|
// ("" in item definition sets it off)
|
2012-06-16 21:45:35 +02:00
|
|
|
if(def.node_placement_prediction == "__default"){
|
|
|
|
if(def.type == ITEM_NODE)
|
|
|
|
def.node_placement_prediction = name;
|
|
|
|
else
|
|
|
|
def.node_placement_prediction = "";
|
2012-06-10 11:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register item definition
|
2012-01-12 06:10:39 +01:00
|
|
|
idef->registerItem(def);
|
|
|
|
|
|
|
|
// Read the node definition (content features) and register it
|
|
|
|
if(def.type == ITEM_NODE)
|
|
|
|
{
|
|
|
|
ContentFeatures f = read_content_features(L, table);
|
|
|
|
ndef->set(f.name, f);
|
2011-11-12 16:37:14 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0; /* number of results */
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// register_alias_raw(name, convert_to_name)
|
|
|
|
static int l_register_alias_raw(lua_State *L)
|
2011-11-29 20:30:22 +01:00
|
|
|
{
|
2011-12-06 14:55:05 +01:00
|
|
|
std::string name = luaL_checkstring(L, 1);
|
|
|
|
std::string convert_to = luaL_checkstring(L, 2);
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Get the writable item definition manager from the server
|
|
|
|
IWritableItemDefManager *idef =
|
|
|
|
get_server(L)->getWritableItemDefManager();
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
idef->registerAlias(name, convert_to);
|
2011-12-06 14:55:05 +01:00
|
|
|
|
|
|
|
return 0; /* number of results */
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// helper for register_craft
|
|
|
|
static bool read_craft_recipe_shaped(lua_State *L, int index,
|
|
|
|
int &width, std::vector<std::string> &recipe)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
2011-12-06 14:55:05 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
if(!lua_istable(L, index))
|
|
|
|
return false;
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
int rowcount = 0;
|
|
|
|
while(lua_next(L, index) != 0){
|
|
|
|
int colcount = 0;
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
if(!lua_istable(L, -1))
|
|
|
|
return false;
|
|
|
|
int table2 = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table2) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
if(!lua_isstring(L, -1))
|
|
|
|
return false;
|
|
|
|
recipe.push_back(lua_tostring(L, -1));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
colcount++;
|
|
|
|
}
|
|
|
|
if(rowcount == 0){
|
|
|
|
width = colcount;
|
|
|
|
} else {
|
|
|
|
if(colcount != width)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
rowcount++;
|
|
|
|
}
|
|
|
|
return width != 0;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// helper for register_craft
|
|
|
|
static bool read_craft_recipe_shapeless(lua_State *L, int index,
|
|
|
|
std::vector<std::string> &recipe)
|
2011-12-06 14:55:05 +01:00
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
if(!lua_istable(L, index))
|
|
|
|
return false;
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, index) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
if(!lua_isstring(L, -1))
|
|
|
|
return false;
|
|
|
|
recipe.push_back(lua_tostring(L, -1));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return true;
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2011-12-03 17:37:50 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// helper for register_craft
|
|
|
|
static bool read_craft_replacements(lua_State *L, int index,
|
|
|
|
CraftReplacements &replacements)
|
|
|
|
{
|
|
|
|
if(index < 0)
|
|
|
|
index = lua_gettop(L) + 1 + index;
|
|
|
|
|
|
|
|
if(!lua_istable(L, index))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, index) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
if(!lua_istable(L, -1))
|
|
|
|
return false;
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
if(!lua_isstring(L, -1))
|
|
|
|
return false;
|
|
|
|
std::string replace_from = lua_tostring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_rawgeti(L, -1, 2);
|
|
|
|
if(!lua_isstring(L, -1))
|
|
|
|
return false;
|
|
|
|
std::string replace_to = lua_tostring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
replacements.pairs.push_back(
|
|
|
|
std::make_pair(replace_from, replace_to));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
|
|
|
|
static int l_register_craft(lua_State *L)
|
|
|
|
{
|
|
|
|
//infostream<<"register_craft"<<std::endl;
|
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
2012-01-12 06:10:39 +01:00
|
|
|
int table = 1;
|
2011-12-04 14:55:37 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// Get the writable craft definition manager from the server
|
|
|
|
IWritableCraftDefManager *craftdef =
|
|
|
|
get_server(L)->getWritableCraftDefManager();
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
std::string type = getstringfield_default(L, table, "type", "shaped");
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
CraftDefinitionShaped
|
|
|
|
*/
|
|
|
|
if(type == "shaped"){
|
|
|
|
std::string output = getstringfield_default(L, table, "output", "");
|
|
|
|
if(output == "")
|
|
|
|
throw LuaError(L, "Crafting definition is missing an output");
|
|
|
|
|
|
|
|
int width = 0;
|
|
|
|
std::vector<std::string> recipe;
|
|
|
|
lua_getfield(L, table, "recipe");
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
throw LuaError(L, "Crafting definition is missing a recipe"
|
|
|
|
" (output=\"" + output + "\")");
|
|
|
|
if(!read_craft_recipe_shaped(L, -1, width, recipe))
|
|
|
|
throw LuaError(L, "Invalid crafting recipe"
|
|
|
|
" (output=\"" + output + "\")");
|
|
|
|
|
|
|
|
CraftReplacements replacements;
|
|
|
|
lua_getfield(L, table, "replacements");
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
if(!read_craft_replacements(L, -1, replacements))
|
|
|
|
throw LuaError(L, "Invalid replacements"
|
|
|
|
" (output=\"" + output + "\")");
|
2011-12-06 14:55:05 +01:00
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
CraftDefinition *def = new CraftDefinitionShaped(
|
|
|
|
output, width, recipe, replacements);
|
|
|
|
craftdef->registerCraft(def);
|
2011-11-29 20:30:22 +01:00
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
CraftDefinitionShapeless
|
|
|
|
*/
|
|
|
|
else if(type == "shapeless"){
|
|
|
|
std::string output = getstringfield_default(L, table, "output", "");
|
|
|
|
if(output == "")
|
|
|
|
throw LuaError(L, "Crafting definition (shapeless)"
|
|
|
|
" is missing an output");
|
|
|
|
|
|
|
|
std::vector<std::string> recipe;
|
|
|
|
lua_getfield(L, table, "recipe");
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
throw LuaError(L, "Crafting definition (shapeless)"
|
|
|
|
" is missing a recipe"
|
|
|
|
" (output=\"" + output + "\")");
|
|
|
|
if(!read_craft_recipe_shapeless(L, -1, recipe))
|
|
|
|
throw LuaError(L, "Invalid crafting recipe"
|
|
|
|
" (output=\"" + output + "\")");
|
|
|
|
|
|
|
|
CraftReplacements replacements;
|
|
|
|
lua_getfield(L, table, "replacements");
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
if(!read_craft_replacements(L, -1, replacements))
|
|
|
|
throw LuaError(L, "Invalid replacements"
|
|
|
|
" (output=\"" + output + "\")");
|
|
|
|
}
|
|
|
|
|
|
|
|
CraftDefinition *def = new CraftDefinitionShapeless(
|
|
|
|
output, recipe, replacements);
|
|
|
|
craftdef->registerCraft(def);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
CraftDefinitionToolRepair
|
|
|
|
*/
|
|
|
|
else if(type == "toolrepair"){
|
|
|
|
float additional_wear = getfloatfield_default(L, table,
|
|
|
|
"additional_wear", 0.0);
|
|
|
|
|
|
|
|
CraftDefinition *def = new CraftDefinitionToolRepair(
|
|
|
|
additional_wear);
|
|
|
|
craftdef->registerCraft(def);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
CraftDefinitionCooking
|
|
|
|
*/
|
|
|
|
else if(type == "cooking"){
|
|
|
|
std::string output = getstringfield_default(L, table, "output", "");
|
|
|
|
if(output == "")
|
|
|
|
throw LuaError(L, "Crafting definition (cooking)"
|
|
|
|
" is missing an output");
|
|
|
|
|
|
|
|
std::string recipe = getstringfield_default(L, table, "recipe", "");
|
|
|
|
if(recipe == "")
|
|
|
|
throw LuaError(L, "Crafting definition (cooking)"
|
|
|
|
" is missing a recipe"
|
|
|
|
" (output=\"" + output + "\")");
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
float cooktime = getfloatfield_default(L, table, "cooktime", 3.0);
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-02-11 18:10:13 +01:00
|
|
|
CraftReplacements replacements;
|
|
|
|
lua_getfield(L, table, "replacements");
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
if(!read_craft_replacements(L, -1, replacements))
|
|
|
|
throw LuaError(L, "Invalid replacements"
|
|
|
|
" (cooking output=\"" + output + "\")");
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
CraftDefinition *def = new CraftDefinitionCooking(
|
2012-02-11 18:10:13 +01:00
|
|
|
output, recipe, cooktime, replacements);
|
2012-01-12 06:10:39 +01:00
|
|
|
craftdef->registerCraft(def);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
CraftDefinitionFuel
|
|
|
|
*/
|
|
|
|
else if(type == "fuel"){
|
|
|
|
std::string recipe = getstringfield_default(L, table, "recipe", "");
|
|
|
|
if(recipe == "")
|
|
|
|
throw LuaError(L, "Crafting definition (fuel)"
|
|
|
|
" is missing a recipe");
|
|
|
|
|
|
|
|
float burntime = getfloatfield_default(L, table, "burntime", 1.0);
|
|
|
|
|
2012-02-11 18:10:13 +01:00
|
|
|
CraftReplacements replacements;
|
|
|
|
lua_getfield(L, table, "replacements");
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
if(!read_craft_replacements(L, -1, replacements))
|
|
|
|
throw LuaError(L, "Invalid replacements"
|
|
|
|
" (fuel recipe=\"" + recipe + "\")");
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
CraftDefinition *def = new CraftDefinitionFuel(
|
2012-02-11 18:10:13 +01:00
|
|
|
recipe, burntime, replacements);
|
2012-01-12 06:10:39 +01:00
|
|
|
craftdef->registerCraft(def);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw LuaError(L, "Unknown crafting definition type: \"" + type + "\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
2011-12-06 14:55:05 +01:00
|
|
|
return 0; /* number of results */
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-04-01 12:08:52 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// setting_get(name)
|
|
|
|
static int l_setting_get(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
try{
|
|
|
|
std::string value = g_settings->get(name);
|
|
|
|
lua_pushstring(L, value.c_str());
|
|
|
|
} catch(SettingNotFoundException &e){
|
|
|
|
lua_pushnil(L);
|
2011-11-29 20:30:22 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// setting_getbool(name)
|
|
|
|
static int l_setting_getbool(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
try{
|
|
|
|
bool value = g_settings->getBool(name);
|
|
|
|
lua_pushboolean(L, value);
|
|
|
|
} catch(SettingNotFoundException &e){
|
|
|
|
lua_pushnil(L);
|
2011-12-28 17:18:08 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2011-12-28 17:18:08 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// chat_send_all(text)
|
|
|
|
static int l_chat_send_all(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *text = luaL_checkstring(L, 1);
|
|
|
|
// Get server from registry
|
|
|
|
Server *server = get_server(L);
|
|
|
|
// Send
|
|
|
|
server->notifyPlayers(narrow_to_wide(text));
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// chat_send_player(name, text)
|
|
|
|
static int l_chat_send_player(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
const char *text = luaL_checkstring(L, 2);
|
|
|
|
// Get server from registry
|
|
|
|
Server *server = get_server(L);
|
|
|
|
// Send
|
|
|
|
server->notifyPlayer(name, narrow_to_wide(text));
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// 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
|
|
|
|
Server *server = get_server(L);
|
|
|
|
// Do it
|
|
|
|
lua_newtable(L);
|
|
|
|
int table = lua_gettop(L);
|
2012-03-30 17:42:18 +02:00
|
|
|
std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
|
2011-12-06 14:55:05 +01:00
|
|
|
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());
|
2011-11-29 20:30:22 +01:00
|
|
|
}
|
2011-12-06 14:55:05 +01:00
|
|
|
lua_pushvalue(L, table);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-08-01 23:17:52 +02:00
|
|
|
// get_ban_list()
|
|
|
|
static int l_get_ban_list(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_pushstring(L, get_server(L)->getBanDescription("").c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_ban_description()
|
|
|
|
static int l_get_ban_description(lua_State *L)
|
|
|
|
{
|
|
|
|
const char * ip_or_name = luaL_checkstring(L, 1);
|
|
|
|
lua_pushstring(L, get_server(L)->getBanDescription(std::string(ip_or_name)).c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ban_player()
|
|
|
|
static int l_ban_player(lua_State *L)
|
|
|
|
{
|
|
|
|
const char * name = luaL_checkstring(L, 1);
|
|
|
|
Player *player = get_env(L)->getPlayer(name);
|
|
|
|
if(player == NULL)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L, false); // no such player
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Address addr = get_server(L)->getPeerAddress(get_env(L)->getPlayer(name)->peer_id);
|
|
|
|
std::string ip_str = addr.serializeString();
|
|
|
|
get_server(L)->setIpBanned(ip_str, name);
|
|
|
|
}
|
|
|
|
catch(con::PeerNotFoundException) // unlikely
|
|
|
|
{
|
|
|
|
dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
|
|
|
|
lua_pushboolean(L, false); // error
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unban_player_or_ip()
|
|
|
|
static int l_unban_player_of_ip(lua_State *L)
|
|
|
|
{
|
|
|
|
const char * ip_or_name = luaL_checkstring(L, 1);
|
|
|
|
get_server(L)->unsetIpBanned(ip_or_name);
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_inventory(location)
|
|
|
|
static int l_get_inventory(lua_State *L)
|
|
|
|
{
|
|
|
|
InventoryLocation loc;
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
std::string type = checkstringfield(L, 1, "type");
|
|
|
|
if(type == "player"){
|
|
|
|
std::string name = checkstringfield(L, 1, "name");
|
|
|
|
loc.setPlayer(name);
|
|
|
|
} else if(type == "node"){
|
|
|
|
lua_getfield(L, 1, "pos");
|
|
|
|
v3s16 pos = check_v3s16(L, -1);
|
|
|
|
loc.setNodeMeta(pos);
|
2012-07-24 19:57:17 +02:00
|
|
|
} else if(type == "detached"){
|
|
|
|
std::string name = checkstringfield(L, 1, "name");
|
|
|
|
loc.setDetached(name);
|
2011-11-29 20:30:22 +01:00
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
if(get_server(L)->getInventory(loc) != NULL)
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
else
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-07-25 01:36:54 +02:00
|
|
|
// create_detached_inventory_raw(name)
|
|
|
|
static int l_create_detached_inventory_raw(lua_State *L)
|
2012-07-24 19:57:17 +02:00
|
|
|
{
|
|
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
if(get_server(L)->createDetachedInventory(name) != NULL){
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
}else{
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
|
|
|
|
static int l_get_dig_params(lua_State *L)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
std::map<std::string, int> groups;
|
|
|
|
read_groups(L, 1, groups);
|
|
|
|
ToolCapabilities tp = read_tool_capabilities(L, 2);
|
2012-01-21 00:11:44 +01:00
|
|
|
if(lua_isnoneornil(L, 3))
|
2012-02-28 18:45:23 +01:00
|
|
|
push_dig_params(L, getDigParams(groups, &tp));
|
2012-01-21 00:11:44 +01:00
|
|
|
else
|
2012-02-28 18:45:23 +01:00
|
|
|
push_dig_params(L, getDigParams(groups, &tp,
|
2012-01-21 00:11:44 +01:00
|
|
|
luaL_checknumber(L, 3)));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
// get_hit_params(groups, tool_capabilities[, time_from_last_punch])
|
|
|
|
static int l_get_hit_params(lua_State *L)
|
2012-01-21 00:11:44 +01:00
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
std::map<std::string, int> groups;
|
|
|
|
read_groups(L, 1, groups);
|
|
|
|
ToolCapabilities tp = read_tool_capabilities(L, 2);
|
2012-01-21 00:11:44 +01:00
|
|
|
if(lua_isnoneornil(L, 3))
|
2012-02-28 18:45:23 +01:00
|
|
|
push_hit_params(L, getHitParams(groups, &tp));
|
2012-01-21 00:11:44 +01:00
|
|
|
else
|
2012-02-28 18:45:23 +01:00
|
|
|
push_hit_params(L, getHitParams(groups, &tp,
|
2012-01-21 00:11:44 +01:00
|
|
|
luaL_checknumber(L, 3)));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// get_current_modname()
|
|
|
|
static int l_get_current_modname(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
// get_modpath(modname)
|
|
|
|
static int l_get_modpath(lua_State *L)
|
|
|
|
{
|
2012-04-01 09:08:52 +02:00
|
|
|
std::string modname = luaL_checkstring(L, 1);
|
2011-12-06 14:55:05 +01:00
|
|
|
// Do it
|
2012-04-01 09:08:52 +02:00
|
|
|
if(modname == "__builtin"){
|
|
|
|
std::string path = get_server(L)->getBuiltinLuaPath();
|
|
|
|
lua_pushstring(L, path.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
2012-01-12 06:10:39 +01:00
|
|
|
const ModSpec *mod = get_server(L)->getModSpec(modname);
|
2011-12-06 14:55:05 +01:00
|
|
|
if(!mod){
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, mod->path.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2012-07-22 03:29:37 +02:00
|
|
|
// get_modnames()
|
|
|
|
// the returned list is sorted alphabetically for you
|
|
|
|
static int l_get_modnames(lua_State *L)
|
|
|
|
{
|
|
|
|
// Get a list of mods
|
|
|
|
core::list<std::string> mods_unsorted, mods_sorted;
|
|
|
|
get_server(L)->getModNames(mods_unsorted);
|
|
|
|
|
|
|
|
// Take unsorted items from mods_unsorted and sort them into
|
|
|
|
// mods_sorted; not great performance but the number of mods on a
|
|
|
|
// server will likely be small.
|
|
|
|
for(core::list<std::string>::Iterator i = mods_unsorted.begin();
|
|
|
|
i != mods_unsorted.end(); i++)
|
|
|
|
{
|
|
|
|
bool added = false;
|
|
|
|
for(core::list<std::string>::Iterator x = mods_sorted.begin();
|
|
|
|
x != mods_unsorted.end(); x++)
|
|
|
|
{
|
|
|
|
// I doubt anybody using Minetest will be using
|
|
|
|
// anything not ASCII based :)
|
|
|
|
if((*i).compare(*x) <= 0)
|
|
|
|
{
|
|
|
|
mods_sorted.insert_before(x, *i);
|
|
|
|
added = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!added)
|
|
|
|
mods_sorted.push_back(*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the table insertion function from Lua.
|
|
|
|
lua_getglobal(L, "table");
|
|
|
|
lua_getfield(L, -1, "insert");
|
|
|
|
int insertion_func = lua_gettop(L);
|
|
|
|
|
|
|
|
// Package them up for Lua
|
|
|
|
lua_newtable(L);
|
|
|
|
int new_table = lua_gettop(L);
|
|
|
|
core::list<std::string>::Iterator i = mods_sorted.begin();
|
|
|
|
while(i != mods_sorted.end())
|
|
|
|
{
|
|
|
|
lua_pushvalue(L, insertion_func);
|
|
|
|
lua_pushvalue(L, new_table);
|
|
|
|
lua_pushstring(L, (*i).c_str());
|
|
|
|
if(lua_pcall(L, 2, 0, 0) != 0)
|
|
|
|
{
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-02-28 19:41:26 +01:00
|
|
|
// get_worldpath()
|
|
|
|
static int l_get_worldpath(lua_State *L)
|
|
|
|
{
|
|
|
|
std::string worldpath = get_server(L)->getWorldPath();
|
|
|
|
lua_pushstring(L, worldpath.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-24 18:01:26 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-03-28 12:22:48 +02:00
|
|
|
// is_singleplayer()
|
|
|
|
static int l_is_singleplayer(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L, get_server(L)->isSingleplayer());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-30 17:42:18 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-03-31 15:23:26 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-06-02 11:19:44 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-07-11 20:46:10 +02:00
|
|
|
// get_craft_recipe(result item)
|
|
|
|
static int l_get_craft_recipe(lua_State *L)
|
|
|
|
{
|
|
|
|
int k = 0;
|
|
|
|
char tmp[20];
|
|
|
|
int input_i = 1;
|
|
|
|
std::string o_item = luaL_checkstring(L,input_i);
|
|
|
|
|
|
|
|
IGameDef *gdef = get_server(L);
|
|
|
|
ICraftDefManager *cdef = gdef->cdef();
|
|
|
|
CraftInput input;
|
|
|
|
CraftOutput output(o_item,0);
|
|
|
|
bool got = cdef->getCraftRecipe(input, output, gdef);
|
|
|
|
lua_newtable(L); // output table
|
|
|
|
if(got){
|
|
|
|
lua_newtable(L);
|
|
|
|
for(std::vector<ItemStack>::const_iterator
|
|
|
|
i = input.items.begin();
|
|
|
|
i != input.items.end(); i++, k++)
|
|
|
|
{
|
|
|
|
if (i->empty())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sprintf(tmp,"%d",k);
|
|
|
|
lua_pushstring(L,tmp);
|
|
|
|
lua_pushstring(L,i->name.c_str());
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
lua_setfield(L, -2, "items");
|
|
|
|
setintfield(L, -1, "width", input.width);
|
|
|
|
switch (input.method) {
|
|
|
|
case CRAFT_METHOD_NORMAL:
|
2012-07-21 14:32:46 +02:00
|
|
|
lua_pushstring(L,"normal");
|
2012-07-11 20:46:10 +02:00
|
|
|
break;
|
|
|
|
case CRAFT_METHOD_COOKING:
|
|
|
|
lua_pushstring(L,"cooking");
|
|
|
|
break;
|
|
|
|
case CRAFT_METHOD_FUEL:
|
|
|
|
lua_pushstring(L,"fuel");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
lua_pushstring(L,"unknown");
|
|
|
|
}
|
|
|
|
lua_setfield(L, -2, "type");
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_setfield(L, -2, "items");
|
|
|
|
setintfield(L, -1, "width", 0);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-07-26 21:06:45 +02:00
|
|
|
// rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
|
|
|
|
static int l_rollback_get_last_node_actor(lua_State *L)
|
|
|
|
{
|
|
|
|
v3s16 p = read_v3s16(L, 1);
|
|
|
|
int range = luaL_checknumber(L, 2);
|
|
|
|
int seconds = luaL_checknumber(L, 3);
|
|
|
|
Server *server = get_server(L);
|
|
|
|
IRollbackManager *rollback = server->getRollbackManager();
|
|
|
|
v3s16 act_p;
|
|
|
|
int act_seconds = 0;
|
|
|
|
std::string actor = rollback->getLastNodeActor(p, range, seconds, &act_p, &act_seconds);
|
|
|
|
lua_pushstring(L, actor.c_str());
|
|
|
|
push_v3s16(L, act_p);
|
|
|
|
lua_pushnumber(L, act_seconds);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rollback_revert_actions_by(actor, seconds) -> bool, log messages
|
|
|
|
static int l_rollback_revert_actions_by(lua_State *L)
|
|
|
|
{
|
|
|
|
std::string actor = luaL_checkstring(L, 1);
|
|
|
|
int seconds = luaL_checknumber(L, 2);
|
|
|
|
Server *server = get_server(L);
|
|
|
|
IRollbackManager *rollback = server->getRollbackManager();
|
|
|
|
std::list<RollbackAction> actions = rollback->getRevertActions(actor, seconds);
|
|
|
|
std::list<std::string> log;
|
|
|
|
bool success = server->rollbackRevertActions(actions, &log);
|
|
|
|
// Push boolean result
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
// Get the table insert function and push the log table
|
|
|
|
lua_getglobal(L, "table");
|
|
|
|
lua_getfield(L, -1, "insert");
|
|
|
|
int table_insert = lua_gettop(L);
|
|
|
|
lua_newtable(L);
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
for(std::list<std::string>::const_iterator i = log.begin();
|
|
|
|
i != log.end(); i++)
|
|
|
|
{
|
|
|
|
lua_pushvalue(L, table_insert);
|
|
|
|
lua_pushvalue(L, table);
|
|
|
|
lua_pushstring(L, i->c_str());
|
|
|
|
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
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2011-12-06 14:55:05 +01:00
|
|
|
static const struct luaL_Reg minetest_f [] = {
|
2012-01-12 06:10:39 +01:00
|
|
|
{"debug", l_debug},
|
|
|
|
{"log", l_log},
|
2012-07-28 21:27:31 +02:00
|
|
|
{"request_shutdown", l_request_shutdown},
|
|
|
|
{"get_server_status", l_get_server_status},
|
2012-01-12 06:10:39 +01:00
|
|
|
{"register_item_raw", l_register_item_raw},
|
|
|
|
{"register_alias_raw", l_register_alias_raw},
|
2011-12-06 14:55:05 +01:00
|
|
|
{"register_craft", l_register_craft},
|
2012-04-01 12:08:52 +02:00
|
|
|
{"setting_set", l_setting_set},
|
2011-12-06 14:55:05 +01:00
|
|
|
{"setting_get", l_setting_get},
|
|
|
|
{"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},
|
2012-08-01 23:17:52 +02:00
|
|
|
{"get_ban_list", l_get_ban_list},
|
|
|
|
{"get_ban_description", l_get_ban_description},
|
|
|
|
{"ban_player", l_ban_player},
|
|
|
|
{"unban_player_or_ip", l_unban_player_of_ip},
|
2011-12-06 14:55:05 +01:00
|
|
|
{"get_inventory", l_get_inventory},
|
2012-07-25 01:36:54 +02:00
|
|
|
{"create_detached_inventory_raw", l_create_detached_inventory_raw},
|
2012-02-28 18:45:23 +01:00
|
|
|
{"get_dig_params", l_get_dig_params},
|
|
|
|
{"get_hit_params", l_get_hit_params},
|
2012-01-12 06:10:39 +01:00
|
|
|
{"get_current_modname", l_get_current_modname},
|
2011-12-06 14:55:05 +01:00
|
|
|
{"get_modpath", l_get_modpath},
|
2012-07-22 03:29:37 +02:00
|
|
|
{"get_modnames", l_get_modnames},
|
2012-02-28 19:41:26 +01:00
|
|
|
{"get_worldpath", l_get_worldpath},
|
2012-03-24 18:01:26 +01:00
|
|
|
{"sound_play", l_sound_play},
|
|
|
|
{"sound_stop", l_sound_stop},
|
2012-03-28 12:22:48 +02:00
|
|
|
{"is_singleplayer", l_is_singleplayer},
|
2012-03-30 17:42:18 +02:00
|
|
|
{"get_password_hash", l_get_password_hash},
|
2012-03-31 15:23:26 +02:00
|
|
|
{"notify_authentication_modified", l_notify_authentication_modified},
|
2012-06-02 11:19:44 +02:00
|
|
|
{"get_craft_result", l_get_craft_result},
|
2012-07-11 20:46:10 +02:00
|
|
|
{"get_craft_recipe", l_get_craft_recipe},
|
2012-07-26 21:06:45 +02:00
|
|
|
{"rollback_get_last_node_actor", l_rollback_get_last_node_actor},
|
|
|
|
{"rollback_revert_actions_by", l_rollback_revert_actions_by},
|
2011-12-06 14:55:05 +01:00
|
|
|
{NULL, NULL}
|
|
|
|
};
|
2011-11-29 20:30:22 +01:00
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
/*
|
|
|
|
Main export function
|
|
|
|
*/
|
|
|
|
|
2011-11-11 18:33:17 +01:00
|
|
|
void scriptapi_export(lua_State *L, Server *server)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"scriptapi_export()"<<std::endl;
|
2011-11-12 10:59:56 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-15 01:03:28 +01:00
|
|
|
|
|
|
|
// Store server as light userdata in registry
|
|
|
|
lua_pushlightuserdata(L, server);
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_server");
|
2011-11-26 01:26:19 +01:00
|
|
|
|
2011-11-11 18:33:17 +01:00
|
|
|
// Register global functions in table minetest
|
|
|
|
lua_newtable(L);
|
|
|
|
luaL_register(L, NULL, minetest_f);
|
|
|
|
lua_setglobal(L, "minetest");
|
|
|
|
|
|
|
|
// Get the main minetest table
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
|
2011-11-12 17:34:04 +01:00
|
|
|
// Add tables to minetest
|
2011-11-11 18:33:17 +01:00
|
|
|
lua_newtable(L);
|
|
|
|
lua_setfield(L, -2, "object_refs");
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_setfield(L, -2, "luaentities");
|
|
|
|
|
2011-12-06 16:23:58 +01:00
|
|
|
// Register wrappers
|
2012-01-12 06:10:39 +01:00
|
|
|
LuaItemStack::Register(L);
|
2011-12-06 16:23:58 +01:00
|
|
|
InvRef::Register(L);
|
2011-11-28 02:06:21 +01:00
|
|
|
NodeMetaRef::Register(L);
|
2012-07-17 15:00:04 +02:00
|
|
|
NodeTimerRef::Register(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
ObjectRef::Register(L);
|
2011-12-06 16:23:58 +01:00
|
|
|
EnvRef::Register(L);
|
2012-03-27 23:38:20 +02:00
|
|
|
LuaPseudoRandom::Register(L);
|
2012-03-31 21:52:25 +02:00
|
|
|
LuaPerlinNoise::Register(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2011-12-02 21:49:54 +01:00
|
|
|
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
|
|
|
|
const std::string &modname)
|
|
|
|
{
|
2011-12-03 01:45:55 +01:00
|
|
|
ModNameStorer modnamestorer(L, modname);
|
|
|
|
|
2011-12-04 17:26:05 +01:00
|
|
|
if(!string_allowed(modname, "abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"0123456789_")){
|
|
|
|
errorstream<<"Error loading mod \""<<modname
|
|
|
|
<<"\": modname does not follow naming conventions: "
|
|
|
|
<<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-12-02 21:49:54 +01:00
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
try{
|
|
|
|
success = script_load(L, scriptpath.c_str());
|
|
|
|
}
|
|
|
|
catch(LuaError &e){
|
2011-12-03 01:45:55 +01:00
|
|
|
errorstream<<"Error loading mod \""<<modname
|
|
|
|
<<"\": "<<e.what()<<std::endl;
|
2011-12-02 21:49:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"scriptapi_add_environment"<<std::endl;
|
2011-11-12 10:59:56 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-12 01:25:30 +01:00
|
|
|
|
|
|
|
// Create EnvRef on stack
|
|
|
|
EnvRef::create(L, env);
|
|
|
|
int envref = lua_gettop(L);
|
|
|
|
|
|
|
|
// minetest.env = envref
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushvalue(L, envref);
|
|
|
|
lua_setfield(L, -2, "env");
|
2011-11-28 01:16:51 +01:00
|
|
|
|
|
|
|
// Store environment as light userdata in registry
|
|
|
|
lua_pushlightuserdata(L, env);
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_env");
|
|
|
|
|
2011-12-03 17:18:59 +01:00
|
|
|
/*
|
|
|
|
Add ActiveBlockModifiers to environment
|
|
|
|
*/
|
2011-11-28 01:16:51 +01:00
|
|
|
|
|
|
|
// Get minetest.registered_abms
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_abms");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
int registered_abms = lua_gettop(L);
|
|
|
|
|
|
|
|
if(lua_istable(L, registered_abms)){
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
int id = lua_tonumber(L, -2);
|
|
|
|
int current_abm = lua_gettop(L);
|
|
|
|
|
|
|
|
std::set<std::string> trigger_contents;
|
|
|
|
lua_getfield(L, current_abm, "nodenames");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
luaL_checktype(L, -1, LUA_TSTRING);
|
|
|
|
trigger_contents.insert(lua_tostring(L, -1));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
2011-12-03 17:18:59 +01:00
|
|
|
} else if(lua_isstring(L, -1)){
|
|
|
|
trigger_contents.insert(lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
std::set<std::string> required_neighbors;
|
|
|
|
lua_getfield(L, current_abm, "neighbors");
|
|
|
|
if(lua_istable(L, -1)){
|
|
|
|
int table = lua_gettop(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, table) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
luaL_checktype(L, -1, LUA_TSTRING);
|
|
|
|
required_neighbors.insert(lua_tostring(L, -1));
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
} else if(lua_isstring(L, -1)){
|
|
|
|
required_neighbors.insert(lua_tostring(L, -1));
|
2011-11-28 01:16:51 +01:00
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
float trigger_interval = 10.0;
|
|
|
|
getfloatfield(L, current_abm, "interval", trigger_interval);
|
|
|
|
|
|
|
|
int trigger_chance = 50;
|
|
|
|
getintfield(L, current_abm, "chance", trigger_chance);
|
|
|
|
|
|
|
|
LuaABM *abm = new LuaABM(L, id, trigger_contents,
|
2011-12-03 17:18:59 +01:00
|
|
|
required_neighbors, trigger_interval, trigger_chance);
|
2011-11-28 01:16:51 +01:00
|
|
|
|
|
|
|
env->addActiveBlockModifier(abm);
|
|
|
|
|
|
|
|
// removes value, keeps key for next iteration
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2011-11-12 01:25:30 +01:00
|
|
|
}
|
|
|
|
|
2011-11-12 16:37:14 +01:00
|
|
|
#if 0
|
2011-11-11 23:46:05 +01:00
|
|
|
// Dump stack top with the dump2 function
|
|
|
|
static void dump2(lua_State *L, const char *name)
|
|
|
|
{
|
|
|
|
// Dump object (debug)
|
|
|
|
lua_getglobal(L, "dump2");
|
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, -2); // Get previous stack top as first parameter
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
if(lua_pcall(L, 2, 0, 0))
|
2011-12-03 01:45:55 +01:00
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2011-11-11 23:46:05 +01:00
|
|
|
}
|
2011-11-12 16:37:14 +01:00
|
|
|
#endif
|
2011-11-11 23:46:05 +01:00
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
/*
|
|
|
|
object_reference
|
|
|
|
*/
|
|
|
|
|
|
|
|
void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2011-11-28 16:11:14 +01:00
|
|
|
//infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
|
2011-11-12 10:59:56 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-12 01:25:30 +01:00
|
|
|
|
|
|
|
// Create object on stack
|
|
|
|
ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
|
|
|
|
int object = lua_gettop(L);
|
|
|
|
|
|
|
|
// Get minetest.object_refs table
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "object_refs");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
int objectstable = lua_gettop(L);
|
|
|
|
|
|
|
|
// object_refs[id] = object
|
|
|
|
lua_pushnumber(L, cobj->getId()); // Push id
|
|
|
|
lua_pushvalue(L, object); // Copy object to top of stack
|
|
|
|
lua_settable(L, objectstable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2011-11-28 16:11:14 +01:00
|
|
|
//infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
|
2011-11-12 10:59:56 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-12 01:25:30 +01:00
|
|
|
|
|
|
|
// Get minetest.object_refs table
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "object_refs");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
int objectstable = lua_gettop(L);
|
|
|
|
|
|
|
|
// Get object_refs[id]
|
|
|
|
lua_pushnumber(L, cobj->getId()); // Push id
|
|
|
|
lua_gettable(L, objectstable);
|
|
|
|
// Set object reference to NULL
|
|
|
|
ObjectRef::set_null(L);
|
|
|
|
lua_pop(L, 1); // pop object
|
|
|
|
|
|
|
|
// Set object_refs[id] = nil
|
|
|
|
lua_pushnumber(L, cobj->getId()); // Push id
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_settable(L, objectstable);
|
|
|
|
}
|
|
|
|
|
2012-03-24 18:52:50 +01:00
|
|
|
/*
|
|
|
|
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
|
2011-11-27 18:39:36 +01:00
|
|
|
{
|
2012-03-24 18:52:50 +01:00
|
|
|
// 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);
|
2011-11-27 18:39:36 +01:00
|
|
|
|
2011-11-28 00:13:55 +01:00
|
|
|
// Foreach
|
|
|
|
lua_pushnil(L);
|
2012-03-24 18:52:50 +01:00
|
|
|
bool first_loop = true;
|
2011-11-28 00:13:55 +01:00
|
|
|
while(lua_next(L, table) != 0){
|
|
|
|
// key at index -2 and value at index -1
|
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
// Call function
|
2012-03-24 18:52:50 +01:00
|
|
|
for(int i = 0; i < nargs; i++)
|
|
|
|
lua_pushvalue(L, arg+i);
|
|
|
|
if(lua_pcall(L, nargs, 1, 0))
|
2011-12-03 01:45:55 +01:00
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-03-24 18:52:50 +01:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2011-11-28 00:13:55 +01:00
|
|
|
// value removed, keep key for next iteration
|
|
|
|
}
|
2012-03-24 18:52:50 +01:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
2011-11-27 18:39:36 +01:00
|
|
|
}
|
2011-11-26 02:20:19 +01:00
|
|
|
|
2012-03-24 18:52:50 +01:00
|
|
|
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;
|
|
|
|
}
|
2011-11-26 02:20:19 +01:00
|
|
|
|
2012-09-08 20:44:26 +02:00
|
|
|
void scriptapi_on_shutdown(lua_State *L)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get registered shutdown hooks
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_on_shutdown");
|
|
|
|
// Call callbacks
|
|
|
|
scriptapi_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
|
|
|
|
}
|
|
|
|
|
2011-11-26 02:20:19 +01:00
|
|
|
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.registered_on_newplayers
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_on_newplayers");
|
2012-03-24 18:52:50 +01:00
|
|
|
// Call callbacks
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
2011-11-26 02:20:19 +01:00
|
|
|
}
|
2012-01-05 23:12:33 +01:00
|
|
|
|
|
|
|
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player)
|
|
|
|
{
|
2012-03-24 18:52:50 +01:00
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
2012-01-05 23:12:33 +01:00
|
|
|
|
2012-03-24 18:52:50 +01:00
|
|
|
// 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);
|
|
|
|
}
|
2012-01-05 23:12:33 +01:00
|
|
|
|
2011-11-26 02:20:19 +01:00
|
|
|
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.registered_on_respawnplayers
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_on_respawnplayers");
|
2012-03-24 18:52:50 +01:00
|
|
|
// 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);
|
2011-11-26 02:20:19 +01:00
|
|
|
return positioning_handled_by_some;
|
|
|
|
}
|
|
|
|
|
2012-03-24 18:52:50 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-03-30 17:42:18 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-07-22 16:10:58 +02:00
|
|
|
/*
|
|
|
|
player
|
|
|
|
*/
|
|
|
|
|
|
|
|
void scriptapi_on_player_receive_fields(lua_State *L,
|
|
|
|
ServerActiveObject *player,
|
|
|
|
const std::string &formname,
|
|
|
|
const std::map<std::string, std::string> &fields)
|
|
|
|
{
|
|
|
|
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_player_receive_fields");
|
|
|
|
// Call callbacks
|
|
|
|
// param 1
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_OR_SC);
|
|
|
|
}
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
/*
|
2012-01-21 00:11:44 +01:00
|
|
|
item callbacks and node callbacks
|
2011-11-29 16:15:18 +01:00
|
|
|
*/
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Retrieves minetest.registered_items[name][callbackname]
|
|
|
|
// If that is nil or on error, return false and stack is unchanged
|
|
|
|
// If that is a function, returns true and pushes the
|
|
|
|
// function onto the stack
|
2012-07-30 15:45:26 +02:00
|
|
|
// If minetest.registered_items[name] doesn't exist, minetest.nodedef_default
|
|
|
|
// is tried instead so unknown items can still be manipulated to some degree
|
2012-01-12 06:10:39 +01:00
|
|
|
static bool get_item_callback(lua_State *L,
|
|
|
|
const char *name, const char *callbackname)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
lua_getglobal(L, "minetest");
|
2012-01-12 06:10:39 +01:00
|
|
|
lua_getfield(L, -1, "registered_items");
|
2011-11-29 16:15:18 +01:00
|
|
|
lua_remove(L, -2);
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_getfield(L, -1, name);
|
|
|
|
lua_remove(L, -2);
|
|
|
|
// Should be a table
|
|
|
|
if(lua_type(L, -1) != LUA_TTABLE)
|
|
|
|
{
|
2012-07-30 15:45:26 +02:00
|
|
|
// Report error and clean up
|
2012-01-12 06:10:39 +01:00
|
|
|
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
|
2011-11-29 16:15:18 +01:00
|
|
|
lua_pop(L, 1);
|
2012-07-30 15:45:26 +02:00
|
|
|
|
|
|
|
// Try minetest.nodedef_default instead
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "nodedef_default");
|
|
|
|
lua_remove(L, -2);
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
lua_getfield(L, -1, callbackname);
|
|
|
|
lua_remove(L, -2);
|
|
|
|
// Should be a function or nil
|
|
|
|
if(lua_type(L, -1) == LUA_TFUNCTION)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if(lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
errorstream<<"Item \""<<name<<"\" callback \""
|
2011-11-29 16:15:18 +01:00
|
|
|
<<callbackname<<" is not a function"<<std::endl;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
|
|
|
|
ServerActiveObject *dropper, v3f pos)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, item.name.c_str(), "on_drop"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
LuaItemStack::create(L, item);
|
|
|
|
objectref_get_or_create(L, dropper);
|
|
|
|
pushFloatPos(L, pos);
|
|
|
|
if(lua_pcall(L, 3, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
item = read_item(L, -1);
|
|
|
|
return true;
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
|
|
|
|
ServerActiveObject *placer, const PointedThing &pointed)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, item.name.c_str(), "on_place"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
LuaItemStack::create(L, item);
|
|
|
|
objectref_get_or_create(L, placer);
|
|
|
|
push_pointed_thing(L, pointed);
|
|
|
|
if(lua_pcall(L, 3, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
item = read_item(L, -1);
|
|
|
|
return true;
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
|
|
|
|
ServerActiveObject *user, const PointedThing &pointed)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, item.name.c_str(), "on_use"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
LuaItemStack::create(L, item);
|
|
|
|
objectref_get_or_create(L, user);
|
|
|
|
push_pointed_thing(L, pointed);
|
|
|
|
if(lua_pcall(L, 3, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
item = read_item(L, -1);
|
|
|
|
return true;
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
|
2012-06-01 16:24:54 +02:00
|
|
|
bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
|
2012-01-21 00:11:44 +01:00
|
|
|
ServerActiveObject *puncher)
|
2011-11-12 16:46:06 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
INodeDefManager *ndef = get_server(L)->ndef();
|
2011-11-12 16:46:06 +01:00
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
|
|
|
|
return false;
|
2011-11-17 10:22:24 +01:00
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
// Call function
|
2012-06-01 16:24:54 +02:00
|
|
|
push_v3s16(L, p);
|
2012-01-21 00:11:44 +01:00
|
|
|
pushnode(L, node, ndef);
|
|
|
|
objectref_get_or_create(L, puncher);
|
|
|
|
if(lua_pcall(L, 3, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
return true;
|
2011-11-17 10:22:24 +01:00
|
|
|
}
|
|
|
|
|
2012-06-01 16:24:54 +02:00
|
|
|
bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
|
2011-11-25 18:49:20 +01:00
|
|
|
ServerActiveObject *digger)
|
2011-11-17 10:22:24 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
INodeDefManager *ndef = get_server(L)->ndef();
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Call function
|
2012-06-01 16:24:54 +02:00
|
|
|
push_v3s16(L, p);
|
2012-01-21 00:11:44 +01:00
|
|
|
pushnode(L, node, ndef);
|
|
|
|
objectref_get_or_create(L, digger);
|
|
|
|
if(lua_pcall(L, 3, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
return true;
|
2011-11-17 10:22:24 +01:00
|
|
|
}
|
|
|
|
|
2012-06-01 16:24:54 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2012-06-05 22:51:37 +02:00
|
|
|
void scriptapi_node_after_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(), "after_destruct"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
push_v3s16(L, p);
|
|
|
|
pushnode(L, node, ndef);
|
|
|
|
if(lua_pcall(L, 2, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
2012-07-17 15:00:04 +02:00
|
|
|
bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime)
|
|
|
|
{
|
|
|
|
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_timer"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
push_v3s16(L, p);
|
|
|
|
lua_pushnumber(L,dtime);
|
|
|
|
if(lua_pcall(L, 2, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
if(lua_isboolean(L,-1) && lua_toboolean(L,-1) == true)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-06-01 19:51:15 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:36:54 +02:00
|
|
|
/*
|
|
|
|
Node metadata inventory callbacks
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Return number of accepted items to be moved
|
|
|
|
int scriptapi_nodemeta_inventory_allow_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 0;
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
|
|
|
"allow_metadata_inventory_move"))
|
|
|
|
return count;
|
|
|
|
|
|
|
|
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
// pos
|
|
|
|
push_v3s16(L, p);
|
|
|
|
// from_list
|
|
|
|
lua_pushstring(L, from_list.c_str());
|
|
|
|
// from_index
|
|
|
|
lua_pushinteger(L, from_index + 1);
|
|
|
|
// to_list
|
|
|
|
lua_pushstring(L, to_list.c_str());
|
|
|
|
// to_index
|
|
|
|
lua_pushinteger(L, to_index + 1);
|
|
|
|
// count
|
|
|
|
lua_pushinteger(L, count);
|
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 7, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_metadata_inventory_move should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return number of accepted items to be put
|
|
|
|
int scriptapi_nodemeta_inventory_allow_put(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 0;
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
|
|
|
"allow_metadata_inventory_put"))
|
|
|
|
return stack.count;
|
|
|
|
|
|
|
|
// Call function(pos, listname, index, stack, player)
|
|
|
|
// pos
|
|
|
|
push_v3s16(L, p);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_metadata_inventory_put should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return number of accepted items to be taken
|
|
|
|
int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
|
2012-07-25 13:35:59 +02:00
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
2012-07-25 01:36:54 +02:00
|
|
|
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 0;
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
|
|
|
"allow_metadata_inventory_take"))
|
2012-07-25 13:35:59 +02:00
|
|
|
return stack.count;
|
2012-07-25 01:36:54 +02:00
|
|
|
|
|
|
|
// Call function(pos, listname, index, count, player)
|
|
|
|
// pos
|
|
|
|
push_v3s16(L, p);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
2012-07-25 13:35:59 +02:00
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_metadata_inventory_take should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report moved items
|
|
|
|
void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
|
2012-06-01 23:33:51 +02:00
|
|
|
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)
|
2012-07-25 01:36:54 +02:00
|
|
|
// pos
|
2012-06-01 23:33:51 +02:00
|
|
|
push_v3s16(L, p);
|
2012-07-25 01:36:54 +02:00
|
|
|
// from_list
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushstring(L, from_list.c_str());
|
2012-07-25 01:36:54 +02:00
|
|
|
// from_index
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushinteger(L, from_index + 1);
|
2012-07-25 01:36:54 +02:00
|
|
|
// to_list
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushstring(L, to_list.c_str());
|
2012-07-25 01:36:54 +02:00
|
|
|
// to_index
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushinteger(L, to_index + 1);
|
2012-07-25 01:36:54 +02:00
|
|
|
// count
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushinteger(L, count);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
2012-06-01 23:33:51 +02:00
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 7, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:36:54 +02:00
|
|
|
// Report put items
|
|
|
|
void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
|
2012-06-01 23:33:51 +02:00
|
|
|
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)
|
2012-07-25 01:36:54 +02:00
|
|
|
return;
|
2012-06-01 23:33:51 +02:00
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
2012-07-25 01:36:54 +02:00
|
|
|
"on_metadata_inventory_put"))
|
|
|
|
return;
|
2012-06-01 23:33:51 +02:00
|
|
|
|
|
|
|
// Call function(pos, listname, index, stack, player)
|
2012-07-25 01:36:54 +02:00
|
|
|
// pos
|
2012-06-01 23:33:51 +02:00
|
|
|
push_v3s16(L, p);
|
2012-07-25 01:36:54 +02:00
|
|
|
// listname
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushstring(L, listname.c_str());
|
2012-07-25 01:36:54 +02:00
|
|
|
// index
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushinteger(L, index + 1);
|
2012-07-25 01:36:54 +02:00
|
|
|
// stack
|
2012-06-01 23:33:51 +02:00
|
|
|
LuaItemStack::create(L, stack);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
2012-06-01 23:33:51 +02:00
|
|
|
objectref_get_or_create(L, player);
|
2012-07-25 01:36:54 +02:00
|
|
|
if(lua_pcall(L, 5, 0, 0))
|
2012-06-01 23:33:51 +02:00
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:36:54 +02:00
|
|
|
// Report taken items
|
|
|
|
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
|
2012-07-25 13:35:59 +02:00
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
2012-06-01 23:33:51 +02:00
|
|
|
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)
|
2012-07-25 01:36:54 +02:00
|
|
|
return;
|
2012-06-01 23:33:51 +02:00
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
|
|
|
"on_metadata_inventory_take"))
|
2012-07-25 01:36:54 +02:00
|
|
|
return;
|
2012-06-01 23:33:51 +02:00
|
|
|
|
2012-07-25 13:35:59 +02:00
|
|
|
// Call function(pos, listname, index, stack, player)
|
2012-07-25 01:36:54 +02:00
|
|
|
// pos
|
2012-06-01 23:33:51 +02:00
|
|
|
push_v3s16(L, p);
|
2012-07-25 01:36:54 +02:00
|
|
|
// listname
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushstring(L, listname.c_str());
|
2012-07-25 01:36:54 +02:00
|
|
|
// index
|
2012-06-01 23:33:51 +02:00
|
|
|
lua_pushinteger(L, index + 1);
|
2012-07-25 13:35:59 +02:00
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Detached inventory callbacks
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Retrieves minetest.detached_inventories[name][callbackname]
|
|
|
|
// If that is nil or on error, return false and stack is unchanged
|
|
|
|
// If that is a function, returns true and pushes the
|
|
|
|
// function onto the stack
|
|
|
|
static bool get_detached_inventory_callback(lua_State *L,
|
|
|
|
const std::string &name, const char *callbackname)
|
|
|
|
{
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "detached_inventories");
|
|
|
|
lua_remove(L, -2);
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_getfield(L, -1, name.c_str());
|
|
|
|
lua_remove(L, -2);
|
|
|
|
// Should be a table
|
|
|
|
if(lua_type(L, -1) != LUA_TTABLE)
|
|
|
|
{
|
|
|
|
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
lua_getfield(L, -1, callbackname);
|
|
|
|
lua_remove(L, -2);
|
|
|
|
// Should be a function or nil
|
|
|
|
if(lua_type(L, -1) == LUA_TFUNCTION)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if(lua_isnil(L, -1))
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
errorstream<<"Detached inventory \""<<name<<"\" callback \""
|
|
|
|
<<callbackname<<"\" is not a function"<<std::endl;
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return number of accepted items to be moved
|
|
|
|
int scriptapi_detached_inventory_allow_move(lua_State *L,
|
|
|
|
const std::string &name,
|
|
|
|
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);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "allow_move"))
|
|
|
|
return count;
|
|
|
|
|
|
|
|
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// from_list
|
|
|
|
lua_pushstring(L, from_list.c_str());
|
|
|
|
// from_index
|
|
|
|
lua_pushinteger(L, from_index + 1);
|
|
|
|
// to_list
|
|
|
|
lua_pushstring(L, to_list.c_str());
|
|
|
|
// to_index
|
|
|
|
lua_pushinteger(L, to_index + 1);
|
|
|
|
// count
|
|
|
|
lua_pushinteger(L, count);
|
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 7, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_move should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return number of accepted items to be put
|
|
|
|
int scriptapi_detached_inventory_allow_put(lua_State *L,
|
|
|
|
const std::string &name,
|
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
|
|
|
ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "allow_put"))
|
|
|
|
return stack.count; // All will be accepted
|
|
|
|
|
|
|
|
// Call function(inv, listname, index, stack, player)
|
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
|
|
|
// player
|
2012-06-01 23:33:51 +02:00
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_put should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return number of accepted items to be taken
|
|
|
|
int scriptapi_detached_inventory_allow_take(lua_State *L,
|
|
|
|
const std::string &name,
|
2012-07-25 13:35:59 +02:00
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
2012-07-25 01:36:54 +02:00
|
|
|
ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "allow_take"))
|
2012-07-25 13:35:59 +02:00
|
|
|
return stack.count; // All will be accepted
|
2012-07-25 01:36:54 +02:00
|
|
|
|
2012-07-25 13:35:59 +02:00
|
|
|
// Call function(inv, listname, index, stack, player)
|
2012-07-25 01:36:54 +02:00
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
2012-07-25 13:35:59 +02:00
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 1, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-07-25 13:35:59 +02:00
|
|
|
if(!lua_isnumber(L, -1))
|
|
|
|
throw LuaError(L, "allow_take should return a number");
|
2012-07-25 01:36:54 +02:00
|
|
|
return luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report moved items
|
|
|
|
void scriptapi_detached_inventory_on_move(lua_State *L,
|
|
|
|
const std::string &name,
|
|
|
|
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);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "on_move"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// from_list
|
|
|
|
lua_pushstring(L, from_list.c_str());
|
|
|
|
// from_index
|
|
|
|
lua_pushinteger(L, from_index + 1);
|
|
|
|
// to_list
|
|
|
|
lua_pushstring(L, to_list.c_str());
|
|
|
|
// to_index
|
|
|
|
lua_pushinteger(L, to_index + 1);
|
|
|
|
// count
|
|
|
|
lua_pushinteger(L, count);
|
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 7, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report put items
|
|
|
|
void scriptapi_detached_inventory_on_put(lua_State *L,
|
|
|
|
const std::string &name,
|
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
|
|
|
ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "on_put"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Call function(inv, listname, index, stack, player)
|
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report taken items
|
|
|
|
void scriptapi_detached_inventory_on_take(lua_State *L,
|
|
|
|
const std::string &name,
|
2012-07-25 13:35:59 +02:00
|
|
|
const std::string &listname, int index, ItemStack &stack,
|
2012-07-25 01:36:54 +02:00
|
|
|
ServerActiveObject *player)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Push callback function on stack
|
|
|
|
if(!get_detached_inventory_callback(L, name, "on_take"))
|
|
|
|
return;
|
|
|
|
|
2012-07-25 13:35:59 +02:00
|
|
|
// Call function(inv, listname, index, stack, player)
|
2012-07-25 01:36:54 +02:00
|
|
|
// inv
|
|
|
|
InventoryLocation loc;
|
|
|
|
loc.setDetached(name);
|
|
|
|
InvRef::create(L, loc);
|
|
|
|
// listname
|
|
|
|
lua_pushstring(L, listname.c_str());
|
|
|
|
// index
|
|
|
|
lua_pushinteger(L, index + 1);
|
2012-07-25 13:35:59 +02:00
|
|
|
// stack
|
|
|
|
LuaItemStack::create(L, stack);
|
2012-07-25 01:36:54 +02:00
|
|
|
// player
|
|
|
|
objectref_get_or_create(L, player);
|
|
|
|
if(lua_pcall(L, 5, 0, 0))
|
|
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
2012-06-01 23:33:51 +02:00
|
|
|
}
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
/*
|
|
|
|
environment
|
|
|
|
*/
|
|
|
|
|
|
|
|
void scriptapi_environment_step(lua_State *L, float dtime)
|
2011-11-21 10:15:15 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-01-21 00:11:44 +01:00
|
|
|
//infostream<<"scriptapi_environment_step"<<std::endl;
|
2011-11-21 10:15:15 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
// Get minetest.registered_globalsteps
|
2011-11-21 10:15:15 +01:00
|
|
|
lua_getglobal(L, "minetest");
|
2012-01-21 00:11:44 +01:00
|
|
|
lua_getfield(L, -1, "registered_globalsteps");
|
2012-03-24 18:52:50 +01:00
|
|
|
// Call callbacks
|
|
|
|
lua_pushnumber(L, dtime);
|
|
|
|
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
2011-11-21 10:15:15 +01:00
|
|
|
}
|
|
|
|
|
2012-03-28 19:46:05 +02:00
|
|
|
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
|
|
|
|
u32 blockseed)
|
2011-11-26 14:19:03 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2011-11-27 18:39:36 +01:00
|
|
|
//infostream<<"scriptapi_environment_on_generated"<<std::endl;
|
2011-11-26 14:19:03 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.registered_on_generateds
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_on_generateds");
|
2012-03-24 18:52:50 +01:00
|
|
|
// Call callbacks
|
|
|
|
push_v3s16(L, minp);
|
|
|
|
push_v3s16(L, maxp);
|
|
|
|
lua_pushnumber(L, blockseed);
|
|
|
|
scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
|
2011-11-26 14:19:03 +01:00
|
|
|
}
|
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
/*
|
|
|
|
luaentity
|
|
|
|
*/
|
|
|
|
|
2012-03-10 00:38:48 +01:00
|
|
|
bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
|
2011-11-11 23:46:05 +01:00
|
|
|
<<name<<"\""<<std::endl;
|
2011-11-12 01:25:30 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2011-11-11 23:46:05 +01:00
|
|
|
// Get minetest.registered_entities[name]
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "registered_entities");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
// Should be a table, which we will use as a prototype
|
2011-11-12 17:34:04 +01:00
|
|
|
//luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
if(lua_type(L, -1) != LUA_TTABLE){
|
|
|
|
errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2011-11-11 23:46:05 +01:00
|
|
|
int prototype_table = lua_gettop(L);
|
|
|
|
//dump2(L, "prototype_table");
|
|
|
|
|
|
|
|
// Create entity object
|
|
|
|
lua_newtable(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
int object = lua_gettop(L);
|
|
|
|
|
2011-11-11 23:46:05 +01:00
|
|
|
// Set object metatable
|
|
|
|
lua_pushvalue(L, prototype_table);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
// Add object reference
|
|
|
|
// This should be userdata with metatable ObjectRef
|
|
|
|
objectref_get(L, id);
|
|
|
|
luaL_checktype(L, -1, LUA_TUSERDATA);
|
|
|
|
if(!luaL_checkudata(L, -1, "ObjectRef"))
|
|
|
|
luaL_typerror(L, -1, "ObjectRef");
|
|
|
|
lua_setfield(L, -2, "object");
|
2011-11-11 23:46:05 +01:00
|
|
|
|
2011-11-12 02:21:40 +01:00
|
|
|
// minetest.luaentities[id] = object
|
2011-11-11 18:33:17 +01:00
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "luaentities");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushnumber(L, id); // Push id
|
|
|
|
lua_pushvalue(L, object); // Copy object to top of stack
|
2011-11-12 02:21:40 +01:00
|
|
|
lua_settable(L, -3);
|
|
|
|
|
2012-03-10 00:38:48 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void scriptapi_luaentity_activate(lua_State *L, u16 id,
|
2012-09-09 16:12:29 +02:00
|
|
|
const std::string &staticdata, u32 dtime_s)
|
2012-03-10 00:38:48 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
|
2012-03-10 00:38:48 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
|
|
|
int object = lua_gettop(L);
|
|
|
|
|
2011-11-21 10:15:15 +01:00
|
|
|
// Get on_activate function
|
2011-11-12 02:21:40 +01:00
|
|
|
lua_pushvalue(L, object);
|
|
|
|
lua_getfield(L, -1, "on_activate");
|
2011-11-21 10:15:15 +01:00
|
|
|
if(!lua_isnil(L, -1)){
|
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, object); // self
|
|
|
|
lua_pushlstring(L, staticdata.c_str(), staticdata.size());
|
2012-09-09 16:12:29 +02:00
|
|
|
lua_pushinteger(L, dtime_s);
|
|
|
|
// Call with 3 arguments, 0 results
|
|
|
|
if(lua_pcall(L, 3, 0, 0))
|
2012-03-10 00:38:48 +01:00
|
|
|
script_error(L, "error running function on_activate: %s\n",
|
|
|
|
lua_tostring(L, -1));
|
2011-11-21 10:15:15 +01:00
|
|
|
}
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2011-11-11 23:46:05 +01:00
|
|
|
void scriptapi_luaentity_rm(lua_State *L, u16 id)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
|
2011-11-11 18:33:17 +01:00
|
|
|
|
|
|
|
// Get minetest.luaentities table
|
|
|
|
lua_getglobal(L, "minetest");
|
|
|
|
lua_getfield(L, -1, "luaentities");
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
int objectstable = lua_gettop(L);
|
|
|
|
|
|
|
|
// Set luaentities[id] = nil
|
2011-11-11 19:50:09 +01:00
|
|
|
lua_pushnumber(L, id); // Push id
|
2011-11-11 18:33:17 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
lua_settable(L, objectstable);
|
|
|
|
|
|
|
|
lua_pop(L, 2); // pop luaentities, minetest
|
|
|
|
}
|
|
|
|
|
2011-11-21 10:15:15 +01:00
|
|
|
std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
//infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
|
2011-11-21 10:15:15 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
|
|
|
int object = lua_gettop(L);
|
|
|
|
|
|
|
|
// Get get_staticdata function
|
|
|
|
lua_pushvalue(L, object);
|
|
|
|
lua_getfield(L, -1, "get_staticdata");
|
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
return "";
|
|
|
|
|
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, object); // self
|
|
|
|
// Call with 1 arguments, 1 results
|
|
|
|
if(lua_pcall(L, 1, 1, 0))
|
|
|
|
script_error(L, "error running function get_staticdata: %s\n",
|
|
|
|
lua_tostring(L, -1));
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2011-11-21 10:15:15 +01:00
|
|
|
size_t len=0;
|
|
|
|
const char *s = lua_tolstring(L, -1, &len);
|
|
|
|
return std::string(s, len);
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2011-11-12 09:39:44 +01:00
|
|
|
void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
|
2012-03-30 11:51:51 +02:00
|
|
|
ObjectProperties *prop)
|
2011-11-12 02:21:40 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2012-03-11 03:15:45 +01:00
|
|
|
//infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
|
2011-11-12 02:21:40 +01:00
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
|
|
|
//int object = lua_gettop(L);
|
|
|
|
|
2012-03-30 12:26:40 +02:00
|
|
|
// Set default values that differ from ObjectProperties defaults
|
|
|
|
prop->hp_max = 10;
|
2011-11-12 02:21:40 +01:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
/* 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_aabb3f(L, -1, 1.0);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
getstringfield(L, -1, "visual", prop->visual);
|
2012-10-23 23:11:24 +02:00
|
|
|
|
|
|
|
getstringfield(L, -1, "mesh", prop->mesh);
|
2012-03-19 04:25:09 +01:00
|
|
|
|
2012-03-31 12:50:25 +02:00
|
|
|
// Deprecated: read object properties directly
|
2012-03-30 12:26:40 +02:00
|
|
|
read_object_properties(L, -1, prop);
|
2012-03-31 12:50:25 +02:00
|
|
|
|
|
|
|
// Read initial_properties
|
|
|
|
lua_getfield(L, -1, "initial_properties");
|
|
|
|
read_object_properties(L, -1, prop);
|
|
|
|
lua_pop(L, 1);
|
2011-11-12 02:21:40 +01:00
|
|
|
}
|
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2011-11-12 01:25:30 +01:00
|
|
|
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
|
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
2011-11-11 18:33:17 +01:00
|
|
|
int object = lua_gettop(L);
|
2011-11-12 01:25:30 +01:00
|
|
|
// State: object is at top of stack
|
|
|
|
// Get step function
|
|
|
|
lua_getfield(L, -1, "on_step");
|
2011-11-17 15:21:17 +01:00
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
return;
|
2011-11-12 01:25:30 +01:00
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, object); // self
|
|
|
|
lua_pushnumber(L, dtime); // dtime
|
|
|
|
// Call with 2 arguments, 0 results
|
|
|
|
if(lua_pcall(L, 2, 0, 0))
|
2011-11-21 10:15:15 +01:00
|
|
|
script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|
2012-03-04 20:08:03 +01:00
|
|
|
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
|
|
|
|
// tool_capabilities, direction)
|
2011-11-12 16:37:14 +01:00
|
|
|
void scriptapi_luaentity_punch(lua_State *L, u16 id,
|
2012-03-04 20:08:03 +01:00
|
|
|
ServerActiveObject *puncher, float time_from_last_punch,
|
|
|
|
const ToolCapabilities *toolcap, v3f dir)
|
2011-11-11 18:33:17 +01:00
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
2011-11-12 01:25:30 +01:00
|
|
|
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
|
|
|
|
StackUnroller stack_unroller(L);
|
2011-11-11 18:33:17 +01:00
|
|
|
|
2011-11-12 01:25:30 +01:00
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
|
|
|
int object = lua_gettop(L);
|
|
|
|
// State: object is at top of stack
|
2011-11-12 16:37:14 +01:00
|
|
|
// Get function
|
|
|
|
lua_getfield(L, -1, "on_punch");
|
2011-11-17 15:21:17 +01:00
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
return;
|
2011-11-12 16:37:14 +01:00
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, object); // self
|
|
|
|
objectref_get_or_create(L, puncher); // Clicker reference
|
2011-12-02 10:51:41 +01:00
|
|
|
lua_pushnumber(L, time_from_last_punch);
|
2012-03-04 20:08:03 +01:00
|
|
|
push_tool_capabilities(L, *toolcap);
|
|
|
|
push_v3f(L, dir);
|
|
|
|
// Call with 5 arguments, 0 results
|
|
|
|
if(lua_pcall(L, 5, 0, 0))
|
2011-11-12 16:37:14 +01:00
|
|
|
script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls entity:on_rightclick(ObjectRef clicker)
|
|
|
|
void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
|
|
|
|
ServerActiveObject *clicker)
|
|
|
|
{
|
|
|
|
realitycheck(L);
|
|
|
|
assert(lua_checkstack(L, 20));
|
|
|
|
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
|
|
|
|
StackUnroller stack_unroller(L);
|
|
|
|
|
|
|
|
// Get minetest.luaentities[id]
|
|
|
|
luaentity_get(L, id);
|
|
|
|
int object = lua_gettop(L);
|
|
|
|
// State: object is at top of stack
|
|
|
|
// Get function
|
2011-11-12 01:25:30 +01:00
|
|
|
lua_getfield(L, -1, "on_rightclick");
|
2011-11-17 15:21:17 +01:00
|
|
|
if(lua_isnil(L, -1))
|
|
|
|
return;
|
2011-11-12 01:25:30 +01:00
|
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
|
|
lua_pushvalue(L, object); // self
|
2011-11-12 16:37:14 +01:00
|
|
|
objectref_get_or_create(L, clicker); // Clicker reference
|
|
|
|
// Call with 2 arguments, 0 results
|
|
|
|
if(lua_pcall(L, 2, 0, 0))
|
|
|
|
script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
|
2011-11-11 18:33:17 +01:00
|
|
|
}
|
|
|
|
|