aboutsummaryrefslogtreecommitdiff
path: root/src/script/cpp_api/s_base.h
blob: f52474f00c75bada14ec9a8d21089b16eaa87f38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
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.
*/

#ifndef S_BASE_H_
#define S_BASE_H_

#include <iostream>
#include <string>

extern "C" {
#include <lua.h>
}

#include "irrlichttypes.h"
#include "threads.h"
#include "threading/mutex.h"
#include "threading/mutex_auto_lock.h"
#include "common/c_types.h"
#include "common/c_internal.h"

#define SCRIPTAPI_LOCK_DEBUG
#define SCRIPTAPI_DEBUG

// MUST be an invalid mod name so that mods can't
// use that name to bypass security!
#define BUILTIN_MOD_NAME "*builtin*"

#define PCALL_RES(RES) do {                 \
	int result_ = (RES);                    \
	if (result_ != 0) {                     \
		scriptError(result_, __FUNCTION__); \
	}                                       \
} while (0)

#define runCallbacks(nargs, mode) \
	runCallbacksRaw((nargs), (mode), __FUNCTION__)

#define setOriginFromTable(index) \
	setOriginFromTableRaw(index, __FUNCTION__)

class Server;
class Environment;
class GUIEngine;
class ServerActiveObject;

class ScriptApiBase {
public:
	ScriptApiBase();
	virtual ~ScriptApiBase();

	// These throw a ModError on failure
	void loadMod(const std::string &script_path, const std::string &mod_name);
	void loadScript(const std::string &script_path);

	void runCallbacksRaw(int nargs,
		RunCallbacksMode mode, const char *fxn);

	/* object */
	void addObjectReference(ServerActiveObject *cobj);
	void removeObjectReference(ServerActiveObject *cobj);

	Server* getServer() { return m_server; }

	std::string getOrigin() { return m_last_run_mod; }
	void setOriginDirect(const char *origin);
	void setOriginFromTableRaw(int index, const char *fxn);

protected:
	friend class LuaABM;
	friend class LuaLBM;
	friend class InvRef;
	friend class ObjectRef;
	friend class NodeMetaRef;
	friend class ModApiBase;
	friend class ModApiEnvMod;
	friend class LuaVoxelManip;

	lua_State* getStack()
		{ return m_luastack; }

	void realityCheck();
	void scriptError(int result, const char *fxn);
	void stackDump(std::ostream &o);

	void setServer(Server* server) { m_server = server; }

	Environment* getEnv() { return m_environment; }
	void setEnv(Environment* env) { m_environment = env; }

	GUIEngine* getGuiEngine() { return m_guiengine; }
	void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }

	void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
	void objectrefGet(lua_State *L, u16 id);

	RecursiveMutex  m_luastackmutex;
	std::string     m_last_run_mod;
	bool            m_secure;
#ifdef SCRIPTAPI_LOCK_DEBUG
	int             m_lock_recursion_count;
	threadid_t      m_owning_thread;
#endif

private:
	lua_State*      m_luastack;

	Server*         m_server;
	Environment*    m_environment;
	GUIEngine*      m_guiengine;
};

