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