]> git.lizzy.rs Git - minetest.git/blob - src/scriptapi.cpp
Scripting WIP; Lua entity step callback works
[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
37 static void stackDump(lua_State *L, std::ostream &o)
38 {
39   int i;
40   int top = lua_gettop(L);
41   for (i = 1; i <= top; i++) {  /* repeat for each level */
42         int t = lua_type(L, i);
43         switch (t) {
44
45           case LUA_TSTRING:  /* strings */
46                 o<<"\""<<lua_tostring(L, i)<<"\"";
47                 break;
48
49           case LUA_TBOOLEAN:  /* booleans */
50                 o<<(lua_toboolean(L, i) ? "true" : "false");
51                 break;
52
53           case LUA_TNUMBER:  /* numbers */ {
54                 char buf[10];
55                 snprintf(buf, 10, "%g", lua_tonumber(L, i));
56                 o<<buf;
57                 break; }
58
59           default:  /* other values */
60                 o<<lua_typename(L, t);
61                 break;
62
63         }
64         o<<" ";
65   }
66   o<<std::endl;
67 }
68
69 static void realitycheck(lua_State *L)
70 {
71         int top = lua_gettop(L);
72         if(top >= 30){
73                 dstream<<"Stack is over 30:"<<std::endl;
74                 stackDump(L, dstream);
75                 script_error(L, "Stack is over 30 (reality check)");
76         }
77 }
78
79 // Register new object prototype
80 // register_entity(name, prototype)
81 static int l_register_entity(lua_State *L)
82 {
83         const char *name = luaL_checkstring(L, 1);
84         luaL_checktype(L, 2, LUA_TTABLE);
85         infostream<<"register_entity: "<<name<<std::endl;
86
87         // Get minetest.registered_entities
88         lua_getglobal(L, "minetest");
89         lua_getfield(L, -1, "registered_entities");
90         luaL_checktype(L, -1, LUA_TTABLE);
91         int registered_entities = lua_gettop(L);
92         lua_pushvalue(L, 2); // Object = param 2 -> stack top
93         // registered_entities[name] = object
94         lua_setfield(L, registered_entities, name);
95         
96         // Get registered object to top of stack
97         lua_pushvalue(L, 2);
98         
99         // Set __index to point to itself
100         lua_pushvalue(L, -1);
101         lua_setfield(L, -2, "__index");
102
103         // Set metatable.__index = metatable
104         luaL_getmetatable(L, "minetest.entity");
105         lua_pushvalue(L, -1); // duplicate metatable
106         lua_setfield(L, -2, "__index");
107         // Set object metatable
108         lua_setmetatable(L, -2);
109
110         return 0; /* number of results */
111 }
112
113 #if 0
114 static int l_new_entity(lua_State *L)
115 {
116         /* o = o or {}
117            setmetatable(o, self)
118            self.__index = self
119            return o */
120         if(lua_isnil(L, -1))
121                 lua_newtable(L);
122         luaL_checktype(L, -1, LUA_TTABLE);
123         luaL_getmetatable(L, "minetest.entity");
124         lua_pushvalue(L, -1); // duplicate metatable
125         lua_setfield(L, -2, "__index");
126         lua_setmetatable(L, -2);
127         // return table
128         return 1;
129 }
130 #endif
131
132 static const struct luaL_Reg minetest_f [] = {
133         {"register_entity", l_register_entity},
134         //{"new_entity", l_new_entity},
135         {NULL, NULL}
136 };
137
138 static int l_entity_set_deleted(lua_State *L)
139 {
140         return 0;
141 }
142
143 static const struct luaL_Reg minetest_entity_m [] = {
144         {"set_deleted", l_entity_set_deleted},
145         {NULL, NULL}
146 };
147
148 class ObjectRef
149 {
150 private:
151         ServerActiveObject *m_object;
152
153         static const char className[];
154         static const luaL_reg methods[];
155
156         static ObjectRef *checkobject(lua_State *L, int narg)
157         {
158                 luaL_checktype(L, narg, LUA_TUSERDATA);
159                 void *ud = luaL_checkudata(L, narg, className);
160                 if(!ud) luaL_typerror(L, narg, className);
161                 return *(ObjectRef**)ud;  // unbox pointer
162         }
163         
164         // Exported functions
165
166         static int l_remove(lua_State *L)
167         {
168                 ObjectRef *o = checkobject(L, 1);
169                 ServerActiveObject *co = o->m_object;
170                 if(co == NULL) return 0;
171                 infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
172                 co->m_removed = true;
173                 return 0;
174         }
175
176         static int gc_object(lua_State *L) {
177                 //ObjectRef *o = checkobject(L, 1);
178                 ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
179                 //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
180                 delete o;
181                 return 0;
182         }
183
184 public:
185         ObjectRef(ServerActiveObject *object):
186                 m_object(object)
187         {
188                 infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
189         }
190
191         ~ObjectRef()
192         {
193                 if(m_object)
194                         infostream<<"ObjectRef destructing for id="<<m_object->getId()<<std::endl;
195                 else
196                         infostream<<"ObjectRef destructing for id=unknown"<<std::endl;
197         }
198
199         // Creates an ObjectRef and leaves it on top of stack
200         // Not callable from Lua; all references are created on the C side.
201         static void create(lua_State *L, ServerActiveObject *object)
202         {
203                 ObjectRef *o = new ObjectRef(object);
204                 //infostream<<"ObjectRef::create: o="<<o<<std::endl;
205                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
206                 luaL_getmetatable(L, className);
207                 lua_setmetatable(L, -2);
208         }
209
210         static void set_null(lua_State *L)
211         {
212                 ObjectRef *o = checkobject(L, -1);
213                 ServerActiveObject *co = o->m_object;
214                 if(co == NULL)
215                         return;
216                 o->m_object = NULL;
217         }
218         
219         static void Register(lua_State *L)
220         {
221                 lua_newtable(L);
222                 int methodtable = lua_gettop(L);
223                 luaL_newmetatable(L, className);
224                 int metatable = lua_gettop(L);
225
226                 lua_pushliteral(L, "__metatable");
227                 lua_pushvalue(L, methodtable);
228                 lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
229
230                 lua_pushliteral(L, "__index");
231                 lua_pushvalue(L, methodtable);
232                 lua_settable(L, metatable);
233
234                 lua_pushliteral(L, "__gc");
235                 lua_pushcfunction(L, gc_object);
236                 lua_settable(L, metatable);
237
238                 lua_pop(L, 1);  // drop metatable
239
240                 luaL_openlib(L, 0, methods, 0);  // fill methodtable
241                 lua_pop(L, 1);  // drop methodtable
242
243                 // Cannot be created from Lua
244                 //lua_register(L, className, create_object);
245         }
246 };
247
248 const char ObjectRef::className[] = "ObjectRef";
249
250 #define method(class, name) {#name, class::l_##name}
251
252 const luaL_reg ObjectRef::methods[] = {
253         method(ObjectRef, remove),
254         {0,0}
255 };
256
257 void scriptapi_export(lua_State *L, Server *server)
258 {
259         realitycheck(L);
260         assert(lua_checkstack(L, 20));
261         infostream<<"scriptapi_export"<<std::endl;
262         
263         // Register global functions in table minetest
264         lua_newtable(L);
265         luaL_register(L, NULL, minetest_f);
266         lua_setglobal(L, "minetest");
267         
268         // Get the main minetest table
269         lua_getglobal(L, "minetest");
270
271         // Add registered_entities table in minetest
272         lua_newtable(L);
273         lua_setfield(L, -2, "registered_entities");
274
275         // Add object_refs table in minetest
276         lua_newtable(L);
277         lua_setfield(L, -2, "object_refs");
278
279         // Add luaentities table in minetest
280         lua_newtable(L);
281         lua_setfield(L, -2, "luaentities");
282
283         // Load and run some base Lua stuff
284         /*script_load(L, (porting::path_data + DIR_DELIM + "scripts"
285                         + DIR_DELIM + "base.lua").c_str());*/
286         
287         // Create entity reference metatable
288         luaL_newmetatable(L, "minetest.entity_reference");
289         lua_pop(L, 1);
290         
291         // Create entity prototype
292         luaL_newmetatable(L, "minetest.entity");
293         // metatable.__index = metatable
294         lua_pushvalue(L, -1); // Duplicate metatable
295         lua_setfield(L, -2, "__index");
296         // Put functions in metatable
297         luaL_register(L, NULL, minetest_entity_m);
298         // Put other stuff in metatable
299
300         // Entity C reference
301         ObjectRef::Register(L);
302 }
303
304 // Dump stack top with the dump2 function
305 static void dump2(lua_State *L, const char *name)
306 {
307         // Dump object (debug)
308         lua_getglobal(L, "dump2");
309         luaL_checktype(L, -1, LUA_TFUNCTION);
310         lua_pushvalue(L, -2); // Get previous stack top as first parameter
311         lua_pushstring(L, name);
312         if(lua_pcall(L, 2, 0, 0))
313                 script_error(L, "error: %s\n", lua_tostring(L, -1));
314 }
315
316 void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
317                 const char *init_state)
318 {
319         realitycheck(L);
320         assert(lua_checkstack(L, 20));
321         infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
322                         <<name<<"\""<<std::endl;
323
324         int initial_top = lua_gettop(L);
325         
326         // Create object as a dummy string (TODO: Create properly)
327
328         // Get minetest.registered_entities[name]
329         lua_getglobal(L, "minetest");
330         lua_getfield(L, -1, "registered_entities");
331         luaL_checktype(L, -1, LUA_TTABLE);
332         lua_pushstring(L, name);
333         lua_gettable(L, -2);
334         // Should be a table, which we will use as a prototype
335         luaL_checktype(L, -1, LUA_TTABLE);
336         int prototype_table = lua_gettop(L);
337         //dump2(L, "prototype_table");
338         
339         // Create entity object
340         lua_newtable(L);
341         int object = lua_gettop(L);
342
343         // Set object metatable
344         lua_pushvalue(L, prototype_table);
345         lua_setmetatable(L, -2);
346         
347         /*// Set prototype_table.__index = prototype_table
348         lua_pushvalue(L, prototype_table); // Copy to top of stack
349         lua_pushvalue(L, -1); // duplicate prototype_table
350         lua_setfield(L, -2, "__index");*/
351         
352         /*lua_pushstring(L, "debug from C");
353         lua_setfield(L, -2, "on_step");*/
354
355         // Get minetest.luaentities table
356         lua_getglobal(L, "minetest");
357         lua_getfield(L, -1, "luaentities");
358         luaL_checktype(L, -1, LUA_TTABLE);
359         int luaentities = lua_gettop(L);
360         
361         // luaentities[id] = object
362         lua_pushnumber(L, id); // Push id
363         lua_pushvalue(L, object); // Copy object to top of stack
364         lua_settable(L, luaentities);
365         
366         lua_settop(L, initial_top); // Reset stack
367 }
368
369 void scriptapi_luaentity_rm(lua_State *L, u16 id)
370 {
371         realitycheck(L);
372         assert(lua_checkstack(L, 20));
373         infostream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
374
375         // Get minetest.luaentities table
376         lua_getglobal(L, "minetest");
377         lua_getfield(L, -1, "luaentities");
378         luaL_checktype(L, -1, LUA_TTABLE);
379         int objectstable = lua_gettop(L);
380         
381         /*// Get luaentities[id]
382         lua_pushnumber(L, cobj->getId()); // Push id
383         lua_gettable(L, objectstable);
384         // Object is at stack top
385         lua_pop(L, 1); // pop object*/
386
387         // Set luaentities[id] = nil
388         lua_pushnumber(L, id); // Push id
389         lua_pushnil(L);
390         lua_settable(L, objectstable);
391         
392         lua_pop(L, 2); // pop luaentities, minetest
393 }
394
395 void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
396 {
397         realitycheck(L);
398         assert(lua_checkstack(L, 20));
399         infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
400
401         // Get minetest.luaentities[i]
402         lua_getglobal(L, "minetest");
403         lua_getfield(L, -1, "luaentities");
404         luaL_checktype(L, -1, LUA_TTABLE);
405         lua_pushnumber(L, id);
406         lua_gettable(L, -2);
407         int object = lua_gettop(L);
408         // State: object is at top of stack
409         /*dump2(L, "entity");
410         lua_getmetatable(L, -1);
411         dump2(L, "getmetatable(entity)");
412         lua_getfield(L, -1, "__index");
413         dump2(L, "getmetatable(entity).__index");
414         lua_pop(L, 1);
415         lua_pop(L, 1);*/
416         // Get step function
417         lua_getfield(L, -1, "on_step");
418         luaL_checktype(L, -1, LUA_TFUNCTION);
419         lua_pushvalue(L, object); // self
420         lua_pushnumber(L, dtime); // dtime
421         // Call with 2 arguments, 0 results
422         if(lua_pcall(L, 2, 0, 0))
423                 script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
424
425         lua_pop(L, 1); // pop object
426         lua_pop(L, 2); // pop luaentities, minetest
427 }
428
429 std::string scriptapi_luaentity_get_state(lua_State *L, u16 id)
430 {
431         realitycheck(L);
432         assert(lua_checkstack(L, 20));
433         infostream<<"scriptapi_luaentity_get_state: id="<<id<<std::endl;
434         
435         return "";
436 }
437
438 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
439 {
440         realitycheck(L);
441         assert(lua_checkstack(L, 20));
442         infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
443
444         // Create object on stack
445         ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
446         int object = lua_gettop(L);
447
448         // Get minetest.object_refs table
449         lua_getglobal(L, "minetest");
450         lua_getfield(L, -1, "object_refs");
451         luaL_checktype(L, -1, LUA_TTABLE);
452         int objectstable = lua_gettop(L);
453         
454         // object_refs[id] = object
455         lua_pushnumber(L, cobj->getId()); // Push id
456         lua_pushvalue(L, object); // Copy object to top of stack
457         lua_settable(L, objectstable);
458         
459         // pop object_refs, minetest and the object
460         lua_pop(L, 3);
461 }
462
463 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
464 {
465         realitycheck(L);
466         assert(lua_checkstack(L, 20));
467         infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
468
469         // Get minetest.object_refs table
470         lua_getglobal(L, "minetest");
471         lua_getfield(L, -1, "object_refs");
472         luaL_checktype(L, -1, LUA_TTABLE);
473         int objectstable = lua_gettop(L);
474         
475         // Get object_refs[id]
476         lua_pushnumber(L, cobj->getId()); // Push id
477         lua_gettable(L, objectstable);
478         // Set object reference to NULL
479         ObjectRef::set_null(L);
480         lua_pop(L, 1); // pop object
481
482         // Set object_refs[id] = nil
483         lua_pushnumber(L, cobj->getId()); // Push id
484         lua_pushnil(L);
485         lua_settable(L, objectstable);
486         
487         // pop object_refs, minetest
488         lua_pop(L, 2);
489 }
490