#endif /* S_BASE_H_ */
"facedir", groups = { falling_node = 1, dig_immediate = 3 }, }) -- Same as falling node, but will stop falling on top of liquids minetest.register_node("testnodes:falling_float", { description = S("Falling+Floating Node"), groups = { falling_node = 1, float = 1, dig_immediate = 3 }, tiles = { "testnodes_node.png", "testnodes_node.png", "testnodes_node_falling.png", }, color = "cyan", }) -- This node attaches to the floor and drops as item -- when the floor is gone. minetest.register_node("testnodes:attached", { description = S("Floor-Attached Node"), tiles = { "testnodes_attached_top.png", "testnodes_attached_bottom.png", "testnodes_attached_side.png", }, groups = { attached_node = 1, dig_immediate = 3 }, }) -- This node attaches to the side of a node and drops as item -- when the node it attaches to is gone. minetest.register_node("testnodes:attached_wallmounted", { description = S("Wallmounted Attached Node"), paramtype2 = "wallmounted", tiles = { "testnodes_attachedw_top.png", "testnodes_attachedw_bottom.png", "testnodes_attachedw_side.png", }, groups = { attached_node = 1, dig_immediate = 3 }, }) -- Jump disabled minetest.register_node("testnodes:nojump", { description = S("Non-jumping Node"), groups = {disable_jump=1, dig_immediate=3}, tiles = {"testnodes_nojump_top.png", "testnodes_nojump_side.png"}, }) -- Jump disabled plant minetest.register_node("testnodes:nojump_walkable", { description = S("Non-jumping Plant Node"), drawtype = "plantlike", groups = {disable_jump=1, dig_immediate=3}, walkable = false, tiles = {"testnodes_nojump_top.png"}, }) -- Climbable up and down with jump and sneak keys minetest.register_node("testnodes:climbable", { description = S("Climbable Node"), climbable = true, walkable = false, paramtype = "light", sunlight_propagates = true, is_ground_content = false, tiles ={"testnodes_climbable_side.png"}, drawtype = "glasslike", groups = {dig_immediate=3}, }) -- Climbable only downwards with sneak key minetest.register_node("testnodes:climbable_nojump", { description = S("Downwards-climbable Node"), climbable = true, walkable = false, groups = {disable_jump=1, dig_immediate=3}, drawtype = "glasslike", tiles ={"testnodes_climbable_nojump_side.png"}, paramtype = "light", sunlight_propagates = true, }) -- A liquid in which you can't rise minetest.register_node("testnodes:liquid_nojump", { description = S("Non-jumping Liquid Source Node"), liquidtype = "source", liquid_range = 1, liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquidflowing_nojump", liquid_alternative_source = "testnodes:liquid_nojump", liquid_renewable = false, groups = {disable_jump=1, dig_immediate=3}, walkable = false, drawtype = "liquid", tiles = {"testnodes_liquidsource.png^[colorize:#FF0000:127"}, special_tiles = { {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = false}, {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = true}, }, use_texture_alpha = "blend", paramtype = "light", pointable = false, liquids_pointable = true, buildable_to = true, is_ground_content = false, post_effect_color = {a = 70, r = 255, g = 0, b = 200}, }) -- A liquid in which you can't rise (flowing variant) minetest.register_node("testnodes:liquidflowing_nojump", { description = S("Non-jumping Flowing Liquid Node"), liquidtype = "flowing", liquid_range = 1, liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquidflowing_nojump", liquid_alternative_source = "testnodes:liquid_nojump", liquid_renewable = false, groups = {disable_jump=1, dig_immediate=3}, walkable = false, drawtype = "flowingliquid", tiles = {"testnodes_liquidflowing.png^[colorize:#FF0000:127"}, special_tiles = { {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false}, {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false}, }, use_texture_alpha = "blend", paramtype = "light", paramtype2 = "flowingliquid", pointable = false, liquids_pointable = true, buildable_to = true, is_ground_content = false, post_effect_color = {a = 70, r = 255, g = 0, b = 200}, }) -- A liquid which doesn't have liquid movement physics (source variant) minetest.register_node("testnodes:liquid_noswim", { description = S("No-swim Liquid Source Node"), liquidtype = "source", liquid_range = 1, liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquidflowing_noswim", liquid_alternative_source = "testnodes:liquid_noswim", liquid_renewable = false, liquid_move_physics = false, groups = {dig_immediate=3}, walkable = false, drawtype = "liquid", tiles = {"testnodes_liquidsource.png^[colorize:#FF00FF:127"}, special_tiles = { {name = "testnodes_liquidsource.png^[colorize:#FF00FF:127", backface_culling = false}, {name = "testnodes_liquidsource.png^[colorize:#FF00FF:127", backface_culling = true}, }, use_texture_alpha = "blend", paramtype = "light", pointable = false, liquids_pointable = true, buildable_to = true, is_ground_content = false, post_effect_color = {a = 70, r = 255, g = 200, b = 200}, }) -- A liquid which doen't have liquid movement physics (flowing variant) minetest.register_node("testnodes:liquidflowing_noswim", { description = S("No-swim Flowing Liquid Node"), liquidtype = "flowing", liquid_range = 1, liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquidflowing_noswim", liquid_alternative_source = "testnodes:liquid_noswim", liquid_renewable = false, liquid_move_physics = false, groups = {dig_immediate=3}, walkable = false, drawtype = "flowingliquid", tiles = {"testnodes_liquidflowing.png^[colorize:#FF00FF:127"}, special_tiles = { {name = "testnodes_liquidflowing.png^[colorize:#FF00FF:127", backface_culling = false}, {name = "testnodes_liquidflowing.png^[colorize:#FF00FF:127", backface_culling = false}, }, use_texture_alpha = "blend", paramtype = "light", paramtype2 = "flowingliquid", pointable = false, liquids_pointable = true, buildable_to = true, is_ground_content = false, post_effect_color = {a = 70, r = 255, g = 200, b = 200}, }) -- Nodes that modify fall damage (various damage modifiers) for i=-100, 100, 25 do if i ~= 0 then local subname, descnum if i < 0 then subname = "m"..math.abs(i) descnum = tostring(i) else subname = tostring(i) descnum = S("+@1", i) end local tex, color, desc if i > 0 then local val = math.floor((i/100)*255) tex = "testnodes_fall_damage_plus.png" color = { b=0, g=255-val, r=255, a=255 } desc = S("Fall Damage Node (+@1%)", i) else tex = "testnodes_fall_damage_minus.png" if i == -100 then color = { r=0, b=0, g=255, a=255 } else local val = math.floor((math.abs(i)/100)*255) color = { r=0, b=255, g=255-val, a=255 } end desc = S("Fall Damage Node (-@1%)", math.abs(i)) end minetest.register_node("testnodes:damage"..subname, { description = desc, groups = {fall_damage_add_percent=i, dig_immediate=3}, tiles = { tex }, is_ground_content = false, color = color, }) end end -- Bouncy nodes (various bounce levels) for i=-140, 180, 20 do local val = math.floor(((i-20)/200)*255) minetest.register_node(("testnodes:bouncy"..i):gsub("-","NEG"), { description = S("Bouncy Node (@1%)", i), groups = {bouncy=i, dig_immediate=3}, tiles ={"testnodes_bouncy.png"}, is_ground_content = false, color = { r=255, g=255-val, b=val, a=255 }, }) end -- Slippery nodes (various slippery levels) for i=1, 5 do minetest.register_node("testnodes:slippery"..i, { description = S("Slippery Node (@1)", i), tiles ={"testnodes_slippery.png"}, is_ground_content = false, groups = {slippery=i, dig_immediate=3}, color = { r=0, g=255, b=math.floor((i/5)*255), a=255 }, }) end -- Move resistance nodes (various resistance levels) for r=0, 7 do if r > 0 then minetest.register_node("testnodes:move_resistance"..r, { description = S("Move-resistant Node (@1)", r), walkable = false, move_resistance = r, drawtype = "glasslike", paramtype = "light", sunlight_propagates = true, tiles = { "testnodes_move_resistance.png" }, is_ground_content = false, groups = { dig_immediate = 3 }, color = { b = 0, g = 255, r = math.floor((r/7)*255), a = 255 }, }) end minetest.register_node("testnodes:move_resistance_liquidlike"..r, { description = S("Move-resistant Node, liquidlike (@1)", r), walkable = false, move_resistance = r, liquid_move_physics = true, drawtype = "glasslike", paramtype = "light", sunlight_propagates = true, tiles = { "testnodes_move_resistance.png" }, is_ground_content = false, groups = { dig_immediate = 3 }, color = { b = 255, g = 0, r = math.floor((r/7)*255), a = 255 }, }) end minetest.register_node("testnodes:climbable_move_resistance_4", { description = S("Climbable Move-resistant Node (4)"), walkable = false, climbable = true, move_resistance = 4, drawtype = "glasslike", paramtype = "light", sunlight_propagates = true, tiles = {"testnodes_climbable_resistance_side.png"}, is_ground_content = false, groups = { dig_immediate = 3 }, }) -- By placing something on the node, the node itself will be replaced minetest.register_node("testnodes:buildable_to", { description = S("Replacable Node"), buildable_to = true, tiles = {"testnodes_buildable_to.png"}, is_ground_content = false, groups = {dig_immediate=3}, }) -- Nodes that deal damage to players that are inside them. -- Negative damage nodes should heal. for d=-3,3 do if d ~= 0 then local sub, tile if d > 0 then sub = tostring(d) tile = "testnodes_damage.png" else sub = "m" .. tostring(math.abs(d)) tile = "testnodes_damage_neg.png" end if math.abs(d) == 2 then tile = tile .. "^[colorize:#000000:70" elseif math.abs(d) == 3 then tile = tile .. "^[colorize:#000000:140" end minetest.register_node("testnodes:damage_"..sub, { description = S("Damage Node (@1 damage per second)", d), damage_per_second = d, walkable = false, is_ground_content = false, drawtype = "allfaces", paramtype = "light", sunlight_propagates = true, tiles = { tile }, groups = {dig_immediate=3}, }) end end -- Causes drowning damage minetest.register_node("testnodes:drowning_1", { description = S("Drowning Node (@1 damage)", 1), drowning = 1, walkable = false, is_ground_content = false, drawtype = "allfaces", paramtype = "light", sunlight_propagates = true, tiles = { "testnodes_drowning.png" }, groups = {dig_immediate=3}, })