forked from Mirrorlandia_minetest/minetest
312 lines
8.0 KiB
C++
312 lines
8.0 KiB
C++
/*
|
|
Minetest
|
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "scriptapi.h"
|
|
#include "scriptapi_common.h"
|
|
|
|
extern "C" {
|
|
#include "lauxlib.h"
|
|
}
|
|
|
|
#include "script.h"
|
|
#include "scriptapi_types.h"
|
|
#include "scriptapi_object.h"
|
|
|
|
|
|
Server* get_server(lua_State *L)
|
|
{
|
|
// Get server from registry
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
|
|
Server *server = (Server*)lua_touserdata(L, -1);
|
|
lua_pop(L, 1);
|
|
return server;
|
|
}
|
|
|
|
ServerEnvironment* get_env(lua_State *L)
|
|
{
|
|
// Get environment from registry
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
|
|
ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
|
|
lua_pop(L, 1);
|
|
return env;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
ToolCapabilities
|
|
*/
|
|
|
|
ToolCapabilities read_tool_capabilities(
|
|
lua_State *L, int table)
|
|
{
|
|
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);
|
|
getintfield(L, table_groupcap, "uses", groupcap.uses);
|
|
// DEPRECATED: maxwear
|
|
float maxwear = 0;
|
|
if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
|
|
if(maxwear != 0)
|
|
groupcap.uses = 1.0/maxwear;
|
|
else
|
|
groupcap.uses = 0;
|
|
infostream<<script_get_backtrace(L)<<std::endl;
|
|
infostream<<"WARNING: field \"maxwear\" is deprecated; "
|
|
<<"should replace with uses=1/maxwear"<<std::endl;
|
|
}
|
|
// Read "times" table
|
|
lua_getfield(L, table_groupcap, "times");
|
|
if(lua_istable(L, -1)){
|
|
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);
|
|
lua_getfield(L, table, "damage_groups");
|
|
if(lua_istable(L, -1)){
|
|
int table_damage_groups = lua_gettop(L);
|
|
lua_pushnil(L);
|
|
while(lua_next(L, table_damage_groups) != 0){
|
|
// key at index -2 and value at index -1
|
|
std::string groupname = luaL_checkstring(L, -2);
|
|
u16 value = luaL_checkinteger(L, -1);
|
|
toolcap.damageGroups[groupname] = value;
|
|
// removes value, keeps key for next iteration
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
return toolcap;
|
|
}
|
|
|
|
void set_tool_capabilities(lua_State *L, int table,
|
|
const ToolCapabilities &toolcap)
|
|
{
|
|
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);
|
|
setintfield(L, -1, "uses", groupcap.uses);
|
|
// Insert groupcap table into groupcaps table
|
|
lua_setfield(L, -2, name.c_str());
|
|
}
|
|
// Set groupcaps table
|
|
lua_setfield(L, -2, "groupcaps");
|
|
//Create damage_groups table
|
|
lua_newtable(L);
|
|
// For each damage group
|
|
for(std::map<std::string, s16>::const_iterator
|
|
i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
|
|
// Create damage group table
|
|
lua_pushinteger(L, i->second);
|
|
lua_setfield(L, -2, i->first.c_str());
|
|
}
|
|
lua_setfield(L, -2, "damage_groups");
|
|
}
|
|
|
|
void push_tool_capabilities(lua_State *L,
|
|
const ToolCapabilities &prop)
|
|
{
|
|
lua_newtable(L);
|
|
set_tool_capabilities(L, -1, prop);
|
|
}
|
|
|
|
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)");
|
|
}
|
|
}
|
|
|
|
/*
|
|
PointedThing
|
|
*/
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
// 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))
|
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
/*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;
|
|
}*/
|
|
|
|
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;
|
|
}
|