]> git.lizzy.rs Git - dragonfireclient.git/blob - src/scriptapi_entity.cpp
Allow spawning particles from the server, from lua
[dragonfireclient.git] / src / scriptapi_entity.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "scriptapi.h"
21 #include "scriptapi_entity.h"
22
23 extern "C" {
24 #include <lauxlib.h>
25 }
26
27 #include "log.h"
28 #include "script.h"
29 #include "scriptapi_types.h"
30 #include "scriptapi_object.h"
31 #include "scriptapi_common.h"
32
33
34 void luaentity_get(lua_State *L, u16 id)
35 {
36         // Get minetest.luaentities[i]
37         lua_getglobal(L, "minetest");
38         lua_getfield(L, -1, "luaentities");
39         luaL_checktype(L, -1, LUA_TTABLE);
40         lua_pushnumber(L, id);
41         lua_gettable(L, -2);
42         lua_remove(L, -2); // luaentities
43         lua_remove(L, -2); // minetest
44 }
45
46 /*
47         luaentity
48 */
49
50 bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
51 {
52         realitycheck(L);
53         assert(lua_checkstack(L, 20));
54         verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
55                         <<name<<"\""<<std::endl;
56         StackUnroller stack_unroller(L);
57
58         // Get minetest.registered_entities[name]
59         lua_getglobal(L, "minetest");
60         lua_getfield(L, -1, "registered_entities");
61         luaL_checktype(L, -1, LUA_TTABLE);
62         lua_pushstring(L, name);
63         lua_gettable(L, -2);
64         // Should be a table, which we will use as a prototype
65         //luaL_checktype(L, -1, LUA_TTABLE);
66         if(lua_type(L, -1) != LUA_TTABLE){
67                 errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
68                 return false;
69         }
70         int prototype_table = lua_gettop(L);
71         //dump2(L, "prototype_table");
72
73         // Create entity object
74         lua_newtable(L);
75         int object = lua_gettop(L);
76
77         // Set object metatable
78         lua_pushvalue(L, prototype_table);
79         lua_setmetatable(L, -2);
80
81         // Add object reference
82         // This should be userdata with metatable ObjectRef
83         objectref_get(L, id);
84         luaL_checktype(L, -1, LUA_TUSERDATA);
85         if(!luaL_checkudata(L, -1, "ObjectRef"))
86                 luaL_typerror(L, -1, "ObjectRef");
87         lua_setfield(L, -2, "object");
88
89         // minetest.luaentities[id] = object
90         lua_getglobal(L, "minetest");
91         lua_getfield(L, -1, "luaentities");
92         luaL_checktype(L, -1, LUA_TTABLE);
93         lua_pushnumber(L, id); // Push id
94         lua_pushvalue(L, object); // Copy object to top of stack
95         lua_settable(L, -3);
96
97         return true;
98 }
99
100 void scriptapi_luaentity_activate(lua_State *L, u16 id,
101                 const std::string &staticdata, u32 dtime_s)
102 {
103         realitycheck(L);
104         assert(lua_checkstack(L, 20));
105         verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
106         StackUnroller stack_unroller(L);
107
108         // Get minetest.luaentities[id]
109         luaentity_get(L, id);
110         int object = lua_gettop(L);
111
112         // Get on_activate function
113         lua_pushvalue(L, object);
114         lua_getfield(L, -1, "on_activate");
115         if(!lua_isnil(L, -1)){
116                 luaL_checktype(L, -1, LUA_TFUNCTION);
117                 lua_pushvalue(L, object); // self
118                 lua_pushlstring(L, staticdata.c_str(), staticdata.size());
119                 lua_pushinteger(L, dtime_s);
120                 // Call with 3 arguments, 0 results
121                 if(lua_pcall(L, 3, 0, 0))
122                         script_error(L, "error running function on_activate: %s\n",
123                                         lua_tostring(L, -1));
124         }
125 }
126
127 void scriptapi_luaentity_rm(lua_State *L, u16 id)
128 {
129         realitycheck(L);
130         assert(lua_checkstack(L, 20));
131         verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
132
133         // Get minetest.luaentities table
134         lua_getglobal(L, "minetest");
135         lua_getfield(L, -1, "luaentities");
136         luaL_checktype(L, -1, LUA_TTABLE);
137         int objectstable = lua_gettop(L);
138
139         // Set luaentities[id] = nil
140         lua_pushnumber(L, id); // Push id
141         lua_pushnil(L);
142         lua_settable(L, objectstable);
143
144         lua_pop(L, 2); // pop luaentities, minetest
145 }
146
147 std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
148 {
149         realitycheck(L);
150         assert(lua_checkstack(L, 20));
151         //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
152         StackUnroller stack_unroller(L);
153
154         // Get minetest.luaentities[id]
155         luaentity_get(L, id);
156         int object = lua_gettop(L);
157
158         // Get get_staticdata function
159         lua_pushvalue(L, object);
160         lua_getfield(L, -1, "get_staticdata");
161         if(lua_isnil(L, -1))
162                 return "";
163
164         luaL_checktype(L, -1, LUA_TFUNCTION);
165         lua_pushvalue(L, object); // self
166         // Call with 1 arguments, 1 results
167         if(lua_pcall(L, 1, 1, 0))
168                 script_error(L, "error running function get_staticdata: %s\n",
169                                 lua_tostring(L, -1));
170
171         size_t len=0;
172         const char *s = lua_tolstring(L, -1, &len);
173         return std::string(s, len);
174 }
175
176 void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
177                 ObjectProperties *prop)
178 {
179         realitycheck(L);
180         assert(lua_checkstack(L, 20));
181         //infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
182         StackUnroller stack_unroller(L);
183
184         // Get minetest.luaentities[id]
185         luaentity_get(L, id);
186         //int object = lua_gettop(L);
187
188         // Set default values that differ from ObjectProperties defaults
189         prop->hp_max = 10;
190
191         /* Read stuff */
192
193         prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
194
195         getboolfield(L, -1, "physical", prop->physical);
196
197         getfloatfield(L, -1, "weight", prop->weight);
198
199         lua_getfield(L, -1, "collisionbox");
200         if(lua_istable(L, -1))
201                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
202         lua_pop(L, 1);
203
204         getstringfield(L, -1, "visual", prop->visual);
205
206         getstringfield(L, -1, "mesh", prop->mesh);
207
208         // Deprecated: read object properties directly
209         read_object_properties(L, -1, prop);
210
211         // Read initial_properties
212         lua_getfield(L, -1, "initial_properties");
213         read_object_properties(L, -1, prop);
214         lua_pop(L, 1);
215 }
216
217 void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
218 {
219         realitycheck(L);
220         assert(lua_checkstack(L, 20));
221         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
222         StackUnroller stack_unroller(L);
223
224         // Get minetest.luaentities[id]
225         luaentity_get(L, id);
226         int object = lua_gettop(L);
227         // State: object is at top of stack
228         // Get step function
229         lua_getfield(L, -1, "on_step");
230         if(lua_isnil(L, -1))
231                 return;
232         luaL_checktype(L, -1, LUA_TFUNCTION);
233         lua_pushvalue(L, object); // self
234         lua_pushnumber(L, dtime); // dtime
235         // Call with 2 arguments, 0 results
236         if(lua_pcall(L, 2, 0, 0))
237                 script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
238 }
239
240 // Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
241 //                       tool_capabilities, direction)
242 void scriptapi_luaentity_punch(lua_State *L, u16 id,
243                 ServerActiveObject *puncher, float time_from_last_punch,
244                 const ToolCapabilities *toolcap, v3f dir)
245 {
246         realitycheck(L);
247         assert(lua_checkstack(L, 20));
248         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
249         StackUnroller stack_unroller(L);
250
251         // Get minetest.luaentities[id]
252         luaentity_get(L, id);
253         int object = lua_gettop(L);
254         // State: object is at top of stack
255         // Get function
256         lua_getfield(L, -1, "on_punch");
257         if(lua_isnil(L, -1))
258                 return;
259         luaL_checktype(L, -1, LUA_TFUNCTION);
260         lua_pushvalue(L, object); // self
261         objectref_get_or_create(L, puncher); // Clicker reference
262         lua_pushnumber(L, time_from_last_punch);
263         push_tool_capabilities(L, *toolcap);
264         push_v3f(L, dir);
265         // Call with 5 arguments, 0 results
266         if(lua_pcall(L, 5, 0, 0))
267                 script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
268 }
269
270 // Calls entity:on_rightclick(ObjectRef clicker)
271 void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
272                 ServerActiveObject *clicker)
273 {
274         realitycheck(L);
275         assert(lua_checkstack(L, 20));
276         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
277         StackUnroller stack_unroller(L);
278
279         // Get minetest.luaentities[id]
280         luaentity_get(L, id);
281         int object = lua_gettop(L);
282         // State: object is at top of stack
283         // Get function
284         lua_getfield(L, -1, "on_rightclick");
285         if(lua_isnil(L, -1))
286                 return;
287         luaL_checktype(L, -1, LUA_TFUNCTION);
288         lua_pushvalue(L, object); // self
289         objectref_get_or_create(L, clicker); // Clicker reference
290         // Call with 2 arguments, 0 results
291         if(lua_pcall(L, 2, 0, 0))
292                 script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
293 }