]> git.lizzy.rs Git - minetest.git/blob - src/scriptapi_object.cpp
Merge remote branch 'origin/master'
[minetest.git] / src / scriptapi_object.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "scriptapi.h"
21 #include "scriptapi_object.h"
22 #include "log.h"
23 #include "tool.h"
24 #include "scriptapi_types.h"
25 #include "scriptapi_inventory.h"
26 #include "scriptapi_item.h"
27 #include "scriptapi_entity.h"
28 #include "scriptapi_common.h"
29
30 /*
31         ObjectRef
32 */
33
34
35 ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
36 {
37         luaL_checktype(L, narg, LUA_TUSERDATA);
38         void *ud = luaL_checkudata(L, narg, className);
39         if(!ud) luaL_typerror(L, narg, className);
40         return *(ObjectRef**)ud;  // unbox pointer
41 }
42
43 ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
44 {
45         ServerActiveObject *co = ref->m_object;
46         return co;
47 }
48
49 LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
50 {
51         ServerActiveObject *obj = getobject(ref);
52         if(obj == NULL)
53                 return NULL;
54         if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
55                 return NULL;
56         return (LuaEntitySAO*)obj;
57 }
58
59 PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
60 {
61         ServerActiveObject *obj = getobject(ref);
62         if(obj == NULL)
63                 return NULL;
64         if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
65                 return NULL;
66         return (PlayerSAO*)obj;
67 }
68
69 Player* ObjectRef::getplayer(ObjectRef *ref)
70 {
71         PlayerSAO *playersao = getplayersao(ref);
72         if(playersao == NULL)
73                 return NULL;
74         return playersao->getPlayer();
75 }
76
77 // Exported functions
78
79 // garbage collector
80 int ObjectRef::gc_object(lua_State *L) {
81         ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
82         //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
83         delete o;
84         return 0;
85 }
86
87 // remove(self)
88 int ObjectRef::l_remove(lua_State *L)
89 {
90         ObjectRef *ref = checkobject(L, 1);
91         ServerActiveObject *co = getobject(ref);
92         if(co == NULL) return 0;
93         verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
94         co->m_removed = true;
95         return 0;
96 }
97
98 // getpos(self)
99 // returns: {x=num, y=num, z=num}
100 int ObjectRef::l_getpos(lua_State *L)
101 {
102         ObjectRef *ref = checkobject(L, 1);
103         ServerActiveObject *co = getobject(ref);
104         if(co == NULL) return 0;
105         v3f pos = co->getBasePosition() / BS;
106         lua_newtable(L);
107         lua_pushnumber(L, pos.X);
108         lua_setfield(L, -2, "x");
109         lua_pushnumber(L, pos.Y);
110         lua_setfield(L, -2, "y");
111         lua_pushnumber(L, pos.Z);
112         lua_setfield(L, -2, "z");
113         return 1;
114 }
115
116 // setpos(self, pos)
117 int ObjectRef::l_setpos(lua_State *L)
118 {
119         ObjectRef *ref = checkobject(L, 1);
120         //LuaEntitySAO *co = getluaobject(ref);
121         ServerActiveObject *co = getobject(ref);
122         if(co == NULL) return 0;
123         // pos
124         v3f pos = checkFloatPos(L, 2);
125         // Do it
126         co->setPos(pos);
127         return 0;
128 }
129
130 // moveto(self, pos, continuous=false)
131 int ObjectRef::l_moveto(lua_State *L)
132 {
133         ObjectRef *ref = checkobject(L, 1);
134         //LuaEntitySAO *co = getluaobject(ref);
135         ServerActiveObject *co = getobject(ref);
136         if(co == NULL) return 0;
137         // pos
138         v3f pos = checkFloatPos(L, 2);
139         // continuous
140         bool continuous = lua_toboolean(L, 3);
141         // Do it
142         co->moveTo(pos, continuous);
143         return 0;
144 }
145
146 // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
147 int ObjectRef::l_punch(lua_State *L)
148 {
149         ObjectRef *ref = checkobject(L, 1);
150         ObjectRef *puncher_ref = checkobject(L, 2);
151         ServerActiveObject *co = getobject(ref);
152         ServerActiveObject *puncher = getobject(puncher_ref);
153         if(co == NULL) return 0;
154         if(puncher == NULL) return 0;
155         v3f dir;
156         if(lua_type(L, 5) != LUA_TTABLE)
157                 dir = co->getBasePosition() - puncher->getBasePosition();
158         else
159                 dir = read_v3f(L, 5);
160         float time_from_last_punch = 1000000;
161         if(lua_isnumber(L, 3))
162                 time_from_last_punch = lua_tonumber(L, 3);
163         ToolCapabilities toolcap = read_tool_capabilities(L, 4);
164         dir.normalize();
165         // Do it
166         co->punch(dir, &toolcap, puncher, time_from_last_punch);
167         return 0;
168 }
169
170 // right_click(self, clicker); clicker = an another ObjectRef
171 int ObjectRef::l_right_click(lua_State *L)
172 {
173         ObjectRef *ref = checkobject(L, 1);
174         ObjectRef *ref2 = checkobject(L, 2);
175         ServerActiveObject *co = getobject(ref);
176         ServerActiveObject *co2 = getobject(ref2);
177         if(co == NULL) return 0;
178         if(co2 == NULL) return 0;
179         // Do it
180         co->rightClick(co2);
181         return 0;
182 }
183
184 // set_hp(self, hp)
185 // hp = number of hitpoints (2 * number of hearts)
186 // returns: nil
187 int ObjectRef::l_set_hp(lua_State *L)
188 {
189         ObjectRef *ref = checkobject(L, 1);
190         luaL_checknumber(L, 2);
191         ServerActiveObject *co = getobject(ref);
192         if(co == NULL) return 0;
193         int hp = lua_tonumber(L, 2);
194         /*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
195                         <<" hp="<<hp<<std::endl;*/
196         // Do it
197         co->setHP(hp);
198         // Return
199         return 0;
200 }
201
202 // get_hp(self)
203 // returns: number of hitpoints (2 * number of hearts)
204 // 0 if not applicable to this type of object
205 int ObjectRef::l_get_hp(lua_State *L)
206 {
207         ObjectRef *ref = checkobject(L, 1);
208         ServerActiveObject *co = getobject(ref);
209         if(co == NULL){
210                 // Default hp is 1
211                 lua_pushnumber(L, 1);
212                 return 1;
213         }
214         int hp = co->getHP();
215         /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
216                         <<" hp="<<hp<<std::endl;*/
217         // Return
218         lua_pushnumber(L, hp);
219         return 1;
220 }
221
222 // get_inventory(self)
223 int ObjectRef::l_get_inventory(lua_State *L)
224 {
225         ObjectRef *ref = checkobject(L, 1);
226         ServerActiveObject *co = getobject(ref);
227         if(co == NULL) return 0;
228         // Do it
229         InventoryLocation loc = co->getInventoryLocation();
230         if(get_server(L)->getInventory(loc) != NULL)
231                 InvRef::create(L, loc);
232         else
233                 lua_pushnil(L); // An object may have no inventory (nil)
234         return 1;
235 }
236
237 // get_wield_list(self)
238 int ObjectRef::l_get_wield_list(lua_State *L)
239 {
240         ObjectRef *ref = checkobject(L, 1);
241         ServerActiveObject *co = getobject(ref);
242         if(co == NULL) return 0;
243         // Do it
244         lua_pushstring(L, co->getWieldList().c_str());
245         return 1;
246 }
247
248 // get_wield_index(self)
249 int ObjectRef::l_get_wield_index(lua_State *L)
250 {
251         ObjectRef *ref = checkobject(L, 1);
252         ServerActiveObject *co = getobject(ref);
253         if(co == NULL) return 0;
254         // Do it
255         lua_pushinteger(L, co->getWieldIndex() + 1);
256         return 1;
257 }
258
259 // get_wielded_item(self)
260 int ObjectRef::l_get_wielded_item(lua_State *L)
261 {
262         ObjectRef *ref = checkobject(L, 1);
263         ServerActiveObject *co = getobject(ref);
264         if(co == NULL){
265                 // Empty ItemStack
266                 LuaItemStack::create(L, ItemStack());
267                 return 1;
268         }
269         // Do it
270         LuaItemStack::create(L, co->getWieldedItem());
271         return 1;
272 }
273
274 // set_wielded_item(self, itemstack or itemstring or table or nil)
275 int ObjectRef::l_set_wielded_item(lua_State *L)
276 {
277         ObjectRef *ref = checkobject(L, 1);
278         ServerActiveObject *co = getobject(ref);
279         if(co == NULL) return 0;
280         // Do it
281         ItemStack item = read_item(L, 2);
282         bool success = co->setWieldedItem(item);
283         lua_pushboolean(L, success);
284         return 1;
285 }
286
287 // set_armor_groups(self, groups)
288 int ObjectRef::l_set_armor_groups(lua_State *L)
289 {
290         ObjectRef *ref = checkobject(L, 1);
291         ServerActiveObject *co = getobject(ref);
292         if(co == NULL) return 0;
293         // Do it
294         ItemGroupList groups;
295         read_groups(L, 2, groups);
296         co->setArmorGroups(groups);
297         return 0;
298 }
299
300 // set_animation(self, frame_range, frame_speed, frame_blend)
301 int ObjectRef::l_set_animation(lua_State *L)
302 {
303         ObjectRef *ref = checkobject(L, 1);
304         ServerActiveObject *co = getobject(ref);
305         if(co == NULL) return 0;
306         // Do it
307         v2f frames = v2f(1, 1);
308         if(!lua_isnil(L, 2))
309                 frames = read_v2f(L, 2);
310         float frame_speed = 15;
311         if(!lua_isnil(L, 3))
312                 frame_speed = lua_tonumber(L, 3);
313         float frame_blend = 0;
314         if(!lua_isnil(L, 4))
315                 frame_blend = lua_tonumber(L, 4);
316         co->setAnimation(frames, frame_speed, frame_blend);
317         return 0;
318 }
319
320 // set_bone_position(self, std::string bone, v3f position, v3f rotation)
321 int ObjectRef::l_set_bone_position(lua_State *L)
322 {
323         ObjectRef *ref = checkobject(L, 1);
324         ServerActiveObject *co = getobject(ref);
325         if(co == NULL) return 0;
326         // Do it
327         std::string bone = "";
328         if(!lua_isnil(L, 2))
329                 bone = lua_tostring(L, 2);
330         v3f position = v3f(0, 0, 0);
331         if(!lua_isnil(L, 3))
332                 position = read_v3f(L, 3);
333         v3f rotation = v3f(0, 0, 0);
334         if(!lua_isnil(L, 4))
335                 rotation = read_v3f(L, 4);
336         co->setBonePosition(bone, position, rotation);
337         return 0;
338 }
339
340 // set_attach(self, parent, bone, position, rotation)
341 int ObjectRef::l_set_attach(lua_State *L)
342 {
343         ObjectRef *ref = checkobject(L, 1);
344         ObjectRef *parent_ref = checkobject(L, 2);
345         ServerActiveObject *co = getobject(ref);
346         ServerActiveObject *parent = getobject(parent_ref);
347         if(co == NULL) return 0;
348         if(parent == NULL) return 0;
349         // Do it
350         std::string bone = "";
351         if(!lua_isnil(L, 3))
352                 bone = lua_tostring(L, 3);
353         v3f position = v3f(0, 0, 0);
354         if(!lua_isnil(L, 4))
355                 position = read_v3f(L, 4);
356         v3f rotation = v3f(0, 0, 0);
357         if(!lua_isnil(L, 5))
358                 rotation = read_v3f(L, 5);
359         co->setAttachment(parent->getId(), bone, position, rotation);
360         return 0;
361 }
362
363 // set_detach(self)
364 int ObjectRef::l_set_detach(lua_State *L)
365 {
366         ObjectRef *ref = checkobject(L, 1);
367         ServerActiveObject *co = getobject(ref);
368         if(co == NULL) return 0;
369         // Do it
370         co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
371         return 0;
372 }
373
374 // set_properties(self, properties)
375 int ObjectRef::l_set_properties(lua_State *L)
376 {
377         ObjectRef *ref = checkobject(L, 1);
378         ServerActiveObject *co = getobject(ref);
379         if(co == NULL) return 0;
380         ObjectProperties *prop = co->accessObjectProperties();
381         if(!prop)
382                 return 0;
383         read_object_properties(L, 2, prop);
384         co->notifyObjectPropertiesModified();
385         return 0;
386 }
387
388 /* LuaEntitySAO-only */
389
390 // setvelocity(self, {x=num, y=num, z=num})
391 int ObjectRef::l_setvelocity(lua_State *L)
392 {
393         ObjectRef *ref = checkobject(L, 1);
394         LuaEntitySAO *co = getluaobject(ref);
395         if(co == NULL) return 0;
396         v3f pos = checkFloatPos(L, 2);
397         // Do it
398         co->setVelocity(pos);
399         return 0;
400 }
401
402 // getvelocity(self)
403 int ObjectRef::l_getvelocity(lua_State *L)
404 {
405         ObjectRef *ref = checkobject(L, 1);
406         LuaEntitySAO *co = getluaobject(ref);
407         if(co == NULL) return 0;
408         // Do it
409         v3f v = co->getVelocity();
410         pushFloatPos(L, v);
411         return 1;
412 }
413
414 // setacceleration(self, {x=num, y=num, z=num})
415 int ObjectRef::l_setacceleration(lua_State *L)
416 {
417         ObjectRef *ref = checkobject(L, 1);
418         LuaEntitySAO *co = getluaobject(ref);
419         if(co == NULL) return 0;
420         // pos
421         v3f pos = checkFloatPos(L, 2);
422         // Do it
423         co->setAcceleration(pos);
424         return 0;
425 }
426
427 // getacceleration(self)
428 int ObjectRef::l_getacceleration(lua_State *L)
429 {
430         ObjectRef *ref = checkobject(L, 1);
431         LuaEntitySAO *co = getluaobject(ref);
432         if(co == NULL) return 0;
433         // Do it
434         v3f v = co->getAcceleration();
435         pushFloatPos(L, v);
436         return 1;
437 }
438
439 // setyaw(self, radians)
440 int ObjectRef::l_setyaw(lua_State *L)
441 {
442         ObjectRef *ref = checkobject(L, 1);
443         LuaEntitySAO *co = getluaobject(ref);
444         if(co == NULL) return 0;
445         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
446         // Do it
447         co->setYaw(yaw);
448         return 0;
449 }
450
451 // getyaw(self)
452 int ObjectRef::l_getyaw(lua_State *L)
453 {
454         ObjectRef *ref = checkobject(L, 1);
455         LuaEntitySAO *co = getluaobject(ref);
456         if(co == NULL) return 0;
457         // Do it
458         float yaw = co->getYaw() * core::DEGTORAD;
459         lua_pushnumber(L, yaw);
460         return 1;
461 }
462
463 // settexturemod(self, mod)
464 int ObjectRef::l_settexturemod(lua_State *L)
465 {
466         ObjectRef *ref = checkobject(L, 1);
467         LuaEntitySAO *co = getluaobject(ref);
468         if(co == NULL) return 0;
469         // Do it
470         std::string mod = luaL_checkstring(L, 2);
471         co->setTextureMod(mod);
472         return 0;
473 }
474
475 // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
476 //           select_horiz_by_yawpitch=false)
477 int ObjectRef::l_setsprite(lua_State *L)
478 {
479         ObjectRef *ref = checkobject(L, 1);
480         LuaEntitySAO *co = getluaobject(ref);
481         if(co == NULL) return 0;
482         // Do it
483         v2s16 p(0,0);
484         if(!lua_isnil(L, 2))
485                 p = read_v2s16(L, 2);
486         int num_frames = 1;
487         if(!lua_isnil(L, 3))
488                 num_frames = lua_tonumber(L, 3);
489         float framelength = 0.2;
490         if(!lua_isnil(L, 4))
491                 framelength = lua_tonumber(L, 4);
492         bool select_horiz_by_yawpitch = false;
493         if(!lua_isnil(L, 5))
494                 select_horiz_by_yawpitch = lua_toboolean(L, 5);
495         co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
496         return 0;
497 }
498
499 // DEPRECATED
500 // get_entity_name(self)
501 int ObjectRef::l_get_entity_name(lua_State *L)
502 {
503         ObjectRef *ref = checkobject(L, 1);
504         LuaEntitySAO *co = getluaobject(ref);
505         if(co == NULL) return 0;
506         // Do it
507         std::string name = co->getName();
508         lua_pushstring(L, name.c_str());
509         return 1;
510 }
511
512 // get_luaentity(self)
513 int ObjectRef::l_get_luaentity(lua_State *L)
514 {
515         ObjectRef *ref = checkobject(L, 1);
516         LuaEntitySAO *co = getluaobject(ref);
517         if(co == NULL) return 0;
518         // Do it
519         luaentity_get(L, co->getId());
520         return 1;
521 }
522
523 /* Player-only */
524
525 // is_player(self)
526 int ObjectRef::l_is_player(lua_State *L)
527 {
528         ObjectRef *ref = checkobject(L, 1);
529         Player *player = getplayer(ref);
530         lua_pushboolean(L, (player != NULL));
531         return 1;
532 }
533
534 // get_player_name(self)
535 int ObjectRef::l_get_player_name(lua_State *L)
536 {
537         ObjectRef *ref = checkobject(L, 1);
538         Player *player = getplayer(ref);
539         if(player == NULL){
540                 lua_pushlstring(L, "", 0);
541                 return 1;
542         }
543         // Do it
544         lua_pushstring(L, player->getName());
545         return 1;
546 }
547
548 // get_look_dir(self)
549 int ObjectRef::l_get_look_dir(lua_State *L)
550 {
551         ObjectRef *ref = checkobject(L, 1);
552         Player *player = getplayer(ref);
553         if(player == NULL) return 0;
554         // Do it
555         float pitch = player->getRadPitch();
556         float yaw = player->getRadYaw();
557         v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
558         push_v3f(L, v);
559         return 1;
560 }
561
562 // get_look_pitch(self)
563 int ObjectRef::l_get_look_pitch(lua_State *L)
564 {
565         ObjectRef *ref = checkobject(L, 1);
566         Player *player = getplayer(ref);
567         if(player == NULL) return 0;
568         // Do it
569         lua_pushnumber(L, player->getRadPitch());
570         return 1;
571 }
572
573 // get_look_yaw(self)
574 int ObjectRef::l_get_look_yaw(lua_State *L)
575 {
576         ObjectRef *ref = checkobject(L, 1);
577         Player *player = getplayer(ref);
578         if(player == NULL) return 0;
579         // Do it
580         lua_pushnumber(L, player->getRadYaw());
581         return 1;
582 }
583
584 // set_look_pitch(self, radians)
585 int ObjectRef::l_set_look_pitch(lua_State *L)
586 {
587         ObjectRef *ref = checkobject(L, 1);
588         PlayerSAO* co = getplayersao(ref);
589         if(co == NULL) return 0;
590         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
591         // Do it
592         co->setPitch(pitch);
593         return 1;
594 }
595
596 // set_look_yaw(self, radians)
597 int ObjectRef::l_set_look_yaw(lua_State *L)
598 {
599         ObjectRef *ref = checkobject(L, 1);
600         PlayerSAO* co = getplayersao(ref);
601         if(co == NULL) return 0;
602         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
603         // Do it
604         co->setYaw(yaw);
605         return 1;
606 }
607
608 // set_inventory_formspec(self, formspec)
609 int ObjectRef::l_set_inventory_formspec(lua_State *L)
610 {
611         ObjectRef *ref = checkobject(L, 1);
612         Player *player = getplayer(ref);
613         if(player == NULL) return 0;
614         std::string formspec = luaL_checkstring(L, 2);
615
616         player->inventory_formspec = formspec;
617         get_server(L)->reportInventoryFormspecModified(player->getName());
618         lua_pushboolean(L, true);
619         return 1;
620 }
621
622 // get_inventory_formspec(self) -> formspec
623 int ObjectRef::l_get_inventory_formspec(lua_State *L)
624 {
625         ObjectRef *ref = checkobject(L, 1);
626         Player *player = getplayer(ref);
627         if(player == NULL) return 0;
628
629         std::string formspec = player->inventory_formspec;
630         lua_pushlstring(L, formspec.c_str(), formspec.size());
631         return 1;
632 }
633
634 // get_player_control(self)
635 int ObjectRef::l_get_player_control(lua_State *L)
636 {
637         ObjectRef *ref = checkobject(L, 1);
638         Player *player = getplayer(ref);
639         if(player == NULL){
640                 lua_pushlstring(L, "", 0);
641                 return 1;
642         }
643         // Do it
644         PlayerControl control = player->getPlayerControl();
645         lua_newtable(L);
646         lua_pushboolean(L, control.up);
647         lua_setfield(L, -2, "up");
648         lua_pushboolean(L, control.down);
649         lua_setfield(L, -2, "down");
650         lua_pushboolean(L, control.left);
651         lua_setfield(L, -2, "left");
652         lua_pushboolean(L, control.right);
653         lua_setfield(L, -2, "right");
654         lua_pushboolean(L, control.jump);
655         lua_setfield(L, -2, "jump");
656         lua_pushboolean(L, control.aux1);
657         lua_setfield(L, -2, "aux1");
658         lua_pushboolean(L, control.sneak);
659         lua_setfield(L, -2, "sneak");
660         lua_pushboolean(L, control.LMB);
661         lua_setfield(L, -2, "LMB");
662         lua_pushboolean(L, control.RMB);
663         lua_setfield(L, -2, "RMB");
664         return 1;
665 }
666
667 // get_player_control_bits(self)
668 int ObjectRef::l_get_player_control_bits(lua_State *L)
669 {
670         ObjectRef *ref = checkobject(L, 1);
671         Player *player = getplayer(ref);
672         if(player == NULL){
673                 lua_pushlstring(L, "", 0);
674                 return 1;
675         }
676         // Do it
677         lua_pushnumber(L, player->keyPressed);
678         return 1;
679 }
680
681
682 ObjectRef::ObjectRef(ServerActiveObject *object):
683         m_object(object)
684 {
685         //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
686 }
687
688 ObjectRef::~ObjectRef()
689 {
690         /*if(m_object)
691                 infostream<<"ObjectRef destructing for id="
692                                 <<m_object->getId()<<std::endl;
693         else
694                 infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
695 }
696
697 // Creates an ObjectRef and leaves it on top of stack
698 // Not callable from Lua; all references are created on the C side.
699 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
700 {
701         ObjectRef *o = new ObjectRef(object);
702         //infostream<<"ObjectRef::create: o="<<o<<std::endl;
703         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
704         luaL_getmetatable(L, className);
705         lua_setmetatable(L, -2);
706 }
707
708 void ObjectRef::set_null(lua_State *L)
709 {
710         ObjectRef *o = checkobject(L, -1);
711         o->m_object = NULL;
712 }
713
714 void ObjectRef::Register(lua_State *L)
715 {
716         lua_newtable(L);
717         int methodtable = lua_gettop(L);
718         luaL_newmetatable(L, className);
719         int metatable = lua_gettop(L);
720
721         lua_pushliteral(L, "__metatable");
722         lua_pushvalue(L, methodtable);
723         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
724
725         lua_pushliteral(L, "__index");
726         lua_pushvalue(L, methodtable);
727         lua_settable(L, metatable);
728
729         lua_pushliteral(L, "__gc");
730         lua_pushcfunction(L, gc_object);
731         lua_settable(L, metatable);
732
733         lua_pop(L, 1);  // drop metatable
734
735         luaL_openlib(L, 0, methods, 0);  // fill methodtable
736         lua_pop(L, 1);  // drop methodtable
737
738         // Cannot be created from Lua
739         //lua_register(L, className, create_object);
740 }
741
742 const char ObjectRef::className[] = "ObjectRef";
743 const luaL_reg ObjectRef::methods[] = {
744         // ServerActiveObject
745         luamethod(ObjectRef, remove),
746         luamethod(ObjectRef, getpos),
747         luamethod(ObjectRef, setpos),
748         luamethod(ObjectRef, moveto),
749         luamethod(ObjectRef, punch),
750         luamethod(ObjectRef, right_click),
751         luamethod(ObjectRef, set_hp),
752         luamethod(ObjectRef, get_hp),
753         luamethod(ObjectRef, get_inventory),
754         luamethod(ObjectRef, get_wield_list),
755         luamethod(ObjectRef, get_wield_index),
756         luamethod(ObjectRef, get_wielded_item),
757         luamethod(ObjectRef, set_wielded_item),
758         luamethod(ObjectRef, set_armor_groups),
759         luamethod(ObjectRef, set_animation),
760         luamethod(ObjectRef, set_bone_position),
761         luamethod(ObjectRef, set_attach),
762         luamethod(ObjectRef, set_detach),
763         luamethod(ObjectRef, set_properties),
764         // LuaEntitySAO-only
765         luamethod(ObjectRef, setvelocity),
766         luamethod(ObjectRef, getvelocity),
767         luamethod(ObjectRef, setacceleration),
768         luamethod(ObjectRef, getacceleration),
769         luamethod(ObjectRef, setyaw),
770         luamethod(ObjectRef, getyaw),
771         luamethod(ObjectRef, settexturemod),
772         luamethod(ObjectRef, setsprite),
773         luamethod(ObjectRef, get_entity_name),
774         luamethod(ObjectRef, get_luaentity),
775         // Player-only
776         luamethod(ObjectRef, is_player),
777         luamethod(ObjectRef, get_player_name),
778         luamethod(ObjectRef, get_look_dir),
779         luamethod(ObjectRef, get_look_pitch),
780         luamethod(ObjectRef, get_look_yaw),
781         luamethod(ObjectRef, set_look_yaw),
782         luamethod(ObjectRef, set_look_pitch),
783         luamethod(ObjectRef, set_inventory_formspec),
784         luamethod(ObjectRef, get_inventory_formspec),
785         luamethod(ObjectRef, get_player_control),
786         luamethod(ObjectRef, get_player_control_bits),
787         {0,0}
788 };
789
790 // Creates a new anonymous reference if cobj=NULL or id=0
791 void objectref_get_or_create(lua_State *L,
792                 ServerActiveObject *cobj)
793 {
794         if(cobj == NULL || cobj->getId() == 0){
795                 ObjectRef::create(L, cobj);
796         } else {
797                 objectref_get(L, cobj->getId());
798         }
799 }
800
801 void objectref_get(lua_State *L, u16 id)
802 {
803         // Get minetest.object_refs[i]
804         lua_getglobal(L, "minetest");
805         lua_getfield(L, -1, "object_refs");
806         luaL_checktype(L, -1, LUA_TTABLE);
807         lua_pushnumber(L, id);
808         lua_gettable(L, -2);
809         lua_remove(L, -2); // object_refs
810         lua_remove(L, -2); // minetest
811 }
812
813 /*
814         ObjectProperties
815 */
816
817 void read_object_properties(lua_State *L, int index,
818                 ObjectProperties *prop)
819 {
820         if(index < 0)
821                 index = lua_gettop(L) + 1 + index;
822         if(!lua_istable(L, index))
823                 return;
824
825         prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
826
827         getboolfield(L, -1, "physical", prop->physical);
828
829         getfloatfield(L, -1, "weight", prop->weight);
830
831         lua_getfield(L, -1, "collisionbox");
832         if(lua_istable(L, -1))
833                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
834         lua_pop(L, 1);
835
836         getstringfield(L, -1, "visual", prop->visual);
837
838         getstringfield(L, -1, "mesh", prop->mesh);
839
840         lua_getfield(L, -1, "visual_size");
841         if(lua_istable(L, -1))
842                 prop->visual_size = read_v2f(L, -1);
843         lua_pop(L, 1);
844
845         lua_getfield(L, -1, "textures");
846         if(lua_istable(L, -1)){
847                 prop->textures.clear();
848                 int table = lua_gettop(L);
849                 lua_pushnil(L);
850                 while(lua_next(L, table) != 0){
851                         // key at index -2 and value at index -1
852                         if(lua_isstring(L, -1))
853                                 prop->textures.push_back(lua_tostring(L, -1));
854                         else
855                                 prop->textures.push_back("");
856                         // removes value, keeps key for next iteration
857                         lua_pop(L, 1);
858                 }
859         }
860         lua_pop(L, 1);
861
862         lua_getfield(L, -1, "colors");
863         if(lua_istable(L, -1)){
864                 prop->colors.clear();
865                 int table = lua_gettop(L);
866                 lua_pushnil(L);
867                 while(lua_next(L, table) != 0){
868                         // key at index -2 and value at index -1
869                         if(lua_isstring(L, -1))
870                                 prop->colors.push_back(readARGB8(L, -1));
871                         else
872                                 prop->colors.push_back(video::SColor(255, 255, 255, 255));
873                         // removes value, keeps key for next iteration
874                         lua_pop(L, 1);
875                 }
876         }
877         lua_pop(L, 1);
878
879         lua_getfield(L, -1, "spritediv");
880         if(lua_istable(L, -1))
881                 prop->spritediv = read_v2s16(L, -1);
882         lua_pop(L, 1);
883
884         lua_getfield(L, -1, "initial_sprite_basepos");
885         if(lua_istable(L, -1))
886                 prop->initial_sprite_basepos = read_v2s16(L, -1);
887         lua_pop(L, 1);
888
889         getboolfield(L, -1, "is_visible", prop->is_visible);
890         getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
891         getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
892 }
893
894 /*
895         object_reference
896 */
897
898 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
899 {
900         realitycheck(L);
901         assert(lua_checkstack(L, 20));
902         //infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
903         StackUnroller stack_unroller(L);
904
905         // Create object on stack
906         ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
907         int object = lua_gettop(L);
908
909         // Get minetest.object_refs table
910         lua_getglobal(L, "minetest");
911         lua_getfield(L, -1, "object_refs");
912         luaL_checktype(L, -1, LUA_TTABLE);
913         int objectstable = lua_gettop(L);
914
915         // object_refs[id] = object
916         lua_pushnumber(L, cobj->getId()); // Push id
917         lua_pushvalue(L, object); // Copy object to top of stack
918         lua_settable(L, objectstable);
919 }
920
921 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
922 {
923         realitycheck(L);
924         assert(lua_checkstack(L, 20));
925         //infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
926         StackUnroller stack_unroller(L);
927
928         // Get minetest.object_refs table
929         lua_getglobal(L, "minetest");
930         lua_getfield(L, -1, "object_refs");
931         luaL_checktype(L, -1, LUA_TTABLE);
932         int objectstable = lua_gettop(L);
933
934         // Get object_refs[id]
935         lua_pushnumber(L, cobj->getId()); // Push id
936         lua_gettable(L, objectstable);
937         // Set object reference to NULL
938         ObjectRef::set_null(L);
939         lua_pop(L, 1); // pop object
940
941         // Set object_refs[id] = nil
942         lua_pushnumber(L, cobj->getId()); // Push id
943         lua_pushnil(L);
944         lua_settable(L, objectstable);
945 }