]> git.lizzy.rs Git - minetest.git/blob - src/scriptapi.cpp
Update TODO list in scriptapi.cpp
[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 #include "tooldef.h"
39
40 /*
41 TODO:
42 - Node definition
43 - Random node triggers
44 - Object visual client-side stuff
45         - Blink effect
46         - Spritesheets and animation
47 - Named node types and dynamic id allocation per MapBlock
48 - LuaNodeMetadata
49         blockdef.has_metadata = true/false
50         - Stores an inventory and stuff in a Settings object
51         meta.inventory_add_list("main")
52         blockdef.on_inventory_modified
53         meta.set("owner", playername)
54         meta.get("owner")
55 - Item definition
56 */
57
58 static void stackDump(lua_State *L, std::ostream &o)
59 {
60   int i;
61   int top = lua_gettop(L);
62   for (i = 1; i <= top; i++) {  /* repeat for each level */
63         int t = lua_type(L, i);
64         switch (t) {
65
66           case LUA_TSTRING:  /* strings */
67                 o<<"\""<<lua_tostring(L, i)<<"\"";
68                 break;
69
70           case LUA_TBOOLEAN:  /* booleans */
71                 o<<(lua_toboolean(L, i) ? "true" : "false");
72                 break;
73
74           case LUA_TNUMBER:  /* numbers */ {
75                 char buf[10];
76                 snprintf(buf, 10, "%g", lua_tonumber(L, i));
77                 o<<buf;
78                 break; }
79
80           default:  /* other values */
81                 o<<lua_typename(L, t);
82                 break;
83
84         }
85         o<<" ";
86   }
87   o<<std::endl;
88 }
89
90 static void realitycheck(lua_State *L)
91 {
92         int top = lua_gettop(L);
93         if(top >= 30){
94                 dstream<<"Stack is over 30:"<<std::endl;
95                 stackDump(L, dstream);
96                 script_error(L, "Stack is over 30 (reality check)");
97         }
98 }
99
100 class StackUnroller
101 {
102 private:
103         lua_State *m_lua;
104         int m_original_top;
105 public:
106         StackUnroller(lua_State *L):
107                 m_lua(L),
108                 m_original_top(-1)
109         {
110                 m_original_top = lua_gettop(m_lua); // store stack height
111         }
112         ~StackUnroller()
113         {
114                 lua_settop(m_lua, m_original_top); // restore stack height
115         }
116 };
117
118 v3f readFloatPos(lua_State *L, int index)
119 {
120         v3f pos;
121         lua_pushvalue(L, index); // Push pos
122         luaL_checktype(L, -1, LUA_TTABLE);
123         lua_getfield(L, -1, "x");
124         pos.X = lua_tonumber(L, -1);
125         lua_pop(L, 1);
126         lua_getfield(L, -1, "y");
127         pos.Y = lua_tonumber(L, -1);
128         lua_pop(L, 1);
129         lua_getfield(L, -1, "z");
130         pos.Z = lua_tonumber(L, -1);
131         lua_pop(L, 1);
132         lua_pop(L, 1); // Pop pos
133         pos *= BS; // Scale to internal format
134         return pos;
135 }
136
137 /*
138         Global functions
139 */
140
141 // Register new object prototype
142 // register_entity(name, prototype)
143 static int l_register_entity(lua_State *L)
144 {
145         const char *name = luaL_checkstring(L, 1);
146         infostream<<"register_entity: "<<name<<std::endl;
147         luaL_checktype(L, 2, LUA_TTABLE);
148
149         // Get minetest.registered_entities
150         lua_getglobal(L, "minetest");
151         lua_getfield(L, -1, "registered_entities");
152         luaL_checktype(L, -1, LUA_TTABLE);
153         int registered_entities = lua_gettop(L);
154         lua_pushvalue(L, 2); // Object = param 2 -> stack top
155         // registered_entities[name] = object
156         lua_setfield(L, registered_entities, name);
157         
158         // Get registered object to top of stack
159         lua_pushvalue(L, 2);
160         
161         // Set __index to point to itself
162         lua_pushvalue(L, -1);
163         lua_setfield(L, -2, "__index");
164
165         // Set metatable.__index = metatable
166         luaL_getmetatable(L, "minetest.entity");
167         lua_pushvalue(L, -1); // duplicate metatable
168         lua_setfield(L, -2, "__index");
169         // Set object metatable
170         lua_setmetatable(L, -2);
171
172         return 0; /* number of results */
173 }
174
175 // Register a global step function
176 // register_globalstep(function)
177 static int l_register_globalstep(lua_State *L)
178 {
179         luaL_checktype(L, 1, LUA_TFUNCTION);
180         infostream<<"register_globalstep"<<std::endl;
181
182         lua_getglobal(L, "table");
183         lua_getfield(L, -1, "insert");
184         int table_insert = lua_gettop(L);
185         // Get minetest.registered_globalsteps
186         lua_getglobal(L, "minetest");
187         lua_getfield(L, -1, "registered_globalsteps");
188         luaL_checktype(L, -1, LUA_TTABLE);
189         int registered_globalsteps = lua_gettop(L);
190         // table.insert(registered_globalsteps, func)
191         lua_pushvalue(L, table_insert);
192         lua_pushvalue(L, registered_globalsteps);
193         lua_pushvalue(L, 1); // push function from argument 1
194         // Call insert
195         if(lua_pcall(L, 2, 0, 0))
196                 script_error(L, "error: %s\n", lua_tostring(L, -1));
197
198         return 0; /* number of results */
199 }
200
201 #if 0
202 // Clear all registered tools
203 // deregister_tools()
204 static int l_deregister_tools(lua_State *L)
205 {
206         infostream<<"deregister_tools"<<std::endl;
207
208         // Get server from registry
209         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
210         Server *server = (Server*)lua_touserdata(L, -1);
211         // And get the writable tool definition manager from the server
212         IWritableToolDefManager *tooldef =
213                         server->getWritableToolDefManager();
214         
215         tooldef->clear();
216
217         return 0; /* number of results */
218 }
219 #endif
220
221 // register_tool(name, {lots of stuff})
222 static int l_register_tool(lua_State *L)
223 {
224         const char *name = luaL_checkstring(L, 1);
225         infostream<<"register_tool: "<<name<<std::endl;
226         luaL_checktype(L, 2, LUA_TTABLE);
227
228         // Get server from registry
229         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
230         Server *server = (Server*)lua_touserdata(L, -1);
231         // And get the writable tool definition manager from the server
232         IWritableToolDefManager *tooldef =
233                         server->getWritableToolDefManager();
234         
235         int table = 2;
236         
237         ToolDefinition def;
238
239         lua_getfield(L, table, "image");
240         if(lua_isstring(L, -1))
241                 def.imagename = lua_tostring(L, -1);
242         lua_pop(L, 1);
243         
244         lua_getfield(L, table, "basetime");
245         def.properties.basetime = lua_tonumber(L, -1);
246         lua_pop(L, 1);
247
248         lua_getfield(L, table, "dt_weight");
249         def.properties.dt_weight = lua_tonumber(L, -1);
250         lua_pop(L, 1);
251
252         lua_getfield(L, table, "dt_crackiness");
253         def.properties.dt_crackiness = lua_tonumber(L, -1);
254         lua_pop(L, 1);
255
256         lua_getfield(L, table, "dt_crumbliness");
257         def.properties.dt_crumbliness = lua_tonumber(L, -1);
258         lua_pop(L, 1);
259
260         lua_getfield(L, table, "dt_cuttability");
261         def.properties.dt_cuttability = lua_tonumber(L, -1);
262         lua_pop(L, 1);
263
264         lua_getfield(L, table, "basedurability");
265         def.properties.basedurability = lua_tonumber(L, -1);
266         lua_pop(L, 1);
267
268         lua_getfield(L, table, "dd_weight");
269         def.properties.dd_weight = lua_tonumber(L, -1);
270         lua_pop(L, 1);
271
272         lua_getfield(L, table, "dd_crackiness");
273         def.properties.dd_crackiness = lua_tonumber(L, -1);
274         lua_pop(L, 1);
275
276         lua_getfield(L, table, "dd_crumbliness");
277         def.properties.dd_crumbliness = lua_tonumber(L, -1);
278         lua_pop(L, 1);
279
280         lua_getfield(L, table, "dd_cuttability");
281         def.properties.dd_cuttability = lua_tonumber(L, -1);
282         lua_pop(L, 1);
283
284         tooldef->registerTool(name, def);
285
286         return 0; /* number of results */
287 }
288
289 static const struct luaL_Reg minetest_f [] = {
290         {"register_entity", l_register_entity},
291         {"register_globalstep", l_register_globalstep},
292         //{"deregister_tools", l_deregister_tools},
293         {"register_tool", l_register_tool},
294         {NULL, NULL}
295 };
296
297 /*
298         LuaEntity functions
299 */
300
301 static const struct luaL_Reg minetest_entity_m [] = {
302         {NULL, NULL}
303 };
304
305 /*
306         Getters for stuff in main tables
307 */
308
309 static void objectref_get(lua_State *L, u16 id)
310 {
311         // Get minetest.object_refs[i]
312         lua_getglobal(L, "minetest");
313         lua_getfield(L, -1, "object_refs");
314         luaL_checktype(L, -1, LUA_TTABLE);
315         lua_pushnumber(L, id);
316         lua_gettable(L, -2);
317         lua_remove(L, -2); // object_refs
318         lua_remove(L, -2); // minetest
319 }
320
321 static void luaentity_get(lua_State *L, u16 id)
322 {
323         // Get minetest.luaentities[i]
324         lua_getglobal(L, "minetest");
325         lua_getfield(L, -1, "luaentities");
326         luaL_checktype(L, -1, LUA_TTABLE);
327         lua_pushnumber(L, id);
328         lua_gettable(L, -2);
329         lua_remove(L, -2); // luaentities
330         lua_remove(L, -2); // minetest
331 }
332
333 /*
334         Reference objects
335 */
336 #define method(class, name) {#name, class::l_##name}
337
338 class EnvRef
339 {
340 private:
341         ServerEnvironment *m_env;
342
343         static const char className[];
344         static const luaL_reg methods[];
345
346         static EnvRef *checkobject(lua_State *L, int narg)
347         {
348                 luaL_checktype(L, narg, LUA_TUSERDATA);
349                 void *ud = luaL_checkudata(L, narg, className);
350                 if(!ud) luaL_typerror(L, narg, className);
351                 return *(EnvRef**)ud;  // unbox pointer
352         }
353         
354         // Exported functions
355
356         // EnvRef:add_node(pos, content)
357         // pos = {x=num, y=num, z=num}
358         // content = number
359         static int l_add_node(lua_State *L)
360         {
361                 infostream<<"EnvRef::l_add_node()"<<std::endl;
362                 EnvRef *o = checkobject(L, 1);
363                 ServerEnvironment *env = o->m_env;
364                 if(env == NULL) return 0;
365                 // pos
366                 v3s16 pos;
367                 lua_pushvalue(L, 2); // Push pos
368                 luaL_checktype(L, -1, LUA_TTABLE);
369                 lua_getfield(L, -1, "x");
370                 pos.X = lua_tonumber(L, -1);
371                 lua_pop(L, 1);
372                 lua_getfield(L, -1, "y");
373                 pos.Y = lua_tonumber(L, -1);
374                 lua_pop(L, 1);
375                 lua_getfield(L, -1, "z");
376                 pos.Z = lua_tonumber(L, -1);
377                 lua_pop(L, 1);
378                 lua_pop(L, 1); // Pop pos
379                 // content
380                 u16 content = 0;
381                 lua_pushvalue(L, 3); // Push content
382                 content = lua_tonumber(L, -1);
383                 lua_pop(L, 1); // Pop content
384                 // Do it
385                 env->getMap().addNodeWithEvent(pos, MapNode(content));
386                 return 0;
387         }
388
389         static int gc_object(lua_State *L) {
390                 EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
391                 delete o;
392                 return 0;
393         }
394
395 public:
396         EnvRef(ServerEnvironment *env):
397                 m_env(env)
398         {
399                 infostream<<"EnvRef created"<<std::endl;
400         }
401
402         ~EnvRef()
403         {
404                 infostream<<"EnvRef destructing"<<std::endl;
405         }
406
407         // Creates an EnvRef and leaves it on top of stack
408         // Not callable from Lua; all references are created on the C side.
409         static void create(lua_State *L, ServerEnvironment *env)
410         {
411                 EnvRef *o = new EnvRef(env);
412                 //infostream<<"EnvRef::create: o="<<o<<std::endl;
413                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
414                 luaL_getmetatable(L, className);
415                 lua_setmetatable(L, -2);
416         }
417
418         static void set_null(lua_State *L)
419         {
420                 EnvRef *o = checkobject(L, -1);
421                 o->m_env = NULL;
422         }
423         
424         static void Register(lua_State *L)
425         {
426                 lua_newtable(L);
427                 int methodtable = lua_gettop(L);
428                 luaL_newmetatable(L, className);
429                 int metatable = lua_gettop(L);
430
431                 lua_pushliteral(L, "__metatable");
432                 lua_pushvalue(L, methodtable);
433                 lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
434
435                 lua_pushliteral(L, "__index");
436                 lua_pushvalue(L, methodtable);
437                 lua_settable(L, metatable);
438
439                 lua_pushliteral(L, "__gc");
440                 lua_pushcfunction(L, gc_object);
441                 lua_settable(L, metatable);
442
443                 lua_pop(L, 1);  // drop metatable
444
445                 luaL_openlib(L, 0, methods, 0);  // fill methodtable
446                 lua_pop(L, 1);  // drop methodtable
447
448                 // Cannot be created from Lua
449                 //lua_register(L, className, create_object);
450         }
451 };
452 const char EnvRef::className[] = "EnvRef";
453 const luaL_reg EnvRef::methods[] = {
454         method(EnvRef, add_node),
455         {0,0}
456 };
457
458 class ObjectRef
459 {
460 private:
461         ServerActiveObject *m_object;
462
463         static const char className[];
464         static const luaL_reg methods[];
465
466         static ObjectRef *checkobject(lua_State *L, int narg)
467         {
468                 luaL_checktype(L, narg, LUA_TUSERDATA);
469                 void *ud = luaL_checkudata(L, narg, className);
470                 if(!ud) luaL_typerror(L, narg, className);
471                 return *(ObjectRef**)ud;  // unbox pointer
472         }
473         
474         static ServerActiveObject* getobject(ObjectRef *ref)
475         {
476                 ServerActiveObject *co = ref->m_object;
477                 return co;
478         }
479         
480         static LuaEntitySAO* getluaobject(ObjectRef *ref)
481         {
482                 ServerActiveObject *obj = getobject(ref);
483                 if(obj == NULL)
484                         return NULL;
485                 if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
486                         return NULL;
487                 return (LuaEntitySAO*)obj;
488         }
489         
490         // Exported functions
491         
492         // garbage collector
493         static int gc_object(lua_State *L) {
494                 ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
495                 //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
496                 delete o;
497                 return 0;
498         }
499
500         // remove(self)
501         static int l_remove(lua_State *L)
502         {
503                 ObjectRef *ref = checkobject(L, 1);
504                 ServerActiveObject *co = getobject(ref);
505                 if(co == NULL) return 0;
506                 infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
507                 co->m_removed = true;
508                 return 0;
509         }
510         
511         // getpos(self)
512         // returns: {x=num, y=num, z=num}
513         static int l_getpos(lua_State *L)
514         {
515                 ObjectRef *ref = checkobject(L, 1);
516                 ServerActiveObject *co = getobject(ref);
517                 if(co == NULL) return 0;
518                 v3f pos = co->getBasePosition() / BS;
519                 lua_newtable(L);
520                 lua_pushnumber(L, pos.X);
521                 lua_setfield(L, -2, "x");
522                 lua_pushnumber(L, pos.Y);
523                 lua_setfield(L, -2, "y");
524                 lua_pushnumber(L, pos.Z);
525                 lua_setfield(L, -2, "z");
526                 return 1;
527         }
528         
529         // setpos(self, pos)
530         static int l_setpos(lua_State *L)
531         {
532                 ObjectRef *ref = checkobject(L, 1);
533                 //LuaEntitySAO *co = getluaobject(ref);
534                 ServerActiveObject *co = getobject(ref);
535                 if(co == NULL) return 0;
536                 // pos
537                 v3f pos = readFloatPos(L, 2);
538                 // Do it
539                 co->setPos(pos);
540                 return 0;
541         }
542         
543         // moveto(self, pos, continuous=false)
544         static int l_moveto(lua_State *L)
545         {
546                 ObjectRef *ref = checkobject(L, 1);
547                 //LuaEntitySAO *co = getluaobject(ref);
548                 ServerActiveObject *co = getobject(ref);
549                 if(co == NULL) return 0;
550                 // pos
551                 v3f pos = readFloatPos(L, 2);
552                 // continuous
553                 bool continuous = lua_toboolean(L, 3);
554                 // Do it
555                 co->moveTo(pos, continuous);
556                 return 0;
557         }
558
559         // add_to_inventory(self, itemstring)
560         // returns: true if item was added, false otherwise
561         static int l_add_to_inventory(lua_State *L)
562         {
563                 ObjectRef *ref = checkobject(L, 1);
564                 luaL_checkstring(L, 2);
565                 ServerActiveObject *co = getobject(ref);
566                 if(co == NULL) return 0;
567                 // itemstring
568                 const char *itemstring = lua_tostring(L, 2);
569                 infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
570                                 <<" itemstring=\""<<itemstring<<"\""<<std::endl;
571                 // Do it
572                 std::istringstream is(itemstring, std::ios::binary);
573                 ServerEnvironment *env = co->getEnv();
574                 assert(env);
575                 IGameDef *gamedef = env->getGameDef();
576                 InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
577                 infostream<<"item="<<env<<std::endl;
578                 bool fits = co->addToInventory(item);
579                 // Return
580                 lua_pushboolean(L, fits);
581                 return 1;
582         }
583
584 public:
585         ObjectRef(ServerActiveObject *object):
586                 m_object(object)
587         {
588                 //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
589         }
590
591         ~ObjectRef()
592         {
593                 /*if(m_object)
594                         infostream<<"ObjectRef destructing for id="
595                                         <<m_object->getId()<<std::endl;
596                 else
597                         infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
598         }
599
600         // Creates an ObjectRef and leaves it on top of stack
601         // Not callable from Lua; all references are created on the C side.
602         static void create(lua_State *L, ServerActiveObject *object)
603         {
604                 ObjectRef *o = new ObjectRef(object);
605                 //infostream<<"ObjectRef::create: o="<<o<<std::endl;
606                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
607                 luaL_getmetatable(L, className);
608                 lua_setmetatable(L, -2);
609         }
610
611         static void set_null(lua_State *L)
612         {
613                 ObjectRef *o = checkobject(L, -1);
614                 o->m_object = NULL;
615         }
616         
617         static void Register(lua_State *L)
618         {
619                 lua_newtable(L);
620                 int methodtable = lua_gettop(L);
621                 luaL_newmetatable(L, className);
622                 int metatable = lua_gettop(L);
623
624                 lua_pushliteral(L, "__metatable");
625                 lua_pushvalue(L, methodtable);
626                 lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
627
628                 lua_pushliteral(L, "__index");
629                 lua_pushvalue(L, methodtable);
630                 lua_settable(L, metatable);
631
632                 lua_pushliteral(L, "__gc");
633                 lua_pushcfunction(L, gc_object);
634                 lua_settable(L, metatable);
635
636                 lua_pop(L, 1);  // drop metatable
637
638                 luaL_openlib(L, 0, methods, 0);  // fill methodtable
639                 lua_pop(L, 1);  // drop methodtable
640
641                 // Cannot be created from Lua
642                 //lua_register(L, className, create_object);
643         }
644 };
645 const char ObjectRef::className[] = "ObjectRef";
646 const luaL_reg ObjectRef::methods[] = {
647         method(ObjectRef, remove),
648         method(ObjectRef, getpos),
649         method(ObjectRef, setpos),
650         method(ObjectRef, moveto),
651         method(ObjectRef, add_to_inventory),
652         {0,0}
653 };
654
655 // Creates a new anonymous reference if id=0
656 static void objectref_get_or_create(lua_State *L,
657                 ServerActiveObject *cobj)
658 {
659         if(cobj->getId() == 0){
660                 ObjectRef::create(L, cobj);
661         } else {
662                 objectref_get(L, cobj->getId());
663         }
664 }
665
666 /*
667         Main export function
668 */
669
670 void scriptapi_export(lua_State *L, Server *server)
671 {
672         realitycheck(L);
673         assert(lua_checkstack(L, 20));
674         infostream<<"scriptapi_export"<<std::endl;
675         StackUnroller stack_unroller(L);
676
677         // Store server as light userdata in registry
678         lua_pushlightuserdata(L, server);
679         lua_setfield(L, LUA_REGISTRYINDEX, "minetest_server");
680         
681         // Register global functions in table minetest
682         lua_newtable(L);
683         luaL_register(L, NULL, minetest_f);
684         lua_setglobal(L, "minetest");
685         
686         // Get the main minetest table
687         lua_getglobal(L, "minetest");
688
689         // Add tables to minetest
690         
691         /*lua_newtable(L);
692         lua_setfield(L, -2, "registered_blocks");*/
693
694         lua_newtable(L);
695         lua_setfield(L, -2, "registered_entities");
696
697         lua_newtable(L);
698         lua_setfield(L, -2, "registered_globalsteps");
699
700         lua_newtable(L);
701         lua_setfield(L, -2, "object_refs");
702
703         lua_newtable(L);
704         lua_setfield(L, -2, "luaentities");
705
706         // Create entity prototype
707         luaL_newmetatable(L, "minetest.entity");
708         // metatable.__index = metatable
709         lua_pushvalue(L, -1); // Duplicate metatable
710         lua_setfield(L, -2, "__index");
711         // Put functions in metatable
712         luaL_register(L, NULL, minetest_entity_m);
713         // Put other stuff in metatable
714
715         // Environment C reference
716         EnvRef::Register(L);
717
718         // Object C reference
719         ObjectRef::Register(L);
720 }
721
722 void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
723 {
724         realitycheck(L);
725         assert(lua_checkstack(L, 20));
726         infostream<<"scriptapi_add_environment"<<std::endl;
727         StackUnroller stack_unroller(L);
728
729         // Create EnvRef on stack
730         EnvRef::create(L, env);
731         int envref = lua_gettop(L);
732
733         // minetest.env = envref
734         lua_getglobal(L, "minetest");
735         luaL_checktype(L, -1, LUA_TTABLE);
736         lua_pushvalue(L, envref);
737         lua_setfield(L, -2, "env");
738 }
739
740 #if 0
741 // Dump stack top with the dump2 function
742 static void dump2(lua_State *L, const char *name)
743 {
744         // Dump object (debug)
745         lua_getglobal(L, "dump2");
746         luaL_checktype(L, -1, LUA_TFUNCTION);
747         lua_pushvalue(L, -2); // Get previous stack top as first parameter
748         lua_pushstring(L, name);
749         if(lua_pcall(L, 2, 0, 0))
750                 script_error(L, "error: %s\n", lua_tostring(L, -1));
751 }
752 #endif
753
754 /*
755         object_reference
756 */
757
758 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
759 {
760         realitycheck(L);
761         assert(lua_checkstack(L, 20));
762         infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
763         StackUnroller stack_unroller(L);
764
765         // Create object on stack
766         ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
767         int object = lua_gettop(L);
768
769         // Get minetest.object_refs table
770         lua_getglobal(L, "minetest");
771         lua_getfield(L, -1, "object_refs");
772         luaL_checktype(L, -1, LUA_TTABLE);
773         int objectstable = lua_gettop(L);
774         
775         // object_refs[id] = object
776         lua_pushnumber(L, cobj->getId()); // Push id
777         lua_pushvalue(L, object); // Copy object to top of stack
778         lua_settable(L, objectstable);
779 }
780
781 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
782 {
783         realitycheck(L);
784         assert(lua_checkstack(L, 20));
785         infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
786         StackUnroller stack_unroller(L);
787
788         // Get minetest.object_refs table
789         lua_getglobal(L, "minetest");
790         lua_getfield(L, -1, "object_refs");
791         luaL_checktype(L, -1, LUA_TTABLE);
792         int objectstable = lua_gettop(L);
793         
794         // Get object_refs[id]
795         lua_pushnumber(L, cobj->getId()); // Push id
796         lua_gettable(L, objectstable);
797         // Set object reference to NULL
798         ObjectRef::set_null(L);
799         lua_pop(L, 1); // pop object
800
801         // Set object_refs[id] = nil
802         lua_pushnumber(L, cobj->getId()); // Push id
803         lua_pushnil(L);
804         lua_settable(L, objectstable);
805 }
806
807 /*
808         environment
809 */
810
811 void scriptapi_environment_step(lua_State *L, float dtime)
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.registered_globalsteps
819         lua_getglobal(L, "minetest");
820         lua_getfield(L, -1, "registered_globalsteps");
821         luaL_checktype(L, -1, LUA_TTABLE);
822         int table = lua_gettop(L);
823         // Foreach
824         lua_pushnil(L);
825         while(lua_next(L, table) != 0){
826                 // key at index -2 and value at index -1
827                 luaL_checktype(L, -1, LUA_TFUNCTION);
828                 // Call function
829                 lua_pushnumber(L, dtime);
830                 if(lua_pcall(L, 1, 0, 0))
831                         script_error(L, "error: %s\n", lua_tostring(L, -1));
832                 // value removed, keep key for next iteration
833         }
834 }
835
836 /*
837         luaentity
838 */
839
840 bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
841                 const char *init_state)
842 {
843         realitycheck(L);
844         assert(lua_checkstack(L, 20));
845         infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
846                         <<name<<"\""<<std::endl;
847         StackUnroller stack_unroller(L);
848         
849         // Create object as a dummy string (TODO: Create properly)
850
851         // Get minetest.registered_entities[name]
852         lua_getglobal(L, "minetest");
853         lua_getfield(L, -1, "registered_entities");
854         luaL_checktype(L, -1, LUA_TTABLE);
855         lua_pushstring(L, name);
856         lua_gettable(L, -2);
857         // Should be a table, which we will use as a prototype
858         //luaL_checktype(L, -1, LUA_TTABLE);
859         if(lua_type(L, -1) != LUA_TTABLE){
860                 errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
861                 return false;
862         }
863         int prototype_table = lua_gettop(L);
864         //dump2(L, "prototype_table");
865         
866         // Create entity object
867         lua_newtable(L);
868         int object = lua_gettop(L);
869
870         // Set object metatable
871         lua_pushvalue(L, prototype_table);
872         lua_setmetatable(L, -2);
873         
874         // Add object reference
875         // This should be userdata with metatable ObjectRef
876         objectref_get(L, id);
877         luaL_checktype(L, -1, LUA_TUSERDATA);
878         if(!luaL_checkudata(L, -1, "ObjectRef"))
879                 luaL_typerror(L, -1, "ObjectRef");
880         lua_setfield(L, -2, "object");
881
882         // minetest.luaentities[id] = object
883         lua_getglobal(L, "minetest");
884         lua_getfield(L, -1, "luaentities");
885         luaL_checktype(L, -1, LUA_TTABLE);
886         lua_pushnumber(L, id); // Push id
887         lua_pushvalue(L, object); // Copy object to top of stack
888         lua_settable(L, -3);
889         
890         // This callback doesn't really make sense
891         /*// Get on_activate function
892         lua_pushvalue(L, object);
893         lua_getfield(L, -1, "on_activate");
894         luaL_checktype(L, -1, LUA_TFUNCTION);
895         lua_pushvalue(L, object); // self
896         // Call with 1 arguments, 0 results
897         if(lua_pcall(L, 1, 0, 0))
898                 script_error(L, "error running function %s:on_activate: %s\n",
899                                 name, lua_tostring(L, -1));*/
900
901         return true;
902 }
903
904 void scriptapi_luaentity_rm(lua_State *L, u16 id)
905 {
906         realitycheck(L);
907         assert(lua_checkstack(L, 20));
908         infostream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
909
910         // Get minetest.luaentities table
911         lua_getglobal(L, "minetest");
912         lua_getfield(L, -1, "luaentities");
913         luaL_checktype(L, -1, LUA_TTABLE);
914         int objectstable = lua_gettop(L);
915         
916         // Set luaentities[id] = nil
917         lua_pushnumber(L, id); // Push id
918         lua_pushnil(L);
919         lua_settable(L, objectstable);
920         
921         lua_pop(L, 2); // pop luaentities, minetest
922 }
923
924 std::string scriptapi_luaentity_get_state(lua_State *L, u16 id)
925 {
926         realitycheck(L);
927         assert(lua_checkstack(L, 20));
928         infostream<<"scriptapi_luaentity_get_state: id="<<id<<std::endl;
929         
930         return "";
931 }
932
933 void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
934                 LuaEntityProperties *prop)
935 {
936         realitycheck(L);
937         assert(lua_checkstack(L, 20));
938         infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
939         StackUnroller stack_unroller(L);
940
941         // Get minetest.luaentities[id]
942         luaentity_get(L, id);
943         //int object = lua_gettop(L);
944
945         lua_getfield(L, -1, "physical");
946         if(lua_isboolean(L, -1))
947                 prop->physical = lua_toboolean(L, -1);
948         lua_pop(L, 1);
949         
950         lua_getfield(L, -1, "weight");
951         prop->weight = lua_tonumber(L, -1);
952         lua_pop(L, 1);
953
954         lua_getfield(L, -1, "collisionbox");
955         if(lua_istable(L, -1)){
956                 lua_rawgeti(L, -1, 1);
957                 prop->collisionbox.MinEdge.X = lua_tonumber(L, -1);
958                 lua_pop(L, 1);
959                 lua_rawgeti(L, -1, 2);
960                 prop->collisionbox.MinEdge.Y = lua_tonumber(L, -1);
961                 lua_pop(L, 1);
962                 lua_rawgeti(L, -1, 3);
963                 prop->collisionbox.MinEdge.Z = lua_tonumber(L, -1);
964                 lua_pop(L, 1);
965                 lua_rawgeti(L, -1, 4);
966                 prop->collisionbox.MaxEdge.X = lua_tonumber(L, -1);
967                 lua_pop(L, 1);
968                 lua_rawgeti(L, -1, 5);
969                 prop->collisionbox.MaxEdge.Y = lua_tonumber(L, -1);
970                 lua_pop(L, 1);
971                 lua_rawgeti(L, -1, 6);
972                 prop->collisionbox.MaxEdge.Z = lua_tonumber(L, -1);
973                 lua_pop(L, 1);
974         }
975         lua_pop(L, 1);
976
977         lua_getfield(L, -1, "visual");
978         if(lua_isstring(L, -1))
979                 prop->visual = lua_tostring(L, -1);
980         lua_pop(L, 1);
981         
982         lua_getfield(L, -1, "textures");
983         if(lua_istable(L, -1)){
984                 prop->textures.clear();
985                 int table = lua_gettop(L);
986                 lua_pushnil(L);
987                 while(lua_next(L, table) != 0){
988                         // key at index -2 and value at index -1
989                         if(lua_isstring(L, -1))
990                                 prop->textures.push_back(lua_tostring(L, -1));
991                         else
992                                 prop->textures.push_back("");
993                         // removes value, keeps key for next iteration
994                         lua_pop(L, 1);
995                 }
996         }
997         lua_pop(L, 1);
998
999 }
1000
1001 void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
1002 {
1003         realitycheck(L);
1004         assert(lua_checkstack(L, 20));
1005         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
1006         StackUnroller stack_unroller(L);
1007
1008         // Get minetest.luaentities[id]
1009         luaentity_get(L, id);
1010         int object = lua_gettop(L);
1011         // State: object is at top of stack
1012         // Get step function
1013         lua_getfield(L, -1, "on_step");
1014         luaL_checktype(L, -1, LUA_TFUNCTION);
1015         lua_pushvalue(L, object); // self
1016         lua_pushnumber(L, dtime); // dtime
1017         // Call with 2 arguments, 0 results
1018         if(lua_pcall(L, 2, 0, 0))
1019                 script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
1020 }
1021
1022 // Calls entity:on_punch(ObjectRef puncher)
1023 void scriptapi_luaentity_punch(lua_State *L, u16 id,
1024                 ServerActiveObject *puncher)
1025 {
1026         realitycheck(L);
1027         assert(lua_checkstack(L, 20));
1028         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
1029         StackUnroller stack_unroller(L);
1030
1031         // Get minetest.luaentities[id]
1032         luaentity_get(L, id);
1033         int object = lua_gettop(L);
1034         // State: object is at top of stack
1035         // Get function
1036         lua_getfield(L, -1, "on_punch");
1037         luaL_checktype(L, -1, LUA_TFUNCTION);
1038         lua_pushvalue(L, object); // self
1039         objectref_get_or_create(L, puncher); // Clicker reference
1040         // Call with 2 arguments, 0 results
1041         if(lua_pcall(L, 2, 0, 0))
1042                 script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
1043 }
1044
1045 // Calls entity:on_rightclick(ObjectRef clicker)
1046 void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
1047                 ServerActiveObject *clicker)
1048 {
1049         realitycheck(L);
1050         assert(lua_checkstack(L, 20));
1051         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
1052         StackUnroller stack_unroller(L);
1053
1054         // Get minetest.luaentities[id]
1055         luaentity_get(L, id);
1056         int object = lua_gettop(L);
1057         // State: object is at top of stack
1058         // Get function
1059         lua_getfield(L, -1, "on_rightclick");
1060         luaL_checktype(L, -1, LUA_TFUNCTION);
1061         lua_pushvalue(L, object); // self
1062         objectref_get_or_create(L, clicker); // Clicker reference
1063         // Call with 2 arguments, 0 results
1064         if(lua_pcall(L, 2, 0, 0))
1065                 script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
1066 }
1067