]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_object.cpp
Add player:get_meta(), deprecate player attributes (#7202)
[dragonfireclient.git] / src / script / lua_api / l_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 "lua_api/l_object.h"
21 #include <cmath>
22 #include "lua_api/l_internal.h"
23 #include "lua_api/l_inventory.h"
24 #include "lua_api/l_item.h"
25 #include "lua_api/l_playermeta.h"
26 #include "common/c_converter.h"
27 #include "common/c_content.h"
28 #include "log.h"
29 #include "tool.h"
30 #include "serverobject.h"
31 #include "content_sao.h"
32 #include "remoteplayer.h"
33 #include "server.h"
34 #include "hud.h"
35 #include "scripting_server.h"
36
37 /*
38         ObjectRef
39 */
40
41
42 ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
43 {
44         luaL_checktype(L, narg, LUA_TUSERDATA);
45         void *ud = luaL_checkudata(L, narg, className);
46         if (!ud) luaL_typerror(L, narg, className);
47         return *(ObjectRef**)ud;  // unbox pointer
48 }
49
50 ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
51 {
52         ServerActiveObject *co = ref->m_object;
53         return co;
54 }
55
56 LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
57 {
58         ServerActiveObject *obj = getobject(ref);
59         if (obj == NULL)
60                 return NULL;
61         if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
62                 return NULL;
63         return (LuaEntitySAO*)obj;
64 }
65
66 PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
67 {
68         ServerActiveObject *obj = getobject(ref);
69         if (obj == NULL)
70                 return NULL;
71         if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
72                 return NULL;
73         return (PlayerSAO*)obj;
74 }
75
76 RemotePlayer *ObjectRef::getplayer(ObjectRef *ref)
77 {
78         PlayerSAO *playersao = getplayersao(ref);
79         if (playersao == NULL)
80                 return NULL;
81         return playersao->getPlayer();
82 }
83
84 // Exported functions
85
86 // garbage collector
87 int ObjectRef::gc_object(lua_State *L) {
88         ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
89         //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
90         delete o;
91         return 0;
92 }
93
94 // remove(self)
95 int ObjectRef::l_remove(lua_State *L)
96 {
97         GET_ENV_PTR;
98
99         ObjectRef *ref = checkobject(L, 1);
100         ServerActiveObject *co = getobject(ref);
101         if (co == NULL)
102                 return 0;
103         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
104                 return 0;
105
106         const std::unordered_set<int> &child_ids = co->getAttachmentChildIds();
107         for (int child_id : child_ids) {
108                 // Child can be NULL if it was deleted earlier
109                 if (ServerActiveObject *child = env->getActiveObject(child_id))
110                         child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
111         }
112
113         verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl;
114         co->m_pending_removal = true;
115         return 0;
116 }
117
118 // get_pos(self)
119 // returns: {x=num, y=num, z=num}
120 int ObjectRef::l_get_pos(lua_State *L)
121 {
122         NO_MAP_LOCK_REQUIRED;
123         ObjectRef *ref = checkobject(L, 1);
124         ServerActiveObject *co = getobject(ref);
125         if (co == NULL) return 0;
126         v3f pos = co->getBasePosition() / BS;
127         lua_newtable(L);
128         lua_pushnumber(L, pos.X);
129         lua_setfield(L, -2, "x");
130         lua_pushnumber(L, pos.Y);
131         lua_setfield(L, -2, "y");
132         lua_pushnumber(L, pos.Z);
133         lua_setfield(L, -2, "z");
134         return 1;
135 }
136
137 // set_pos(self, pos)
138 int ObjectRef::l_set_pos(lua_State *L)
139 {
140         NO_MAP_LOCK_REQUIRED;
141         ObjectRef *ref = checkobject(L, 1);
142         //LuaEntitySAO *co = getluaobject(ref);
143         ServerActiveObject *co = getobject(ref);
144         if (co == NULL) return 0;
145         // pos
146         v3f pos = checkFloatPos(L, 2);
147         // Do it
148         co->setPos(pos);
149         return 0;
150 }
151
152 // move_to(self, pos, continuous=false)
153 int ObjectRef::l_move_to(lua_State *L)
154 {
155         NO_MAP_LOCK_REQUIRED;
156         ObjectRef *ref = checkobject(L, 1);
157         //LuaEntitySAO *co = getluaobject(ref);
158         ServerActiveObject *co = getobject(ref);
159         if (co == NULL) return 0;
160         // pos
161         v3f pos = checkFloatPos(L, 2);
162         // continuous
163         bool continuous = lua_toboolean(L, 3);
164         // Do it
165         co->moveTo(pos, continuous);
166         return 0;
167 }
168
169 // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
170 int ObjectRef::l_punch(lua_State *L)
171 {
172         NO_MAP_LOCK_REQUIRED;
173         ObjectRef *ref = checkobject(L, 1);
174         ObjectRef *puncher_ref = checkobject(L, 2);
175         ServerActiveObject *co = getobject(ref);
176         ServerActiveObject *puncher = getobject(puncher_ref);
177         if (co == NULL) return 0;
178         if (puncher == NULL) return 0;
179         v3f dir;
180         if (lua_type(L, 5) != LUA_TTABLE)
181                 dir = co->getBasePosition() - puncher->getBasePosition();
182         else
183                 dir = read_v3f(L, 5);
184         float time_from_last_punch = 1000000;
185         if (lua_isnumber(L, 3))
186                 time_from_last_punch = lua_tonumber(L, 3);
187         ToolCapabilities toolcap = read_tool_capabilities(L, 4);
188         dir.normalize();
189
190         s16 src_original_hp = co->getHP();
191         s16 dst_origin_hp = puncher->getHP();
192
193         // Do it
194         co->punch(dir, &toolcap, puncher, time_from_last_punch);
195
196         // If the punched is a player, and its HP changed
197         if (src_original_hp != co->getHP() &&
198                         co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
199                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
200         }
201
202         // If the puncher is a player, and its HP changed
203         if (dst_origin_hp != puncher->getHP() &&
204                         puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
205                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher,
206                                 PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co));
207         }
208         return 0;
209 }
210
211 // right_click(self, clicker); clicker = an another ObjectRef
212 int ObjectRef::l_right_click(lua_State *L)
213 {
214         NO_MAP_LOCK_REQUIRED;
215         ObjectRef *ref = checkobject(L, 1);
216         ObjectRef *ref2 = checkobject(L, 2);
217         ServerActiveObject *co = getobject(ref);
218         ServerActiveObject *co2 = getobject(ref2);
219         if (co == NULL) return 0;
220         if (co2 == NULL) return 0;
221         // Do it
222         co->rightClick(co2);
223         return 0;
224 }
225
226 // set_hp(self, hp)
227 // hp = number of hitpoints (2 * number of hearts)
228 // returns: nil
229 int ObjectRef::l_set_hp(lua_State *L)
230 {
231         NO_MAP_LOCK_REQUIRED;
232
233         // Get Object
234         ObjectRef *ref = checkobject(L, 1);
235         luaL_checknumber(L, 2);
236         ServerActiveObject *co = getobject(ref);
237         if (co == NULL)
238                 return 0;
239
240         // Get HP
241         int hp = lua_tonumber(L, 2);
242
243         // Get Reason
244         PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
245         reason.from_mod = true;
246         if (lua_istable(L, 3)) {
247                 lua_pushvalue(L, 3);
248
249                 lua_getfield(L, -1, "type");
250                 if (lua_isstring(L, -1) && !reason.setTypeFromString(lua_tostring(L, -1))) {
251                         errorstream << "Bad type given!" << std::endl;
252                 }
253                 lua_pop(L, 1);
254
255                 reason.lua_reference = luaL_ref(L, LUA_REGISTRYINDEX);
256         }
257
258         // Do it
259         co->setHP(hp, reason);
260         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
261                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
262
263         // Return
264         return 0;
265 }
266
267 // get_hp(self)
268 // returns: number of hitpoints (2 * number of hearts)
269 // 0 if not applicable to this type of object
270 int ObjectRef::l_get_hp(lua_State *L)
271 {
272         NO_MAP_LOCK_REQUIRED;
273         ObjectRef *ref = checkobject(L, 1);
274         ServerActiveObject *co = getobject(ref);
275         if (co == NULL) {
276                 // Default hp is 1
277                 lua_pushnumber(L, 1);
278                 return 1;
279         }
280         int hp = co->getHP();
281         /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
282                         <<" hp="<<hp<<std::endl;*/
283         // Return
284         lua_pushnumber(L, hp);
285         return 1;
286 }
287
288 // get_inventory(self)
289 int ObjectRef::l_get_inventory(lua_State *L)
290 {
291         NO_MAP_LOCK_REQUIRED;
292         ObjectRef *ref = checkobject(L, 1);
293         ServerActiveObject *co = getobject(ref);
294         if (co == NULL) return 0;
295         // Do it
296         InventoryLocation loc = co->getInventoryLocation();
297         if (getServer(L)->getInventory(loc) != NULL)
298                 InvRef::create(L, loc);
299         else
300                 lua_pushnil(L); // An object may have no inventory (nil)
301         return 1;
302 }
303
304 // get_wield_list(self)
305 int ObjectRef::l_get_wield_list(lua_State *L)
306 {
307         NO_MAP_LOCK_REQUIRED;
308         ObjectRef *ref = checkobject(L, 1);
309         ServerActiveObject *co = getobject(ref);
310         if (co == NULL) return 0;
311         // Do it
312         lua_pushstring(L, co->getWieldList().c_str());
313         return 1;
314 }
315
316 // get_wield_index(self)
317 int ObjectRef::l_get_wield_index(lua_State *L)
318 {
319         NO_MAP_LOCK_REQUIRED;
320         ObjectRef *ref = checkobject(L, 1);
321         ServerActiveObject *co = getobject(ref);
322         if (co == NULL) return 0;
323         // Do it
324         lua_pushinteger(L, co->getWieldIndex() + 1);
325         return 1;
326 }
327
328 // get_wielded_item(self)
329 int ObjectRef::l_get_wielded_item(lua_State *L)
330 {
331         NO_MAP_LOCK_REQUIRED;
332         ObjectRef *ref = checkobject(L, 1);
333         ServerActiveObject *co = getobject(ref);
334         if (co == NULL) {
335                 // Empty ItemStack
336                 LuaItemStack::create(L, ItemStack());
337                 return 1;
338         }
339         // Do it
340         LuaItemStack::create(L, co->getWieldedItem());
341         return 1;
342 }
343
344 // set_wielded_item(self, itemstack or itemstring or table or nil)
345 int ObjectRef::l_set_wielded_item(lua_State *L)
346 {
347         NO_MAP_LOCK_REQUIRED;
348         ObjectRef *ref = checkobject(L, 1);
349         ServerActiveObject *co = getobject(ref);
350         if (co == NULL) return 0;
351         // Do it
352         ItemStack item = read_item(L, 2, getServer(L)->idef());
353         bool success = co->setWieldedItem(item);
354         if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
355                 getServer(L)->SendInventory(((PlayerSAO*)co));
356         }
357         lua_pushboolean(L, success);
358         return 1;
359 }
360
361 // set_armor_groups(self, groups)
362 int ObjectRef::l_set_armor_groups(lua_State *L)
363 {
364         NO_MAP_LOCK_REQUIRED;
365         ObjectRef *ref = checkobject(L, 1);
366         ServerActiveObject *co = getobject(ref);
367         if (co == NULL) return 0;
368         // Do it
369         ItemGroupList groups;
370         read_groups(L, 2, groups);
371         co->setArmorGroups(groups);
372         return 0;
373 }
374
375 // get_armor_groups(self)
376 int ObjectRef::l_get_armor_groups(lua_State *L)
377 {
378         NO_MAP_LOCK_REQUIRED;
379         ObjectRef *ref = checkobject(L, 1);
380         ServerActiveObject *co = getobject(ref);
381         if (co == NULL)
382                 return 0;
383         // Do it
384         push_groups(L, co->getArmorGroups());
385         return 1;
386 }
387
388 // set_physics_override(self, physics_override_speed, physics_override_jump,
389 //                      physics_override_gravity, sneak, sneak_glitch, new_move)
390 int ObjectRef::l_set_physics_override(lua_State *L)
391 {
392         NO_MAP_LOCK_REQUIRED;
393         ObjectRef *ref = checkobject(L, 1);
394         PlayerSAO *co = (PlayerSAO *) getobject(ref);
395         if (co == NULL) return 0;
396         // Do it
397         if (lua_istable(L, 2)) {
398                 co->m_physics_override_speed = getfloatfield_default(
399                                 L, 2, "speed", co->m_physics_override_speed);
400                 co->m_physics_override_jump = getfloatfield_default(
401                                 L, 2, "jump", co->m_physics_override_jump);
402                 co->m_physics_override_gravity = getfloatfield_default(
403                                 L, 2, "gravity", co->m_physics_override_gravity);
404                 co->m_physics_override_sneak = getboolfield_default(
405                                 L, 2, "sneak", co->m_physics_override_sneak);
406                 co->m_physics_override_sneak_glitch = getboolfield_default(
407                                 L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
408                 co->m_physics_override_new_move = getboolfield_default(
409                                 L, 2, "new_move", co->m_physics_override_new_move);
410                 co->m_physics_override_sent = false;
411         } else {
412                 // old, non-table format
413                 if (!lua_isnil(L, 2)) {
414                         co->m_physics_override_speed = lua_tonumber(L, 2);
415                         co->m_physics_override_sent = false;
416                 }
417                 if (!lua_isnil(L, 3)) {
418                         co->m_physics_override_jump = lua_tonumber(L, 3);
419                         co->m_physics_override_sent = false;
420                 }
421                 if (!lua_isnil(L, 4)) {
422                         co->m_physics_override_gravity = lua_tonumber(L, 4);
423                         co->m_physics_override_sent = false;
424                 }
425         }
426         return 0;
427 }
428
429 // get_physics_override(self)
430 int ObjectRef::l_get_physics_override(lua_State *L)
431 {
432         NO_MAP_LOCK_REQUIRED;
433         ObjectRef *ref = checkobject(L, 1);
434         PlayerSAO *co = (PlayerSAO *)getobject(ref);
435         if (co == NULL)
436                 return 0;
437         // Do it
438         lua_newtable(L);
439         lua_pushnumber(L, co->m_physics_override_speed);
440         lua_setfield(L, -2, "speed");
441         lua_pushnumber(L, co->m_physics_override_jump);
442         lua_setfield(L, -2, "jump");
443         lua_pushnumber(L, co->m_physics_override_gravity);
444         lua_setfield(L, -2, "gravity");
445         lua_pushboolean(L, co->m_physics_override_sneak);
446         lua_setfield(L, -2, "sneak");
447         lua_pushboolean(L, co->m_physics_override_sneak_glitch);
448         lua_setfield(L, -2, "sneak_glitch");
449         lua_pushboolean(L, co->m_physics_override_new_move);
450         lua_setfield(L, -2, "new_move");
451         return 1;
452 }
453
454 // set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
455 int ObjectRef::l_set_animation(lua_State *L)
456 {
457         NO_MAP_LOCK_REQUIRED;
458         ObjectRef *ref = checkobject(L, 1);
459         ServerActiveObject *co = getobject(ref);
460         if (co == NULL) return 0;
461         // Do it
462         v2f frames = v2f(1, 1);
463         if (!lua_isnil(L, 2))
464                 frames = read_v2f(L, 2);
465         float frame_speed = 15;
466         if (!lua_isnil(L, 3))
467                 frame_speed = lua_tonumber(L, 3);
468         float frame_blend = 0;
469         if (!lua_isnil(L, 4))
470                 frame_blend = lua_tonumber(L, 4);
471         bool frame_loop = true;
472         if (lua_isboolean(L, 5))
473                 frame_loop = lua_toboolean(L, 5);
474         co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
475         return 0;
476 }
477
478 // get_animation(self)
479 int ObjectRef::l_get_animation(lua_State *L)
480 {
481         NO_MAP_LOCK_REQUIRED;
482         ObjectRef *ref = checkobject(L, 1);
483         ServerActiveObject *co = getobject(ref);
484         if (co == NULL)
485                 return 0;
486         // Do it
487         v2f frames = v2f(1,1);
488         float frame_speed = 15;
489         float frame_blend = 0;
490         bool frame_loop = true;
491         co->getAnimation(&frames, &frame_speed, &frame_blend, &frame_loop);
492
493         push_v2f(L, frames);
494         lua_pushnumber(L, frame_speed);
495         lua_pushnumber(L, frame_blend);
496         lua_pushboolean(L, frame_loop);
497         return 4;
498 }
499
500 // set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
501 int ObjectRef::l_set_local_animation(lua_State *L)
502 {
503         NO_MAP_LOCK_REQUIRED;
504         ObjectRef *ref = checkobject(L, 1);
505         RemotePlayer *player = getplayer(ref);
506         if (player == NULL)
507                 return 0;
508         // Do it
509         v2s32 frames[4];
510         for (int i=0;i<4;i++) {
511                 if (!lua_isnil(L, 2+1))
512                         frames[i] = read_v2s32(L, 2+i);
513         }
514         float frame_speed = 30;
515         if (!lua_isnil(L, 6))
516                 frame_speed = lua_tonumber(L, 6);
517
518         getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed);
519         lua_pushboolean(L, true);
520         return 1;
521 }
522
523 // get_local_animation(self)
524 int ObjectRef::l_get_local_animation(lua_State *L)
525 {
526         NO_MAP_LOCK_REQUIRED
527         ObjectRef *ref = checkobject(L, 1);
528         RemotePlayer *player = getplayer(ref);
529         if (player == NULL)
530                 return 0;
531
532         v2s32 frames[4];
533         float frame_speed;
534         player->getLocalAnimations(frames, &frame_speed);
535
536         for (const v2s32 &frame : frames) {
537                 push_v2s32(L, frame);
538         }
539
540         lua_pushnumber(L, frame_speed);
541         return 5;
542 }
543
544 // set_eye_offset(self, v3f first pv, v3f third pv)
545 int ObjectRef::l_set_eye_offset(lua_State *L)
546 {
547         NO_MAP_LOCK_REQUIRED;
548         ObjectRef *ref = checkobject(L, 1);
549         RemotePlayer *player = getplayer(ref);
550         if (player == NULL)
551                 return 0;
552         // Do it
553         v3f offset_first = v3f(0, 0, 0);
554         v3f offset_third = v3f(0, 0, 0);
555
556         if (!lua_isnil(L, 2))
557                 offset_first = read_v3f(L, 2);
558         if (!lua_isnil(L, 3))
559                 offset_third = read_v3f(L, 3);
560
561         // Prevent abuse of offset values (keep player always visible)
562         offset_third.X = rangelim(offset_third.X,-10,10);
563         offset_third.Z = rangelim(offset_third.Z,-5,5);
564         /* TODO: if possible: improve the camera colision detetion to allow Y <= -1.5) */
565         offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS
566
567         getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third);
568         lua_pushboolean(L, true);
569         return 1;
570 }
571
572 // get_eye_offset(self)
573 int ObjectRef::l_get_eye_offset(lua_State *L)
574 {
575         NO_MAP_LOCK_REQUIRED;
576         ObjectRef *ref = checkobject(L, 1);
577         RemotePlayer *player = getplayer(ref);
578         if (player == NULL)
579                 return 0;
580         // Do it
581         push_v3f(L, player->eye_offset_first);
582         push_v3f(L, player->eye_offset_third);
583         return 2;
584 }
585
586 // set_animation_frame_speed(self, frame_speed)
587 int ObjectRef::l_set_animation_frame_speed(lua_State *L)
588 {
589         NO_MAP_LOCK_REQUIRED;
590         ObjectRef *ref = checkobject(L, 1);
591         ServerActiveObject *co = getobject(ref);
592         if (co == NULL)
593                 return 0;
594
595         // Do it
596         if (!lua_isnil(L, 2)) {
597                 float frame_speed = lua_tonumber(L, 2);
598                 co->setAnimationSpeed(frame_speed);
599                 lua_pushboolean(L, true);
600         } else {
601                 lua_pushboolean(L, false);
602         }
603         return 1;
604 }
605
606 // set_bone_position(self, std::string bone, v3f position, v3f rotation)
607 int ObjectRef::l_set_bone_position(lua_State *L)
608 {
609         NO_MAP_LOCK_REQUIRED;
610         ObjectRef *ref = checkobject(L, 1);
611         ServerActiveObject *co = getobject(ref);
612         if (co == NULL) return 0;
613         // Do it
614         std::string bone;
615         if (!lua_isnil(L, 2))
616                 bone = lua_tostring(L, 2);
617         v3f position = v3f(0, 0, 0);
618         if (!lua_isnil(L, 3))
619                 position = check_v3f(L, 3);
620         v3f rotation = v3f(0, 0, 0);
621         if (!lua_isnil(L, 4))
622                 rotation = check_v3f(L, 4);
623         co->setBonePosition(bone, position, rotation);
624         return 0;
625 }
626
627 // get_bone_position(self, bone)
628 int ObjectRef::l_get_bone_position(lua_State *L)
629 {
630         NO_MAP_LOCK_REQUIRED;
631         ObjectRef *ref = checkobject(L, 1);
632         ServerActiveObject *co = getobject(ref);
633         if (co == NULL)
634                 return 0;
635         // Do it
636         std::string bone;
637         if (!lua_isnil(L, 2))
638                 bone = lua_tostring(L, 2);
639
640         v3f position = v3f(0, 0, 0);
641         v3f rotation = v3f(0, 0, 0);
642         co->getBonePosition(bone, &position, &rotation);
643
644         push_v3f(L, position);
645         push_v3f(L, rotation);
646         return 2;
647 }
648
649 // set_attach(self, parent, bone, position, rotation)
650 int ObjectRef::l_set_attach(lua_State *L)
651 {
652         GET_ENV_PTR;
653
654         ObjectRef *ref = checkobject(L, 1);
655         ObjectRef *parent_ref = checkobject(L, 2);
656         ServerActiveObject *co = getobject(ref);
657         ServerActiveObject *parent = getobject(parent_ref);
658         if (co == NULL)
659                 return 0;
660         if (parent == NULL)
661                 return 0;
662         // Do it
663         int parent_id = 0;
664         std::string bone;
665         v3f position = v3f(0, 0, 0);
666         v3f rotation = v3f(0, 0, 0);
667         co->getAttachment(&parent_id, &bone, &position, &rotation);
668         if (parent_id) {
669                 ServerActiveObject *old_parent = env->getActiveObject(parent_id);
670                 old_parent->removeAttachmentChild(co->getId());
671         }
672
673         bone = "";
674         if (!lua_isnil(L, 3))
675                 bone = lua_tostring(L, 3);
676         position = v3f(0, 0, 0);
677         if (!lua_isnil(L, 4))
678                 position = read_v3f(L, 4);
679         rotation = v3f(0, 0, 0);
680         if (!lua_isnil(L, 5))
681                 rotation = read_v3f(L, 5);
682         co->setAttachment(parent->getId(), bone, position, rotation);
683         parent->addAttachmentChild(co->getId());
684         return 0;
685 }
686
687 // get_attach(self)
688 int ObjectRef::l_get_attach(lua_State *L)
689 {
690         GET_ENV_PTR;
691
692         ObjectRef *ref = checkobject(L, 1);
693         ServerActiveObject *co = getobject(ref);
694         if (co == NULL)
695                 return 0;
696
697         // Do it
698         int parent_id = 0;
699         std::string bone;
700         v3f position = v3f(0, 0, 0);
701         v3f rotation = v3f(0, 0, 0);
702         co->getAttachment(&parent_id, &bone, &position, &rotation);
703         if (!parent_id)
704                 return 0;
705         ServerActiveObject *parent = env->getActiveObject(parent_id);
706
707         getScriptApiBase(L)->objectrefGetOrCreate(L, parent);
708         lua_pushlstring(L, bone.c_str(), bone.size());
709         push_v3f(L, position);
710         push_v3f(L, rotation);
711         return 4;
712 }
713
714 // set_detach(self)
715 int ObjectRef::l_set_detach(lua_State *L)
716 {
717         GET_ENV_PTR;
718
719         ObjectRef *ref = checkobject(L, 1);
720         ServerActiveObject *co = getobject(ref);
721         if (co == NULL)
722                 return 0;
723
724         int parent_id = 0;
725         std::string bone;
726         v3f position;
727         v3f rotation;
728         co->getAttachment(&parent_id, &bone, &position, &rotation);
729         ServerActiveObject *parent = NULL;
730         if (parent_id) {
731                 parent = env->getActiveObject(parent_id);
732                 co->setAttachment(0, "", position, rotation);
733         } else {
734                 co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
735         }
736         // Do it
737         if (parent != NULL)
738                 parent->removeAttachmentChild(co->getId());
739         return 0;
740 }
741
742 // set_properties(self, properties)
743 int ObjectRef::l_set_properties(lua_State *L)
744 {
745         NO_MAP_LOCK_REQUIRED;
746         ObjectRef *ref = checkobject(L, 1);
747         ServerActiveObject *co = getobject(ref);
748         if (co == NULL) return 0;
749         ObjectProperties *prop = co->accessObjectProperties();
750         if (!prop)
751                 return 0;
752         read_object_properties(L, 2, prop, getServer(L)->idef());
753         if (prop->hp_max < co->getHP()) {
754                 PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
755                 co->setHP(prop->hp_max, reason);
756                 if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
757                         getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
758         }
759         co->notifyObjectPropertiesModified();
760         return 0;
761 }
762
763 // get_properties(self)
764 int ObjectRef::l_get_properties(lua_State *L)
765 {
766         NO_MAP_LOCK_REQUIRED;
767         ObjectRef *ref = checkobject(L, 1);
768         ServerActiveObject *co = getobject(ref);
769         if (co == NULL)
770                 return 0;
771         ObjectProperties *prop = co->accessObjectProperties();
772         if (!prop)
773                 return 0;
774         push_object_properties(L, prop);
775         return 1;
776 }
777
778 // is_player(self)
779 int ObjectRef::l_is_player(lua_State *L)
780 {
781         NO_MAP_LOCK_REQUIRED;
782         ObjectRef *ref = checkobject(L, 1);
783         RemotePlayer *player = getplayer(ref);
784         lua_pushboolean(L, (player != NULL));
785         return 1;
786 }
787
788 // set_nametag_attributes(self, attributes)
789 int ObjectRef::l_set_nametag_attributes(lua_State *L)
790 {
791         NO_MAP_LOCK_REQUIRED;
792         ObjectRef *ref = checkobject(L, 1);
793         ServerActiveObject *co = getobject(ref);
794
795         if (co == NULL)
796                 return 0;
797         ObjectProperties *prop = co->accessObjectProperties();
798         if (!prop)
799                 return 0;
800
801         lua_getfield(L, 2, "color");
802         if (!lua_isnil(L, -1)) {
803                 video::SColor color = prop->nametag_color;
804                 read_color(L, -1, &color);
805                 prop->nametag_color = color;
806         }
807         lua_pop(L, 1);
808
809         std::string nametag = getstringfield_default(L, 2, "text", "");
810         prop->nametag = nametag;
811
812         co->notifyObjectPropertiesModified();
813         lua_pushboolean(L, true);
814         return 1;
815 }
816
817 // get_nametag_attributes(self)
818 int ObjectRef::l_get_nametag_attributes(lua_State *L)
819 {
820         NO_MAP_LOCK_REQUIRED;
821         ObjectRef *ref = checkobject(L, 1);
822         ServerActiveObject *co = getobject(ref);
823
824         if (co == NULL)
825                 return 0;
826         ObjectProperties *prop = co->accessObjectProperties();
827         if (!prop)
828                 return 0;
829
830         video::SColor color = prop->nametag_color;
831
832         lua_newtable(L);
833         push_ARGB8(L, color);
834         lua_setfield(L, -2, "color");
835         lua_pushstring(L, prop->nametag.c_str());
836         lua_setfield(L, -2, "text");
837         return 1;
838 }
839
840 /* LuaEntitySAO-only */
841
842 // set_velocity(self, {x=num, y=num, z=num})
843 int ObjectRef::l_set_velocity(lua_State *L)
844 {
845         NO_MAP_LOCK_REQUIRED;
846         ObjectRef *ref = checkobject(L, 1);
847         LuaEntitySAO *co = getluaobject(ref);
848         if (co == NULL) return 0;
849         v3f pos = checkFloatPos(L, 2);
850         // Do it
851         co->setVelocity(pos);
852         return 0;
853 }
854
855 // add_velocity(self, {x=num, y=num, z=num})
856 int ObjectRef::l_add_velocity(lua_State *L)
857 {
858         NO_MAP_LOCK_REQUIRED;
859         ObjectRef *ref = checkobject(L, 1);
860         LuaEntitySAO *co = getluaobject(ref);
861         if (!co)
862                 return 0;
863         v3f pos = checkFloatPos(L, 2);
864         // Do it
865         co->addVelocity(pos);
866         return 0;
867 }
868
869 // get_velocity(self)
870 int ObjectRef::l_get_velocity(lua_State *L)
871 {
872         NO_MAP_LOCK_REQUIRED;
873         ObjectRef *ref = checkobject(L, 1);
874         LuaEntitySAO *co = getluaobject(ref);
875         if (co == NULL) return 0;
876         // Do it
877         v3f v = co->getVelocity();
878         pushFloatPos(L, v);
879         return 1;
880 }
881
882 // set_acceleration(self, {x=num, y=num, z=num})
883 int ObjectRef::l_set_acceleration(lua_State *L)
884 {
885         NO_MAP_LOCK_REQUIRED;
886         ObjectRef *ref = checkobject(L, 1);
887         LuaEntitySAO *co = getluaobject(ref);
888         if (co == NULL) return 0;
889         // pos
890         v3f pos = checkFloatPos(L, 2);
891         // Do it
892         co->setAcceleration(pos);
893         return 0;
894 }
895
896 // get_acceleration(self)
897 int ObjectRef::l_get_acceleration(lua_State *L)
898 {
899         NO_MAP_LOCK_REQUIRED;
900         ObjectRef *ref = checkobject(L, 1);
901         LuaEntitySAO *co = getluaobject(ref);
902         if (co == NULL) return 0;
903         // Do it
904         v3f v = co->getAcceleration();
905         pushFloatPos(L, v);
906         return 1;
907 }
908
909 // set_yaw(self, radians)
910 int ObjectRef::l_set_yaw(lua_State *L)
911 {
912         NO_MAP_LOCK_REQUIRED;
913         ObjectRef *ref = checkobject(L, 1);
914         LuaEntitySAO *co = getluaobject(ref);
915         if (co == NULL) return 0;
916         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
917         // Do it
918         co->setYaw(yaw);
919         return 0;
920 }
921
922 // get_yaw(self)
923 int ObjectRef::l_get_yaw(lua_State *L)
924 {
925         NO_MAP_LOCK_REQUIRED;
926         ObjectRef *ref = checkobject(L, 1);
927         LuaEntitySAO *co = getluaobject(ref);
928         if (co == NULL) return 0;
929         // Do it
930         float yaw = co->getYaw() * core::DEGTORAD;
931         lua_pushnumber(L, yaw);
932         return 1;
933 }
934
935 // set_texture_mod(self, mod)
936 int ObjectRef::l_set_texture_mod(lua_State *L)
937 {
938         NO_MAP_LOCK_REQUIRED;
939         ObjectRef *ref = checkobject(L, 1);
940         LuaEntitySAO *co = getluaobject(ref);
941         if (co == NULL) return 0;
942         // Do it
943         std::string mod = luaL_checkstring(L, 2);
944         co->setTextureMod(mod);
945         return 0;
946 }
947
948 // get_texture_mod(self)
949 int ObjectRef::l_get_texture_mod(lua_State *L)
950 {
951         NO_MAP_LOCK_REQUIRED;
952         ObjectRef *ref = checkobject(L, 1);
953         LuaEntitySAO *co = getluaobject(ref);
954         if (co == NULL) return 0;
955         // Do it
956         std::string mod = co->getTextureMod();
957         lua_pushstring(L, mod.c_str());
958         return 1;
959 }
960
961 // set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
962 //           select_horiz_by_yawpitch=false)
963 int ObjectRef::l_set_sprite(lua_State *L)
964 {
965         NO_MAP_LOCK_REQUIRED;
966         ObjectRef *ref = checkobject(L, 1);
967         LuaEntitySAO *co = getluaobject(ref);
968         if (co == NULL) return 0;
969         // Do it
970         v2s16 p(0,0);
971         if (!lua_isnil(L, 2))
972                 p = read_v2s16(L, 2);
973         int num_frames = 1;
974         if (!lua_isnil(L, 3))
975                 num_frames = lua_tonumber(L, 3);
976         float framelength = 0.2;
977         if (!lua_isnil(L, 4))
978                 framelength = lua_tonumber(L, 4);
979         bool select_horiz_by_yawpitch = false;
980         if (!lua_isnil(L, 5))
981                 select_horiz_by_yawpitch = lua_toboolean(L, 5);
982         co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
983         return 0;
984 }
985
986 // DEPRECATED
987 // get_entity_name(self)
988 int ObjectRef::l_get_entity_name(lua_State *L)
989 {
990         NO_MAP_LOCK_REQUIRED;
991         ObjectRef *ref = checkobject(L, 1);
992         LuaEntitySAO *co = getluaobject(ref);
993         log_deprecated(L,"Deprecated call to \"get_entity_name");
994         if (co == NULL) return 0;
995         // Do it
996         std::string name = co->getName();
997         lua_pushstring(L, name.c_str());
998         return 1;
999 }
1000
1001 // get_luaentity(self)
1002 int ObjectRef::l_get_luaentity(lua_State *L)
1003 {
1004         NO_MAP_LOCK_REQUIRED;
1005         ObjectRef *ref = checkobject(L, 1);
1006         LuaEntitySAO *co = getluaobject(ref);
1007         if (co == NULL) return 0;
1008         // Do it
1009         luaentity_get(L, co->getId());
1010         return 1;
1011 }
1012
1013 /* Player-only */
1014
1015 // is_player_connected(self)
1016 int ObjectRef::l_is_player_connected(lua_State *L)
1017 {
1018         NO_MAP_LOCK_REQUIRED;
1019         ObjectRef *ref = checkobject(L, 1);
1020         RemotePlayer *player = getplayer(ref);
1021         lua_pushboolean(L, (player != NULL && player->getPeerId() != PEER_ID_INEXISTENT));
1022         return 1;
1023 }
1024
1025 // get_player_name(self)
1026 int ObjectRef::l_get_player_name(lua_State *L)
1027 {
1028         NO_MAP_LOCK_REQUIRED;
1029         ObjectRef *ref = checkobject(L, 1);
1030         RemotePlayer *player = getplayer(ref);
1031         if (player == NULL) {
1032                 lua_pushlstring(L, "", 0);
1033                 return 1;
1034         }
1035         // Do it
1036         lua_pushstring(L, player->getName());
1037         return 1;
1038 }
1039
1040 // get_player_velocity(self)
1041 int ObjectRef::l_get_player_velocity(lua_State *L)
1042 {
1043         NO_MAP_LOCK_REQUIRED;
1044         ObjectRef *ref = checkobject(L, 1);
1045         RemotePlayer *player = getplayer(ref);
1046         if (player == NULL) {
1047                 lua_pushnil(L);
1048                 return 1;
1049         }
1050         // Do it
1051         push_v3f(L, player->getSpeed() / BS);
1052         return 1;
1053 }
1054
1055 // get_look_dir(self)
1056 int ObjectRef::l_get_look_dir(lua_State *L)
1057 {
1058         NO_MAP_LOCK_REQUIRED;
1059         ObjectRef *ref = checkobject(L, 1);
1060         PlayerSAO* co = getplayersao(ref);
1061         if (co == NULL) return 0;
1062         // Do it
1063         float pitch = co->getRadPitchDep();
1064         float yaw = co->getRadYawDep();
1065         v3f v(std::cos(pitch) * std::cos(yaw), std::sin(pitch), std::cos(pitch) *
1066                 std::sin(yaw));
1067         push_v3f(L, v);
1068         return 1;
1069 }
1070
1071 // DEPRECATED
1072 // get_look_pitch(self)
1073 int ObjectRef::l_get_look_pitch(lua_State *L)
1074 {
1075         NO_MAP_LOCK_REQUIRED;
1076
1077         log_deprecated(L,
1078                 "Deprecated call to get_look_pitch, use get_look_vertical instead");
1079
1080         ObjectRef *ref = checkobject(L, 1);
1081         PlayerSAO* co = getplayersao(ref);
1082         if (co == NULL) return 0;
1083         // Do it
1084         lua_pushnumber(L, co->getRadPitchDep());
1085         return 1;
1086 }
1087
1088 // DEPRECATED
1089 // get_look_yaw(self)
1090 int ObjectRef::l_get_look_yaw(lua_State *L)
1091 {
1092         NO_MAP_LOCK_REQUIRED;
1093
1094         log_deprecated(L,
1095                 "Deprecated call to get_look_yaw, use get_look_horizontal instead");
1096
1097         ObjectRef *ref = checkobject(L, 1);
1098         PlayerSAO* co = getplayersao(ref);
1099         if (co == NULL) return 0;
1100         // Do it
1101         lua_pushnumber(L, co->getRadYawDep());
1102         return 1;
1103 }
1104
1105 // get_look_pitch2(self)
1106 int ObjectRef::l_get_look_vertical(lua_State *L)
1107 {
1108         NO_MAP_LOCK_REQUIRED;
1109         ObjectRef *ref = checkobject(L, 1);
1110         PlayerSAO* co = getplayersao(ref);
1111         if (co == NULL) return 0;
1112         // Do it
1113         lua_pushnumber(L, co->getRadPitch());
1114         return 1;
1115 }
1116
1117 // get_look_yaw2(self)
1118 int ObjectRef::l_get_look_horizontal(lua_State *L)
1119 {
1120         NO_MAP_LOCK_REQUIRED;
1121         ObjectRef *ref = checkobject(L, 1);
1122         PlayerSAO* co = getplayersao(ref);
1123         if (co == NULL) return 0;
1124         // Do it
1125         lua_pushnumber(L, co->getRadYaw());
1126         return 1;
1127 }
1128
1129 // set_look_vertical(self, radians)
1130 int ObjectRef::l_set_look_vertical(lua_State *L)
1131 {
1132         NO_MAP_LOCK_REQUIRED;
1133         ObjectRef *ref = checkobject(L, 1);
1134         PlayerSAO* co = getplayersao(ref);
1135         if (co == NULL) return 0;
1136         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1137         // Do it
1138         co->setPitchAndSend(pitch);
1139         return 1;
1140 }
1141
1142 // set_look_horizontal(self, radians)
1143 int ObjectRef::l_set_look_horizontal(lua_State *L)
1144 {
1145         NO_MAP_LOCK_REQUIRED;
1146         ObjectRef *ref = checkobject(L, 1);
1147         PlayerSAO* co = getplayersao(ref);
1148         if (co == NULL) return 0;
1149         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1150         // Do it
1151         co->setYawAndSend(yaw);
1152         return 1;
1153 }
1154
1155 // DEPRECATED
1156 // set_look_pitch(self, radians)
1157 int ObjectRef::l_set_look_pitch(lua_State *L)
1158 {
1159         NO_MAP_LOCK_REQUIRED;
1160
1161         log_deprecated(L,
1162                 "Deprecated call to set_look_pitch, use set_look_vertical instead.");
1163
1164         ObjectRef *ref = checkobject(L, 1);
1165         PlayerSAO* co = getplayersao(ref);
1166         if (co == NULL) return 0;
1167         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1168         // Do it
1169         co->setPitchAndSend(pitch);
1170         return 1;
1171 }
1172
1173 // DEPRECATED
1174 // set_look_yaw(self, radians)
1175 int ObjectRef::l_set_look_yaw(lua_State *L)
1176 {
1177         NO_MAP_LOCK_REQUIRED;
1178
1179         log_deprecated(L,
1180                 "Deprecated call to set_look_yaw, use set_look_horizontal instead.");
1181
1182         ObjectRef *ref = checkobject(L, 1);
1183         PlayerSAO* co = getplayersao(ref);
1184         if (co == NULL) return 0;
1185         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1186         // Do it
1187         co->setYawAndSend(yaw);
1188         return 1;
1189 }
1190
1191 // set_breath(self, breath)
1192 int ObjectRef::l_set_breath(lua_State *L)
1193 {
1194         NO_MAP_LOCK_REQUIRED;
1195         ObjectRef *ref = checkobject(L, 1);
1196         PlayerSAO* co = getplayersao(ref);
1197         if (co == NULL) return 0;
1198         u16 breath = luaL_checknumber(L, 2);
1199         co->setBreath(breath);
1200
1201         return 0;
1202 }
1203
1204 // get_breath(self)
1205 int ObjectRef::l_get_breath(lua_State *L)
1206 {
1207         NO_MAP_LOCK_REQUIRED;
1208         ObjectRef *ref = checkobject(L, 1);
1209         PlayerSAO* co = getplayersao(ref);
1210         if (co == NULL) return 0;
1211         // Do it
1212         u16 breath = co->getBreath();
1213         lua_pushinteger (L, breath);
1214         return 1;
1215 }
1216
1217 // set_attribute(self, attribute, value)
1218 int ObjectRef::l_set_attribute(lua_State *L)
1219 {
1220         ObjectRef *ref = checkobject(L, 1);
1221         PlayerSAO* co = getplayersao(ref);
1222         if (co == NULL)
1223                 return 0;
1224
1225         std::string attr = luaL_checkstring(L, 2);
1226         if (lua_isnil(L, 3)) {
1227                 co->getMeta().removeString(attr);
1228         } else {
1229                 std::string value = luaL_checkstring(L, 3);
1230                 co->getMeta().setString(attr, value);
1231         }
1232         return 1;
1233 }
1234
1235 // get_attribute(self, attribute)
1236 int ObjectRef::l_get_attribute(lua_State *L)
1237 {
1238         ObjectRef *ref = checkobject(L, 1);
1239         PlayerSAO* co = getplayersao(ref);
1240         if (co == NULL)
1241                 return 0;
1242
1243         std::string attr = luaL_checkstring(L, 2);
1244
1245         std::string value;
1246         if (co->getMeta().getStringToRef(attr, value)) {
1247                 lua_pushstring(L, value.c_str());
1248                 return 1;
1249         }
1250
1251         return 0;
1252 }
1253
1254
1255 // get_meta(self, attribute)
1256 int ObjectRef::l_get_meta(lua_State *L)
1257 {
1258         ObjectRef *ref = checkobject(L, 1);
1259         PlayerSAO *co = getplayersao(ref);
1260         if (co == NULL)
1261                 return 0;
1262
1263         PlayerMetaRef::create(L, &co->getMeta());
1264         return 1;
1265 }
1266
1267
1268 // set_inventory_formspec(self, formspec)
1269 int ObjectRef::l_set_inventory_formspec(lua_State *L)
1270 {
1271         NO_MAP_LOCK_REQUIRED;
1272         ObjectRef *ref = checkobject(L, 1);
1273         RemotePlayer *player = getplayer(ref);
1274         if (player == NULL) return 0;
1275         std::string formspec = luaL_checkstring(L, 2);
1276
1277         player->inventory_formspec = formspec;
1278         getServer(L)->reportInventoryFormspecModified(player->getName());
1279         lua_pushboolean(L, true);
1280         return 1;
1281 }
1282
1283 // get_inventory_formspec(self) -> formspec
1284 int ObjectRef::l_get_inventory_formspec(lua_State *L)
1285 {
1286         NO_MAP_LOCK_REQUIRED;
1287         ObjectRef *ref = checkobject(L, 1);
1288         RemotePlayer *player = getplayer(ref);
1289         if (player == NULL) return 0;
1290
1291         std::string formspec = player->inventory_formspec;
1292         lua_pushlstring(L, formspec.c_str(), formspec.size());
1293         return 1;
1294 }
1295
1296 // set_formspec_prepend(self, formspec)
1297 int ObjectRef::l_set_formspec_prepend(lua_State *L)
1298 {
1299         NO_MAP_LOCK_REQUIRED;
1300         ObjectRef *ref = checkobject(L, 1);
1301         RemotePlayer *player = getplayer(ref);
1302         if (player == NULL)
1303                 return 0;
1304
1305         std::string formspec = luaL_checkstring(L, 2);
1306
1307         player->formspec_prepend = formspec;
1308         getServer(L)->reportFormspecPrependModified(player->getName());
1309         lua_pushboolean(L, true);
1310         return 1;
1311 }
1312
1313 // get_formspec_prepend(self) -> formspec
1314 int ObjectRef::l_get_formspec_prepend(lua_State *L)
1315 {
1316         NO_MAP_LOCK_REQUIRED;
1317         ObjectRef *ref = checkobject(L, 1);
1318         RemotePlayer *player = getplayer(ref);
1319         if (player == NULL)
1320                  return 0;
1321
1322         std::string formspec = player->formspec_prepend;
1323         lua_pushlstring(L, formspec.c_str(), formspec.size());
1324         return 1;
1325 }
1326
1327 // get_player_control(self)
1328 int ObjectRef::l_get_player_control(lua_State *L)
1329 {
1330         NO_MAP_LOCK_REQUIRED;
1331         ObjectRef *ref = checkobject(L, 1);
1332         RemotePlayer *player = getplayer(ref);
1333         if (player == NULL) {
1334                 lua_pushlstring(L, "", 0);
1335                 return 1;
1336         }
1337
1338         const PlayerControl &control = player->getPlayerControl();
1339         lua_newtable(L);
1340         lua_pushboolean(L, control.up);
1341         lua_setfield(L, -2, "up");
1342         lua_pushboolean(L, control.down);
1343         lua_setfield(L, -2, "down");
1344         lua_pushboolean(L, control.left);
1345         lua_setfield(L, -2, "left");
1346         lua_pushboolean(L, control.right);
1347         lua_setfield(L, -2, "right");
1348         lua_pushboolean(L, control.jump);
1349         lua_setfield(L, -2, "jump");
1350         lua_pushboolean(L, control.aux1);
1351         lua_setfield(L, -2, "aux1");
1352         lua_pushboolean(L, control.sneak);
1353         lua_setfield(L, -2, "sneak");
1354         lua_pushboolean(L, control.LMB);
1355         lua_setfield(L, -2, "LMB");
1356         lua_pushboolean(L, control.RMB);
1357         lua_setfield(L, -2, "RMB");
1358         return 1;
1359 }
1360
1361 // get_player_control_bits(self)
1362 int ObjectRef::l_get_player_control_bits(lua_State *L)
1363 {
1364         NO_MAP_LOCK_REQUIRED;
1365         ObjectRef *ref = checkobject(L, 1);
1366         RemotePlayer *player = getplayer(ref);
1367         if (player == NULL) {
1368                 lua_pushlstring(L, "", 0);
1369                 return 1;
1370         }
1371         // Do it
1372         lua_pushnumber(L, player->keyPressed);
1373         return 1;
1374 }
1375
1376 // hud_add(self, form)
1377 int ObjectRef::l_hud_add(lua_State *L)
1378 {
1379         NO_MAP_LOCK_REQUIRED;
1380         ObjectRef *ref = checkobject(L, 1);
1381         RemotePlayer *player = getplayer(ref);
1382         if (player == NULL)
1383                 return 0;
1384
1385         HudElement *elem = new HudElement;
1386         read_hud_element(L, elem);
1387
1388         u32 id = getServer(L)->hudAdd(player, elem);
1389         if (id == U32_MAX) {
1390                 delete elem;
1391                 return 0;
1392         }
1393
1394         lua_pushnumber(L, id);
1395         return 1;
1396 }
1397
1398 // hud_remove(self, id)
1399 int ObjectRef::l_hud_remove(lua_State *L)
1400 {
1401         NO_MAP_LOCK_REQUIRED;
1402         ObjectRef *ref = checkobject(L, 1);
1403         RemotePlayer *player = getplayer(ref);
1404         if (player == NULL)
1405                 return 0;
1406
1407         u32 id = -1;
1408         if (!lua_isnil(L, 2))
1409                 id = lua_tonumber(L, 2);
1410
1411         if (!getServer(L)->hudRemove(player, id))
1412                 return 0;
1413
1414         lua_pushboolean(L, true);
1415         return 1;
1416 }
1417
1418 // hud_change(self, id, stat, data)
1419 int ObjectRef::l_hud_change(lua_State *L)
1420 {
1421         NO_MAP_LOCK_REQUIRED;
1422         ObjectRef *ref = checkobject(L, 1);
1423         RemotePlayer *player = getplayer(ref);
1424         if (player == NULL)
1425                 return 0;
1426
1427         u32 id = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : -1;
1428
1429         HudElement *e = player->getHud(id);
1430         if (!e)
1431                 return 0;
1432
1433         void *value = NULL;
1434         HudElementStat stat = read_hud_change(L, e, &value);
1435
1436         getServer(L)->hudChange(player, id, stat, value);
1437
1438         lua_pushboolean(L, true);
1439         return 1;
1440 }
1441
1442 // hud_get(self, id)
1443 int ObjectRef::l_hud_get(lua_State *L)
1444 {
1445         NO_MAP_LOCK_REQUIRED;
1446         ObjectRef *ref = checkobject(L, 1);
1447         RemotePlayer *player = getplayer(ref);
1448         if (player == NULL)
1449                 return 0;
1450
1451         u32 id = lua_tonumber(L, -1);
1452
1453         HudElement *e = player->getHud(id);
1454         if (!e)
1455                 return 0;
1456         push_hud_element(L, e);
1457         return 1;
1458 }
1459
1460 // hud_set_flags(self, flags)
1461 int ObjectRef::l_hud_set_flags(lua_State *L)
1462 {
1463         NO_MAP_LOCK_REQUIRED;
1464         ObjectRef *ref = checkobject(L, 1);
1465         RemotePlayer *player = getplayer(ref);
1466         if (player == NULL)
1467                 return 0;
1468
1469         u32 flags = 0;
1470         u32 mask  = 0;
1471         bool flag;
1472
1473         const EnumString *esp = es_HudBuiltinElement;
1474         for (int i = 0; esp[i].str; i++) {
1475                 if (getboolfield(L, 2, esp[i].str, flag)) {
1476                         flags |= esp[i].num * flag;
1477                         mask  |= esp[i].num;
1478                 }
1479         }
1480         if (!getServer(L)->hudSetFlags(player, flags, mask))
1481                 return 0;
1482
1483         lua_pushboolean(L, true);
1484         return 1;
1485 }
1486
1487 int ObjectRef::l_hud_get_flags(lua_State *L)
1488 {
1489         NO_MAP_LOCK_REQUIRED;
1490         ObjectRef *ref = checkobject(L, 1);
1491         RemotePlayer *player = getplayer(ref);
1492         if (player == NULL)
1493                 return 0;
1494
1495         lua_newtable(L);
1496         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
1497         lua_setfield(L, -2, "hotbar");
1498         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
1499         lua_setfield(L, -2, "healthbar");
1500         lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
1501         lua_setfield(L, -2, "crosshair");
1502         lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
1503         lua_setfield(L, -2, "wielditem");
1504         lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
1505         lua_setfield(L, -2, "breathbar");
1506         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1507         lua_setfield(L, -2, "minimap");
1508         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1509         lua_setfield(L, -2, "minimap_radar");
1510
1511         return 1;
1512 }
1513
1514 // hud_set_hotbar_itemcount(self, hotbar_itemcount)
1515 int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
1516 {
1517         NO_MAP_LOCK_REQUIRED;
1518         ObjectRef *ref = checkobject(L, 1);
1519         RemotePlayer *player = getplayer(ref);
1520         if (player == NULL)
1521                 return 0;
1522
1523         s32 hotbar_itemcount = lua_tonumber(L, 2);
1524
1525         if (!getServer(L)->hudSetHotbarItemcount(player, hotbar_itemcount))
1526                 return 0;
1527
1528         lua_pushboolean(L, true);
1529         return 1;
1530 }
1531
1532 // hud_get_hotbar_itemcount(self)
1533 int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
1534 {
1535         NO_MAP_LOCK_REQUIRED;
1536         ObjectRef *ref = checkobject(L, 1);
1537         RemotePlayer *player = getplayer(ref);
1538         if (player == NULL)
1539                 return 0;
1540
1541         lua_pushnumber(L, player->getHotbarItemcount());
1542         return 1;
1543 }
1544
1545 // hud_set_hotbar_image(self, name)
1546 int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
1547 {
1548         NO_MAP_LOCK_REQUIRED;
1549         ObjectRef *ref = checkobject(L, 1);
1550         RemotePlayer *player = getplayer(ref);
1551         if (player == NULL)
1552                 return 0;
1553
1554         std::string name = lua_tostring(L, 2);
1555
1556         getServer(L)->hudSetHotbarImage(player, name);
1557         return 1;
1558 }
1559
1560 // hud_get_hotbar_image(self)
1561 int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
1562 {
1563         NO_MAP_LOCK_REQUIRED;
1564         ObjectRef *ref = checkobject(L, 1);
1565         RemotePlayer *player = getplayer(ref);
1566         if (player == NULL)
1567                 return 0;
1568
1569         const std::string &name = player->getHotbarImage();
1570         lua_pushlstring(L, name.c_str(), name.size());
1571         return 1;
1572 }
1573
1574 // hud_set_hotbar_selected_image(self, name)
1575 int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
1576 {
1577         NO_MAP_LOCK_REQUIRED;
1578         ObjectRef *ref = checkobject(L, 1);
1579         RemotePlayer *player = getplayer(ref);
1580         if (player == NULL)
1581                 return 0;
1582
1583         std::string name = lua_tostring(L, 2);
1584
1585         getServer(L)->hudSetHotbarSelectedImage(player, name);
1586         return 1;
1587 }
1588
1589 // hud_get_hotbar_selected_image(self)
1590 int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
1591 {
1592         NO_MAP_LOCK_REQUIRED;
1593         ObjectRef *ref = checkobject(L, 1);
1594         RemotePlayer *player = getplayer(ref);
1595         if (player == NULL)
1596                 return 0;
1597
1598         const std::string &name = player->getHotbarSelectedImage();
1599         lua_pushlstring(L, name.c_str(), name.size());
1600         return 1;
1601 }
1602
1603 // set_sky(self, bgcolor, type, list, clouds = true)
1604 int ObjectRef::l_set_sky(lua_State *L)
1605 {
1606         NO_MAP_LOCK_REQUIRED;
1607         ObjectRef *ref = checkobject(L, 1);
1608         RemotePlayer *player = getplayer(ref);
1609         if (player == NULL)
1610                 return 0;
1611
1612         video::SColor bgcolor(255,255,255,255);
1613         read_color(L, 2, &bgcolor);
1614
1615         std::string type = luaL_checkstring(L, 3);
1616
1617         std::vector<std::string> params;
1618         if (lua_istable(L, 4)) {
1619                 lua_pushnil(L);
1620                 while (lua_next(L, 4) != 0) {
1621                         // key at index -2 and value at index -1
1622                         if (lua_isstring(L, -1))
1623                                 params.emplace_back(lua_tostring(L, -1));
1624                         else
1625                                 params.emplace_back("");
1626                         // removes value, keeps key for next iteration
1627                         lua_pop(L, 1);
1628                 }
1629         }
1630
1631         if (type == "skybox" && params.size() != 6)
1632                 throw LuaError("skybox expects 6 textures");
1633
1634         bool clouds = true;
1635         if (lua_isboolean(L, 5))
1636                 clouds = lua_toboolean(L, 5);
1637
1638         getServer(L)->setSky(player, bgcolor, type, params, clouds);
1639         lua_pushboolean(L, true);
1640         return 1;
1641 }
1642
1643 // get_sky(self)
1644 int ObjectRef::l_get_sky(lua_State *L)
1645 {
1646         NO_MAP_LOCK_REQUIRED;
1647         ObjectRef *ref = checkobject(L, 1);
1648         RemotePlayer *player = getplayer(ref);
1649         if (player == NULL)
1650                 return 0;
1651         video::SColor bgcolor(255, 255, 255, 255);
1652         std::string type;
1653         std::vector<std::string> params;
1654         bool clouds;
1655
1656         player->getSky(&bgcolor, &type, &params, &clouds);
1657         type = type.empty() ? "regular" : type;
1658
1659         push_ARGB8(L, bgcolor);
1660         lua_pushlstring(L, type.c_str(), type.size());
1661         lua_newtable(L);
1662         s16 i = 1;
1663         for (const std::string &param : params) {
1664                 lua_pushlstring(L, param.c_str(), param.size());
1665                 lua_rawseti(L, -2, i);
1666                 i++;
1667         }
1668         lua_pushboolean(L, clouds);
1669         return 4;
1670 }
1671
1672 // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
1673 int ObjectRef::l_set_clouds(lua_State *L)
1674 {
1675         NO_MAP_LOCK_REQUIRED;
1676         ObjectRef *ref = checkobject(L, 1);
1677         RemotePlayer *player = getplayer(ref);
1678         if (!player)
1679                 return 0;
1680         if (!lua_istable(L, 2))
1681                 return 0;
1682
1683         CloudParams cloud_params = player->getCloudParams();
1684
1685         cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
1686
1687         lua_getfield(L, 2, "color");
1688         if (!lua_isnil(L, -1))
1689                 read_color(L, -1, &cloud_params.color_bright);
1690         lua_pop(L, 1);
1691         lua_getfield(L, 2, "ambient");
1692         if (!lua_isnil(L, -1))
1693                 read_color(L, -1, &cloud_params.color_ambient);
1694         lua_pop(L, 1);
1695
1696         cloud_params.height    = getfloatfield_default(L, 2, "height",    cloud_params.height   );
1697         cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
1698
1699         lua_getfield(L, 2, "speed");
1700         if (lua_istable(L, -1)) {
1701                 v2f new_speed;
1702                 new_speed.X = getfloatfield_default(L, -1, "x", 0);
1703                 new_speed.Y = getfloatfield_default(L, -1, "z", 0);
1704                 cloud_params.speed = new_speed;
1705         }
1706         lua_pop(L, 1);
1707
1708         getServer(L)->setClouds(player, cloud_params);
1709         lua_pushboolean(L, true);
1710         return 1;
1711 }
1712
1713 int ObjectRef::l_get_clouds(lua_State *L)
1714 {
1715         NO_MAP_LOCK_REQUIRED;
1716         ObjectRef *ref = checkobject(L, 1);
1717         RemotePlayer *player = getplayer(ref);
1718         if (!player)
1719                 return 0;
1720         const CloudParams &cloud_params = player->getCloudParams();
1721
1722         lua_newtable(L);
1723         lua_pushnumber(L, cloud_params.density);
1724         lua_setfield(L, -2, "density");
1725         push_ARGB8(L, cloud_params.color_bright);
1726         lua_setfield(L, -2, "color");
1727         push_ARGB8(L, cloud_params.color_ambient);
1728         lua_setfield(L, -2, "ambient");
1729         lua_pushnumber(L, cloud_params.height);
1730         lua_setfield(L, -2, "height");
1731         lua_pushnumber(L, cloud_params.thickness);
1732         lua_setfield(L, -2, "thickness");
1733         lua_newtable(L);
1734         lua_pushnumber(L, cloud_params.speed.X);
1735         lua_setfield(L, -2, "x");
1736         lua_pushnumber(L, cloud_params.speed.Y);
1737         lua_setfield(L, -2, "y");
1738         lua_setfield(L, -2, "speed");
1739
1740         return 1;
1741 }
1742
1743
1744 // override_day_night_ratio(self, brightness=0...1)
1745 int ObjectRef::l_override_day_night_ratio(lua_State *L)
1746 {
1747         NO_MAP_LOCK_REQUIRED;
1748         ObjectRef *ref = checkobject(L, 1);
1749         RemotePlayer *player = getplayer(ref);
1750         if (player == NULL)
1751                 return 0;
1752
1753         bool do_override = false;
1754         float ratio = 0.0f;
1755         if (!lua_isnil(L, 2)) {
1756                 do_override = true;
1757                 ratio = luaL_checknumber(L, 2);
1758         }
1759
1760         if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio))
1761                 return 0;
1762
1763         lua_pushboolean(L, true);
1764         return 1;
1765 }
1766
1767 // get_day_night_ratio(self)
1768 int ObjectRef::l_get_day_night_ratio(lua_State *L)
1769 {
1770         NO_MAP_LOCK_REQUIRED;
1771         ObjectRef *ref = checkobject(L, 1);
1772         RemotePlayer *player = getplayer(ref);
1773         if (player == NULL)
1774                 return 0;
1775
1776         bool do_override;
1777         float ratio;
1778         player->getDayNightRatio(&do_override, &ratio);
1779
1780         if (do_override)
1781                 lua_pushnumber(L, ratio);
1782         else
1783                 lua_pushnil(L);
1784
1785         return 1;
1786 }
1787
1788 ObjectRef::ObjectRef(ServerActiveObject *object):
1789         m_object(object)
1790 {
1791         //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
1792 }
1793
1794 // Creates an ObjectRef and leaves it on top of stack
1795 // Not callable from Lua; all references are created on the C side.
1796 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
1797 {
1798         ObjectRef *o = new ObjectRef(object);
1799         //infostream<<"ObjectRef::create: o="<<o<<std::endl;
1800         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
1801         luaL_getmetatable(L, className);
1802         lua_setmetatable(L, -2);
1803 }
1804
1805 void ObjectRef::set_null(lua_State *L)
1806 {
1807         ObjectRef *o = checkobject(L, -1);
1808         o->m_object = NULL;
1809 }
1810
1811 void ObjectRef::Register(lua_State *L)
1812 {
1813         lua_newtable(L);
1814         int methodtable = lua_gettop(L);
1815         luaL_newmetatable(L, className);
1816         int metatable = lua_gettop(L);
1817
1818         lua_pushliteral(L, "__metatable");
1819         lua_pushvalue(L, methodtable);
1820         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
1821
1822         lua_pushliteral(L, "__index");
1823         lua_pushvalue(L, methodtable);
1824         lua_settable(L, metatable);
1825
1826         lua_pushliteral(L, "__gc");
1827         lua_pushcfunction(L, gc_object);
1828         lua_settable(L, metatable);
1829
1830         lua_pop(L, 1);  // drop metatable
1831
1832         luaL_openlib(L, 0, methods, 0);  // fill methodtable
1833         lua_pop(L, 1);  // drop methodtable
1834
1835         // Cannot be created from Lua
1836         //lua_register(L, className, create_object);
1837 }
1838
1839 const char ObjectRef::className[] = "ObjectRef";
1840 const luaL_Reg ObjectRef::methods[] = {
1841         // ServerActiveObject
1842         luamethod(ObjectRef, remove),
1843         luamethod_aliased(ObjectRef, get_pos, getpos),
1844         luamethod_aliased(ObjectRef, set_pos, setpos),
1845         luamethod_aliased(ObjectRef, move_to, moveto),
1846         luamethod(ObjectRef, punch),
1847         luamethod(ObjectRef, right_click),
1848         luamethod(ObjectRef, set_hp),
1849         luamethod(ObjectRef, get_hp),
1850         luamethod(ObjectRef, get_inventory),
1851         luamethod(ObjectRef, get_wield_list),
1852         luamethod(ObjectRef, get_wield_index),
1853         luamethod(ObjectRef, get_wielded_item),
1854         luamethod(ObjectRef, set_wielded_item),
1855         luamethod(ObjectRef, set_armor_groups),
1856         luamethod(ObjectRef, get_armor_groups),
1857         luamethod(ObjectRef, set_animation),
1858         luamethod(ObjectRef, get_animation),
1859         luamethod(ObjectRef, set_animation_frame_speed),
1860         luamethod(ObjectRef, set_bone_position),
1861         luamethod(ObjectRef, get_bone_position),
1862         luamethod(ObjectRef, set_attach),
1863         luamethod(ObjectRef, get_attach),
1864         luamethod(ObjectRef, set_detach),
1865         luamethod(ObjectRef, set_properties),
1866         luamethod(ObjectRef, get_properties),
1867         luamethod(ObjectRef, set_nametag_attributes),
1868         luamethod(ObjectRef, get_nametag_attributes),
1869         // LuaEntitySAO-only
1870         luamethod_aliased(ObjectRef, set_velocity, setvelocity),
1871         luamethod(ObjectRef, add_velocity),
1872         luamethod_aliased(ObjectRef, get_velocity, getvelocity),
1873         luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
1874         luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
1875         luamethod_aliased(ObjectRef, set_yaw, setyaw),
1876         luamethod_aliased(ObjectRef, get_yaw, getyaw),
1877         luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
1878         luamethod_aliased(ObjectRef, set_sprite, setsprite),
1879         luamethod(ObjectRef, get_entity_name),
1880         luamethod(ObjectRef, get_luaentity),
1881         // Player-only
1882         luamethod(ObjectRef, is_player),
1883         luamethod(ObjectRef, is_player_connected),
1884         luamethod(ObjectRef, get_player_name),
1885         luamethod(ObjectRef, get_player_velocity),
1886         luamethod(ObjectRef, get_look_dir),
1887         luamethod(ObjectRef, get_look_pitch),
1888         luamethod(ObjectRef, get_look_yaw),
1889         luamethod(ObjectRef, get_look_vertical),
1890         luamethod(ObjectRef, get_look_horizontal),
1891         luamethod(ObjectRef, set_look_horizontal),
1892         luamethod(ObjectRef, set_look_vertical),
1893         luamethod(ObjectRef, set_look_yaw),
1894         luamethod(ObjectRef, set_look_pitch),
1895         luamethod(ObjectRef, get_breath),
1896         luamethod(ObjectRef, set_breath),
1897         luamethod(ObjectRef, get_attribute),
1898         luamethod(ObjectRef, set_attribute),
1899         luamethod(ObjectRef, get_meta),
1900         luamethod(ObjectRef, set_inventory_formspec),
1901         luamethod(ObjectRef, get_inventory_formspec),
1902         luamethod(ObjectRef, set_formspec_prepend),
1903         luamethod(ObjectRef, get_formspec_prepend),
1904         luamethod(ObjectRef, get_player_control),
1905         luamethod(ObjectRef, get_player_control_bits),
1906         luamethod(ObjectRef, set_physics_override),
1907         luamethod(ObjectRef, get_physics_override),
1908         luamethod(ObjectRef, hud_add),
1909         luamethod(ObjectRef, hud_remove),
1910         luamethod(ObjectRef, hud_change),
1911         luamethod(ObjectRef, hud_get),
1912         luamethod(ObjectRef, hud_set_flags),
1913         luamethod(ObjectRef, hud_get_flags),
1914         luamethod(ObjectRef, hud_set_hotbar_itemcount),
1915         luamethod(ObjectRef, hud_get_hotbar_itemcount),
1916         luamethod(ObjectRef, hud_set_hotbar_image),
1917         luamethod(ObjectRef, hud_get_hotbar_image),
1918         luamethod(ObjectRef, hud_set_hotbar_selected_image),
1919         luamethod(ObjectRef, hud_get_hotbar_selected_image),
1920         luamethod(ObjectRef, set_sky),
1921         luamethod(ObjectRef, get_sky),
1922         luamethod(ObjectRef, set_clouds),
1923         luamethod(ObjectRef, get_clouds),
1924         luamethod(ObjectRef, override_day_night_ratio),
1925         luamethod(ObjectRef, get_day_night_ratio),
1926         luamethod(ObjectRef, set_local_animation),
1927         luamethod(ObjectRef, get_local_animation),
1928         luamethod(ObjectRef, set_eye_offset),
1929         luamethod(ObjectRef, get_eye_offset),
1930         {0,0}
1931 };