]> git.lizzy.rs Git - minetest.git/blob - src/scriptapi.cpp
Scripting WIP
[minetest.git] / src / scriptapi.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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
22 #include <iostream>
23 extern "C" {
24 #include <lua.h>
25 #include <lualib.h>
26 #include <lauxlib.h>
27 }
28
29 #include "log.h"
30 #include "server.h"
31 #include "porting.h"
32 #include "filesys.h"
33 #include "serverobject.h"
34 #include "script.h"
35 //#include "luna.h"
36 #include "luaentity_common.h"
37 #include "content_sao.h" // For LuaEntitySAO
38
39 /*
40 TODO:
41 - Global environment step function
42 - Random node triggers
43 - Object network and client-side stuff
44 - Named node types and dynamic id allocation
45 - LuaNodeMetadata
46         blockdef.has_metadata = true/false
47         - Stores an inventory and stuff in a Settings object
48         meta.inventory_add_list("main")
49         blockdef.on_inventory_modified
50         meta.set("owner", playername)
51         meta.get("owner")
52 */
53
54 static void stackDump(lua_State *L, std::ostream &o)
55 {
56   int i;
57   int top = lua_gettop(L);
58   for (i = 1; i <= top; i++) {  /* repeat for each level */
59         int t = lua_type(L, i);
60         switch (t) {
61
62           case LUA_TSTRING:  /* strings */
63                 o<<"\""<<lua_tostring(L, i)<<"\"";
64                 break;
65
66           case LUA_TBOOLEAN:  /* booleans */
67                 o<<(lua_toboolean(L, i) ? "true" : "false");
68                 break;
69
70           case LUA_TNUMBER:  /* numbers */ {
71                 char buf[10];
72                 snprintf(buf, 10, "%g", lua_tonumber(L, i));
73                 o<<buf;
74                 break; }
75
76           default:  /* other values */
77                 o<<lua_typename(L, t);
78                 break;
79
80         }
81         o<<" ";
82   }
83   o<<std::endl;
84 }
85
86 static void realitycheck(lua_State *L)
87 {
88         int top = lua_gettop(L);
89         if(top >= 30){
90                 dstream<<"Stack is over 30:"<<std::endl;
91                 stackDump(L, dstream);
92                 script_error(L, "Stack is over 30 (reality check)");
93         }
94 }
95
96 class StackUnroller
97 {
98 private:
99         lua_State *m_lua;
100         int m_original_top;
101 public:
102         StackUnroller(lua_State *L):
103                 m_lua(L),
104                 m_original_top(-1)
105         {
106                 m_original_top = lua_gettop(m_lua); // store stack height
107         }
108         ~StackUnroller()
109         {
110                 lua_settop(m_lua, m_original_top); // restore stack height
111         }
112 };
113
114 v3f readFloatPos(lua_State *L, int index)
115 {
116         v3f pos;
117         lua_pushvalue(L, index); // Push pos
118         luaL_checktype(L, -1, LUA_TTABLE);
119         lua_getfield(L, -1, "x");
120         pos.X = lua_tonumber(L, -1);
121         lua_pop(L, 1);
122         lua_getfield(L, -1, "y");
123         pos.Y = lua_tonumber(L, -1);
124         lua_pop(L, 1);
125         lua_getfield(L, -1, "z");
126         pos.Z = lua_tonumber(L, -1);
127         lua_pop(L, 1);
128         lua_pop(L, 1); // Pop pos
129         pos *= BS; // Scale to internal format
130         return pos;
131 }
132
133 /*
134         Global functions
135 */
136
137 // Register new object prototype
138 // register_entity(name, prototype)
139 static int l_register_entity(lua_State *L)
140 {
141         const char *name = luaL_checkstring(L, 1);
142         luaL_checktype(L, 2, LUA_TTABLE);
143         infostream<<"register_entity: "<<name<<std::endl;
144
145         // Get minetest.registered_entities
146         lua_getglobal(L, "minetest");
147         lua_getfield(L, -1, "registered_entities");
148         luaL_checktype(L, -1, LUA_TTABLE);
149         int registered_entities = lua_gettop(L);
150         lua_pushvalue(L, 2); // Object = param 2 -> stack top
151         // registered_entities[name] = object
152         lua_setfield(L, registered_entities, name);
153         
154         // Get registered object to top of stack
155         lua_pushvalue(L, 2);
156         
157         // Set __index to point to itself
158         lua_pushvalue(L, -1);
159         lua_setfield(L, -2, "__index");
160
161         // Set metatable.__index = metatable
162         luaL_getmetatable(L, "minetest.entity");
163         lua_pushvalue(L, -1); // duplicate metatable
164         lua_setfield(L, -2, "__index");
165         // Set object metatable
166         lua_setmetatable(L, -2);
167
168         return 0; /* number of results */
169 }
170
171 static const struct luaL_Reg minetest_f [] = {
172         {"register_entity", l_register_entity},
173         {NULL, NULL}
174 };
175
176 /*
177         LuaEntity functions
178 */
179
180 static const struct luaL_Reg minetest_entity_m [] = {
181         {NULL, NULL}
182 };
183
184 /*
185         Getters for stuff in main tables
186 */
187
188 static void objectref_get(lua_State *L, u16 id)
189 {
190         // Get minetest.object_refs[i]
191         lua_getglobal(L, "minetest");
192         lua_getfield(L, -1, "object_refs");
193         luaL_checktype(L, -1, LUA_TTABLE);
194         lua_pushnumber(L, id);
195         lua_gettable(L, -2);
196         lua_remove(L, -2); // object_refs
197         lua_remove(L, -2); // minetest
198 }
199
200 static void luaentity_get(lua_State *L, u16 id)
201 {
202         // Get minetest.luaentities[i]
203         lua_getglobal(L, "minetest");
204         lua_getfield(L, -1, "luaentities");
205         luaL_checktype(L, -1, LUA_TTABLE);
206         lua_pushnumber(L, id);
207         lua_gettable(L, -2);
208         lua_remove(L, -2); // luaentities
209         lua_remove(L, -2); // minetest
210 }
211
212 /*
213         Reference objects
214 */
215 #define method(class, name) {#name, class::l_##name}
216
217 class EnvRef
218 {
219 private:
220         ServerEnvironment *m_env;
221
222         static const char className[];
223         static const luaL_reg methods[];
224
225         static EnvRef *checkobject(lua_State *L, int narg)
226         {
227                 luaL_checktype(L, narg, LUA_TUSERDATA);
228                 void *ud = luaL_checkudata(L, narg, className);
229                 if(!ud) luaL_typerror(L, narg, className);
230                 return *(EnvRef**)ud;  // unbox pointer
231         }
232         
233         // Exported functions
234
235         // EnvRef:add_node(pos, content)
236         // pos = {x=num, y=num, z=num}
237         // content = number
238         static int l_add_node(lua_State *L)
239         {
240                 infostream<<"EnvRef::l_add_node()"<<std::endl;
241                 EnvRef *o = checkobject(L, 1);
242                 ServerEnvironment *env = o->m_env;
243                 if(env == NULL) return 0;
244                 // pos
245                 v3s16 pos;
246                 lua_pushvalue(L, 2); // Push pos
247                 luaL_checktype(L, -1, LUA_TTABLE);
248                 lua_getfield(L, -1, "x");
249                 pos.X = lua_tonumber(L, -1);
250                 lua_pop(L, 1);
251                 lua_getfield(L, -1, "y");
252                 pos.Y = lua_tonumber(L, -1);
253                 lua_pop(L, 1);
254                 lua_getfield(L, -1, "z");
255                 pos.Z = lua_tonumber(L, -1);
256                 lua_pop(L, 1);
257                 lua_pop(L, 1); // Pop pos
258                 // content
259                 u16 content = 0;
260                 lua_pushvalue(L, 3); // Push content
261                 content = lua_tonumber(L, -1);
262                 lua_pop(L, 1); // Pop content
263                 // Do it
264                 env->getMap().addNodeWithEvent(pos, MapNode(content));
265                 return 0;
266         }
267
268         static int gc_object(lua_State *L) {
269                 EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
270                 delete o;
271                 return 0;
272         }
273
274 public:
275         EnvRef(ServerEnvironment *env):
276                 m_env(env)
277         {
278                 infostream<<"EnvRef created"<<std::endl;
279         }
280
281         ~EnvRef()
282         {
283                 infostream<<"EnvRef destructing"<<std::endl;
284         }
285
286         // Creates an EnvRef and leaves it on top of stack
287         // Not callable from Lua; all references are created on the C side.
288         static void create(lua_State *L, ServerEnvironment *env)
289         {
290                 EnvRef *o = new EnvRef(env);
291                 //infostream<<"EnvRef::create: o="<<o<<std::endl;
292                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
293                 luaL_getmetatable(L, className);
294                 lua_setmetatable(L, -2);
295         }
296
297         static void set_null(lua_State *L)
298         {
299                 EnvRef *o = checkobject(L, -1);
300                 o->m_env = NULL;
301         }
302         
303         static void Register(lua_State *L)
304         {
305                 lua_newtable(L);
306                 int methodtable = lua_gettop(L);
307                 luaL_newmetatable(L, className);
308                 int metatable = lua_gettop(L);
309
310                 lua_pushliteral(L, "__metatable");
311                 lua_pushvalue(L, methodtable);
312                 lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
313
314                 lua_pushliteral(L, "__index");
315                 lua_pushvalue(L, methodtable);
316                 lua_settable(L, metatable);
317
318                 lua_pushliteral(L, "__gc");
319                 lua_pushcfunction(L, gc_object);
320                 lua_settable(L, metatable);
321
322                 lua_pop(L, 1);  // drop metatable
323
324                 luaL_openlib(L, 0, methods, 0);  // fill methodtable
325                 lua_pop(L, 1);  // drop methodtable
326
327                 // Cannot be created from Lua
328                 //lua_register(L, className, create_object);
329         }
330 };
331 const char EnvRef::className[] = "EnvRef";
332 const luaL_reg EnvRef::methods[] = {
333         method(EnvRef, add_node),
334         {0,0}
335 };
336
337 class ObjectRef
338 {
339 private:
340         ServerActiveObject *m_object;
341
342         static const char className[];
343         static const luaL_reg methods[];
344
345         static ObjectRef *checkobject(lua_State *L, int narg)
346         {
347                 luaL_checktype(L, narg, LUA_TUSERDATA);
348                 void *ud = luaL_checkudata(L, narg, className);
349                 if(!ud) luaL_typerror(L, narg, className);
350                 return *(ObjectRef**)ud;  // unbox pointer
351         }
352         
353         static ServerActiveObject* getobject(ObjectRef *ref)
354         {
355                 ServerActiveObject *co = ref->m_object;
356                 return co;
357         }
358         
359         static LuaEntitySAO* getluaobject(ObjectRef *ref)
360         {
361                 ServerActiveObject *obj = getobject(ref);
362                 if(obj == NULL)
363                         return NULL;
364                 if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
365                         return NULL;
366                 return (LuaEntitySAO*)obj;
367         }
368         
369         // Exported functions
370
371         static int l_remove(lua_State *L)
372         {
373                 ObjectRef *ref = checkobject(L, 1);
374                 ServerActiveObject *co = getobject(ref);
375                 if(co == NULL) return 0;
376                 infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
377                 co->m_removed = true;
378                 return 0;
379         }
380
381         static int l_getpos(lua_State *L)
382         {
383                 ObjectRef *ref = checkobject(L, 1);
384                 ServerActiveObject *co = getobject(ref);
385                 if(co == NULL) return 0;
386                 v3f pos = co->getBasePosition() / BS;
387                 lua_newtable(L);
388                 lua_pushnumber(L, pos.X);
389                 lua_setfield(L, -2, "x");
390                 lua_pushnumber(L, pos.Y);
391                 lua_setfield(L, -2, "y");
392                 lua_pushnumber(L, pos.Z);
393                 lua_setfield(L, -2, "z");
394                 return 1;
395         }
396
397         static int l_setpos(lua_State *L)
398         {
399                 ObjectRef *ref = checkobject(L, 1);
400                 //LuaEntitySAO *co = getluaobject(ref);
401                 ServerActiveObject *co = getobject(ref);
402                 if(co == NULL) return 0;
403                 // pos
404                 v3f pos = readFloatPos(L, 2);
405                 // Do it
406                 co->setPos(pos);
407                 return 0;
408         }
409
410         static int l_moveto(lua_State *L)
411         {
412                 ObjectRef *ref = checkobject(L, 1);
413                 //LuaEntitySAO *co = getluaobject(ref);
414                 ServerActiveObject *co = getobject(ref);
415                 if(co == NULL) return 0;
416                 // pos
417                 v3f pos = readFloatPos(L, 2);
418                 // Do it
419                 co->moveTo(pos);
420                 return 0;
421         }
422
423         static int gc_object(lua_State *L) {
424                 //ObjectRef *o = checkobject(L, 1);
425                 ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
426                 //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
427                 delete o;
428                 return 0;
429         }
430
431 public:
432         ObjectRef(ServerActiveObject *object):
433                 m_object(object)
434         {
435                 //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
436         }
437
438         ~ObjectRef()
439         {
440                 /*if(m_object)
441                         infostream<<"ObjectRef destructing for id="
442                                         <<m_object->getId()<<std::endl;
443                 else
444                         infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
445         }
446
447         // Creates an ObjectRef and leaves it on top of stack
448         // Not callable from Lua; all references are created on the C side.
449         static void create(lua_State *L, ServerActiveObject *object)
450         {
451                 ObjectRef *o = new ObjectRef(object);
452                 //infostream<<"ObjectRef::create: o="<<o<<std::endl;
453                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
454                 luaL_getmetatable(L, className);
455                 lua_setmetatable(L, -2);
456         }
457
458         static void set_null(lua_State *L)
459         {
460                 ObjectRef *o = checkobject(L, -1);
461                 o->m_object = NULL;
462         }
463         
464         static void Register(lua_State *L)
465         {
466                 lua_newtable(L);
467                 int methodtable = lua_gettop(L);
468                 luaL_newmetatable(L, className);
469                 int metatable = lua_gettop(L);
470
471                 lua_pushliteral(L, "__metatable");
472                 lua_pushvalue(L, methodtable);
473                 lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
474
475                 lua_pushliteral(L, "__index");
476                 lua_pushvalue(L, methodtable);
477                 lua_settable(L, metatable);
478
479                 lua_pushliteral(L, "__gc");
480                 lua_pushcfunction(L, gc_object);
481                 lua_settable(L, metatable);
482
483                 lua_pop(L, 1);  // drop metatable
484
485                 luaL_openlib(L, 0, methods, 0);  // fill methodtable
486                 lua_pop(L, 1);  // drop methodtable
487
488                 // Cannot be created from Lua
489                 //lua_register(L, className, create_object);
490         }
491 };
492 const char ObjectRef::className[] = "ObjectRef";
493 const luaL_reg ObjectRef::methods[] = {
494         method(ObjectRef, remove),
495         method(ObjectRef, getpos),
496         method(ObjectRef, setpos),
497         method(ObjectRef, moveto),
498         {0,0}
499 };
500
501 /*
502         Main export function
503 */
504
505 void scriptapi_export(lua_State *L, Server *server)
506 {
507         realitycheck(L);
508         assert(lua_checkstack(L, 20));
509         infostream<<"scriptapi_export"<<std::endl;
510         StackUnroller stack_unroller(L);
511         
512         // Register global functions in table minetest
513         lua_newtable(L);
514         luaL_register(L, NULL, minetest_f);
515         lua_setglobal(L, "minetest");
516         
517         // Get the main minetest table
518         lua_getglobal(L, "minetest");
519
520         // Add registered_entities table in minetest
521         lua_newtable(L);
522         lua_setfield(L, -2, "registered_entities");
523
524         // Add object_refs table in minetest
525         lua_newtable(L);
526         lua_setfield(L, -2, "object_refs");
527
528         // Add luaentities table in minetest
529         lua_newtable(L);
530         lua_setfield(L, -2, "luaentities");
531
532         // Create entity prototype
533         luaL_newmetatable(L, "minetest.entity");
534         // metatable.__index = metatable
535         lua_pushvalue(L, -1); // Duplicate metatable
536         lua_setfield(L, -2, "__index");
537         // Put functions in metatable
538         luaL_register(L, NULL, minetest_entity_m);
539         // Put other stuff in metatable
540
541         // Environment C reference
542         EnvRef::Register(L);
543
544         // Object C reference
545         ObjectRef::Register(L);
546 }
547
548 void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
549 {
550         realitycheck(L);
551         assert(lua_checkstack(L, 20));
552         infostream<<"scriptapi_add_environment"<<std::endl;
553         StackUnroller stack_unroller(L);
554
555         // Create EnvRef on stack
556         EnvRef::create(L, env);
557         int envref = lua_gettop(L);
558
559         // minetest.env = envref
560         lua_getglobal(L, "minetest");
561         luaL_checktype(L, -1, LUA_TTABLE);
562         lua_pushvalue(L, envref);
563         lua_setfield(L, -2, "env");
564 }
565
566 // Dump stack top with the dump2 function
567 static void dump2(lua_State *L, const char *name)
568 {
569         // Dump object (debug)
570         lua_getglobal(L, "dump2");
571         luaL_checktype(L, -1, LUA_TFUNCTION);
572         lua_pushvalue(L, -2); // Get previous stack top as first parameter
573         lua_pushstring(L, name);
574         if(lua_pcall(L, 2, 0, 0))
575                 script_error(L, "error: %s\n", lua_tostring(L, -1));
576 }
577
578 /*
579         object_reference
580 */
581
582 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
583 {
584         realitycheck(L);
585         assert(lua_checkstack(L, 20));
586         infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
587         StackUnroller stack_unroller(L);
588
589         // Create object on stack
590         ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
591         int object = lua_gettop(L);
592
593         // Get minetest.object_refs table
594         lua_getglobal(L, "minetest");
595         lua_getfield(L, -1, "object_refs");
596         luaL_checktype(L, -1, LUA_TTABLE);
597         int objectstable = lua_gettop(L);
598         
599         // object_refs[id] = object
600         lua_pushnumber(L, cobj->getId()); // Push id
601         lua_pushvalue(L, object); // Copy object to top of stack
602         lua_settable(L, objectstable);
603 }
604
605 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
606 {
607         realitycheck(L);
608         assert(lua_checkstack(L, 20));
609         infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
610         StackUnroller stack_unroller(L);
611
612         // Get minetest.object_refs table
613         lua_getglobal(L, "minetest");
614         lua_getfield(L, -1, "object_refs");
615         luaL_checktype(L, -1, LUA_TTABLE);
616         int objectstable = lua_gettop(L);
617         
618         // Get object_refs[id]
619         lua_pushnumber(L, cobj->getId()); // Push id
620         lua_gettable(L, objectstable);
621         // Set object reference to NULL
622         ObjectRef::set_null(L);
623         lua_pop(L, 1); // pop object
624
625         // Set object_refs[id] = nil
626         lua_pushnumber(L, cobj->getId()); // Push id
627         lua_pushnil(L);
628         lua_settable(L, objectstable);
629 }
630
631 /*
632         luaentity
633 */
634
635 void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
636                 const char *init_state)
637 {
638         realitycheck(L);
639         assert(lua_checkstack(L, 20));
640         infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
641                         <<name<<"\""<<std::endl;
642         StackUnroller stack_unroller(L);
643         
644         // Create object as a dummy string (TODO: Create properly)
645
646         // Get minetest.registered_entities[name]
647         lua_getglobal(L, "minetest");
648         lua_getfield(L, -1, "registered_entities");
649         luaL_checktype(L, -1, LUA_TTABLE);
650         lua_pushstring(L, name);
651         lua_gettable(L, -2);
652         // Should be a table, which we will use as a prototype
653         luaL_checktype(L, -1, LUA_TTABLE);
654         int prototype_table = lua_gettop(L);
655         //dump2(L, "prototype_table");
656         
657         // Create entity object
658         lua_newtable(L);
659         int object = lua_gettop(L);
660
661         // Set object metatable
662         lua_pushvalue(L, prototype_table);
663         lua_setmetatable(L, -2);
664         
665         // Add object reference
666         // This should be userdata with metatable ObjectRef
667         objectref_get(L, id);
668         luaL_checktype(L, -1, LUA_TUSERDATA);
669         if(!luaL_checkudata(L, -1, "ObjectRef"))
670                 luaL_typerror(L, -1, "ObjectRef");
671         lua_setfield(L, -2, "object");
672
673         // minetest.luaentities[id] = object
674         lua_getglobal(L, "minetest");
675         lua_getfield(L, -1, "luaentities");
676         luaL_checktype(L, -1, LUA_TTABLE);
677         lua_pushnumber(L, id); // Push id
678         lua_pushvalue(L, object); // Copy object to top of stack
679         lua_settable(L, -3);
680         
681         // This callback doesn't really make sense
682         /*// Get on_activate function
683         lua_pushvalue(L, object);
684         lua_getfield(L, -1, "on_activate");
685         luaL_checktype(L, -1, LUA_TFUNCTION);
686         lua_pushvalue(L, object); // self
687         // Call with 1 arguments, 0 results
688         if(lua_pcall(L, 1, 0, 0))
689                 script_error(L, "error running function %s:on_activate: %s\n",
690                                 name, lua_tostring(L, -1));*/
691 }
692
693 void scriptapi_luaentity_rm(lua_State *L, u16 id)
694 {
695         realitycheck(L);
696         assert(lua_checkstack(L, 20));
697         infostream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
698
699         // Get minetest.luaentities table
700         lua_getglobal(L, "minetest");
701         lua_getfield(L, -1, "luaentities");
702         luaL_checktype(L, -1, LUA_TTABLE);
703         int objectstable = lua_gettop(L);
704         
705         // Set luaentities[id] = nil
706         lua_pushnumber(L, id); // Push id
707         lua_pushnil(L);
708         lua_settable(L, objectstable);
709         
710         lua_pop(L, 2); // pop luaentities, minetest
711 }
712
713 std::string scriptapi_luaentity_get_state(lua_State *L, u16 id)
714 {
715         realitycheck(L);
716         assert(lua_checkstack(L, 20));
717         infostream<<"scriptapi_luaentity_get_state: id="<<id<<std::endl;
718         
719         return "";
720 }
721
722 void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
723                 LuaEntityProperties *prop)
724 {
725         realitycheck(L);
726         assert(lua_checkstack(L, 20));
727         infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
728         StackUnroller stack_unroller(L);
729
730         // Get minetest.luaentities[id]
731         luaentity_get(L, id);
732         //int object = lua_gettop(L);
733
734         lua_getfield(L, -1, "physical");
735         if(lua_isboolean(L, -1))
736                 prop->physical = lua_toboolean(L, -1);
737         lua_pop(L, 1);
738         
739         lua_getfield(L, -1, "weight");
740         prop->weight = lua_tonumber(L, -1);
741         lua_pop(L, 1);
742
743         lua_getfield(L, -1, "collisionbox");
744         if(lua_istable(L, -1)){
745                 lua_rawgeti(L, -1, 1);
746                 prop->collisionbox.MinEdge.X = lua_tonumber(L, -1);
747                 lua_pop(L, 1);
748                 lua_rawgeti(L, -1, 2);
749                 prop->collisionbox.MinEdge.Y = lua_tonumber(L, -1);
750                 lua_pop(L, 1);
751                 lua_rawgeti(L, -1, 3);
752                 prop->collisionbox.MinEdge.Z = lua_tonumber(L, -1);
753                 lua_pop(L, 1);
754                 lua_rawgeti(L, -1, 4);
755                 prop->collisionbox.MaxEdge.X = lua_tonumber(L, -1);
756                 lua_pop(L, 1);
757                 lua_rawgeti(L, -1, 5);
758                 prop->collisionbox.MaxEdge.Y = lua_tonumber(L, -1);
759                 lua_pop(L, 1);
760                 lua_rawgeti(L, -1, 6);
761                 prop->collisionbox.MaxEdge.Z = lua_tonumber(L, -1);
762                 lua_pop(L, 1);
763         }
764         lua_pop(L, 1);
765
766         lua_getfield(L, -1, "visual");
767         if(lua_isstring(L, -1))
768                 prop->visual = lua_tostring(L, -1);
769         lua_pop(L, 1);
770         
771         lua_getfield(L, -1, "textures");
772         if(lua_istable(L, -1)){
773                 prop->textures.clear();
774                 int table = lua_gettop(L);
775                 lua_pushnil(L);
776                 while(lua_next(L, table) != 0){
777                         // key at index -2 and value at index -1
778                         if(lua_isstring(L, -1))
779                                 prop->textures.push_back(lua_tostring(L, -1));
780                         else
781                                 prop->textures.push_back("");
782                         // removes value, keeps key for next iteration
783                         lua_pop(L, 1);
784                 }
785         }
786         lua_pop(L, 1);
787 }
788
789 void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
790 {
791         realitycheck(L);
792         assert(lua_checkstack(L, 20));
793         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
794         StackUnroller stack_unroller(L);
795
796         // Get minetest.luaentities[id]
797         luaentity_get(L, id);
798         int object = lua_gettop(L);
799         // State: object is at top of stack
800         // Get step function
801         lua_getfield(L, -1, "on_step");
802         luaL_checktype(L, -1, LUA_TFUNCTION);
803         lua_pushvalue(L, object); // self
804         lua_pushnumber(L, dtime); // dtime
805         // Call with 2 arguments, 0 results
806         if(lua_pcall(L, 2, 0, 0))
807                 script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
808 }
809
810 void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id,
811                 const char *playername)
812 {
813         realitycheck(L);
814         assert(lua_checkstack(L, 20));
815         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
816         StackUnroller stack_unroller(L);
817
818         // Get minetest.luaentities[id]
819         luaentity_get(L, id);
820         int object = lua_gettop(L);
821         // State: object is at top of stack
822         // Get step function
823         lua_getfield(L, -1, "on_rightclick");
824         luaL_checktype(L, -1, LUA_TFUNCTION);
825         lua_pushvalue(L, object); // self
826         // Call with 1 arguments, 0 results
827         if(lua_pcall(L, 1, 0, 0))
828                 script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
829 }
830