Exposing the zoom key to Lua API (#9903)
[oweals/minetest.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 "remoteplayer.h"
31 #include "server.h"
32 #include "hud.h"
33 #include "scripting_server.h"
34 #include "server/luaentity_sao.h"
35 #include "server/player_sao.h"
36 #include "server/serverinventorymgr.h"
37
38 /*
39         ObjectRef
40 */
41
42
43 ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
44 {
45         luaL_checktype(L, narg, LUA_TUSERDATA);
46         void *ud = luaL_checkudata(L, narg, className);
47         if (!ud) luaL_typerror(L, narg, className);
48         return *(ObjectRef**)ud;  // unbox pointer
49 }
50
51 ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
52 {
53         ServerActiveObject *co = ref->m_object;
54         if (co && co->isGone())
55                 return NULL;
56         return co;
57 }
58
59 LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
60 {
61         ServerActiveObject *obj = getobject(ref);
62         if (obj == NULL)
63                 return NULL;
64         if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
65                 return NULL;
66         return (LuaEntitySAO*)obj;
67 }
68
69 PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
70 {
71         ServerActiveObject *obj = getobject(ref);
72         if (obj == NULL)
73                 return NULL;
74         if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
75                 return NULL;
76         return (PlayerSAO*)obj;
77 }
78
79 RemotePlayer *ObjectRef::getplayer(ObjectRef *ref)
80 {
81         PlayerSAO *playersao = getplayersao(ref);
82         if (playersao == NULL)
83                 return NULL;
84         return playersao->getPlayer();
85 }
86
87 // Exported functions
88
89 // garbage collector
90 int ObjectRef::gc_object(lua_State *L) {
91         ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
92         //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
93         delete o;
94         return 0;
95 }
96
97 // remove(self)
98 int ObjectRef::l_remove(lua_State *L)
99 {
100         GET_ENV_PTR;
101
102         ObjectRef *ref = checkobject(L, 1);
103         ServerActiveObject *co = getobject(ref);
104         if (co == NULL)
105                 return 0;
106         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
107                 return 0;
108
109         co->clearChildAttachments();
110         co->clearParentAttachment();
111
112         verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl;
113         co->m_pending_removal = true;
114         return 0;
115 }
116
117 // get_pos(self)
118 // returns: {x=num, y=num, z=num}
119 int ObjectRef::l_get_pos(lua_State *L)
120 {
121         NO_MAP_LOCK_REQUIRED;
122         ObjectRef *ref = checkobject(L, 1);
123         ServerActiveObject *co = getobject(ref);
124         if (co == NULL) return 0;
125         push_v3f(L, co->getBasePosition() / BS);
126         return 1;
127 }
128
129 // set_pos(self, pos)
130 int ObjectRef::l_set_pos(lua_State *L)
131 {
132         NO_MAP_LOCK_REQUIRED;
133         ObjectRef *ref = checkobject(L, 1);
134         ServerActiveObject *co = getobject(ref);
135         if (co == NULL) return 0;
136         // pos
137         v3f pos = checkFloatPos(L, 2);
138         // Do it
139         co->setPos(pos);
140         return 0;
141 }
142
143 // move_to(self, pos, continuous=false)
144 int ObjectRef::l_move_to(lua_State *L)
145 {
146         NO_MAP_LOCK_REQUIRED;
147         ObjectRef *ref = checkobject(L, 1);
148         ServerActiveObject *co = getobject(ref);
149         if (co == NULL) return 0;
150         // pos
151         v3f pos = checkFloatPos(L, 2);
152         // continuous
153         bool continuous = readParam<bool>(L, 3);
154         // Do it
155         co->moveTo(pos, continuous);
156         return 0;
157 }
158
159 // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
160 int ObjectRef::l_punch(lua_State *L)
161 {
162         NO_MAP_LOCK_REQUIRED;
163         ObjectRef *ref = checkobject(L, 1);
164         ObjectRef *puncher_ref = checkobject(L, 2);
165         ServerActiveObject *co = getobject(ref);
166         ServerActiveObject *puncher = getobject(puncher_ref);
167         if (!co || !puncher)
168                 return 0;
169         v3f dir;
170         if (lua_type(L, 5) != LUA_TTABLE)
171                 dir = co->getBasePosition() - puncher->getBasePosition();
172         else
173                 dir = read_v3f(L, 5);
174         float time_from_last_punch = 1000000;
175         if (lua_isnumber(L, 3))
176                 time_from_last_punch = lua_tonumber(L, 3);
177         ToolCapabilities toolcap = read_tool_capabilities(L, 4);
178         dir.normalize();
179
180         u16 src_original_hp = co->getHP();
181         u16 dst_origin_hp = puncher->getHP();
182
183         // Do it
184         u16 wear = co->punch(dir, &toolcap, puncher, time_from_last_punch);
185         lua_pushnumber(L, wear);
186
187         // If the punched is a player, and its HP changed
188         if (src_original_hp != co->getHP() &&
189                         co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
190                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co,
191                                 PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
192         }
193
194         // If the puncher is a player, and its HP changed
195         if (dst_origin_hp != puncher->getHP() &&
196                         puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
197                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher,
198                                 PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co));
199         }
200         return 1;
201 }
202
203 // right_click(self, clicker); clicker = an another ObjectRef
204 int ObjectRef::l_right_click(lua_State *L)
205 {
206         NO_MAP_LOCK_REQUIRED;
207         ObjectRef *ref = checkobject(L, 1);
208         ObjectRef *ref2 = checkobject(L, 2);
209         ServerActiveObject *co = getobject(ref);
210         ServerActiveObject *co2 = getobject(ref2);
211         if (co == NULL) return 0;
212         if (co2 == NULL) return 0;
213         // Do it
214         co->rightClick(co2);
215         return 0;
216 }
217
218 // set_hp(self, hp)
219 // hp = number of hitpoints (2 * number of hearts)
220 // returns: nil
221 int ObjectRef::l_set_hp(lua_State *L)
222 {
223         NO_MAP_LOCK_REQUIRED;
224
225         // Get Object
226         ObjectRef *ref = checkobject(L, 1);
227         luaL_checknumber(L, 2);
228         ServerActiveObject *co = getobject(ref);
229         if (co == NULL)
230                 return 0;
231
232         // Get HP
233         int hp = lua_tonumber(L, 2);
234
235         // Get Reason
236         PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
237         reason.from_mod = true;
238         if (lua_istable(L, 3)) {
239                 lua_pushvalue(L, 3);
240
241                 lua_getfield(L, -1, "type");
242                 if (lua_isstring(L, -1) &&
243                                 !reason.setTypeFromString(readParam<std::string>(L, -1))) {
244                         errorstream << "Bad type given!" << std::endl;
245                 }
246                 lua_pop(L, 1);
247
248                 reason.lua_reference = luaL_ref(L, LUA_REGISTRYINDEX);
249         }
250
251         // Do it
252         co->setHP(hp, reason);
253         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
254                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
255
256         if (reason.hasLuaReference())
257                 luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference);
258
259         // Return
260         return 0;
261 }
262
263 // get_hp(self)
264 // returns: number of hitpoints (2 * number of hearts)
265 // 0 if not applicable to this type of object
266 int ObjectRef::l_get_hp(lua_State *L)
267 {
268         NO_MAP_LOCK_REQUIRED;
269         ObjectRef *ref = checkobject(L, 1);
270         ServerActiveObject *co = getobject(ref);
271         if (co == NULL) {
272                 // Default hp is 1
273                 lua_pushnumber(L, 1);
274                 return 1;
275         }
276         int hp = co->getHP();
277         /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
278                         <<" hp="<<hp<<std::endl;*/
279         // Return
280         lua_pushnumber(L, hp);
281         return 1;
282 }
283
284 // get_inventory(self)
285 int ObjectRef::l_get_inventory(lua_State *L)
286 {
287         NO_MAP_LOCK_REQUIRED;
288         ObjectRef *ref = checkobject(L, 1);
289         ServerActiveObject *co = getobject(ref);
290         if (co == NULL) return 0;
291         // Do it
292         InventoryLocation loc = co->getInventoryLocation();
293         if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
294                 InvRef::create(L, loc);
295         else
296                 lua_pushnil(L); // An object may have no inventory (nil)
297         return 1;
298 }
299
300 // get_wield_list(self)
301 int ObjectRef::l_get_wield_list(lua_State *L)
302 {
303         NO_MAP_LOCK_REQUIRED;
304         ObjectRef *ref = checkobject(L, 1);
305         ServerActiveObject *co = getobject(ref);
306         if (!co)
307                 return 0;
308
309         lua_pushstring(L, co->getWieldList().c_str());
310         return 1;
311 }
312
313 // get_wield_index(self)
314 int ObjectRef::l_get_wield_index(lua_State *L)
315 {
316         NO_MAP_LOCK_REQUIRED;
317         ObjectRef *ref = checkobject(L, 1);
318         ServerActiveObject *co = getobject(ref);
319         if (!co)
320                 return 0;
321
322         lua_pushinteger(L, co->getWieldIndex() + 1);
323         return 1;
324 }
325
326 // get_wielded_item(self)
327 int ObjectRef::l_get_wielded_item(lua_State *L)
328 {
329         NO_MAP_LOCK_REQUIRED;
330         ObjectRef *ref = checkobject(L, 1);
331         ServerActiveObject *co = getobject(ref);
332         if (!co) {
333                 // Empty ItemStack
334                 LuaItemStack::create(L, ItemStack());
335                 return 1;
336         }
337
338         ItemStack selected_item;
339         co->getWieldedItem(&selected_item, nullptr);
340         LuaItemStack::create(L, selected_item);
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, true);
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 = readParam<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 = readParam<bool>(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 // send_mapblock(self, pos)
587 int ObjectRef::l_send_mapblock(lua_State *L)
588 {
589         NO_MAP_LOCK_REQUIRED;
590         ObjectRef *ref = checkobject(L, 1);
591
592         RemotePlayer *player = getplayer(ref);
593         if (!player)
594                 return 0;
595         v3s16 p = read_v3s16(L, 2);
596
597         session_t peer_id = player->getPeerId();
598         bool r = getServer(L)->SendBlock(peer_id, p);
599
600         lua_pushboolean(L, r);
601         return 1;
602 }
603
604 // set_animation_frame_speed(self, frame_speed)
605 int ObjectRef::l_set_animation_frame_speed(lua_State *L)
606 {
607         NO_MAP_LOCK_REQUIRED;
608         ObjectRef *ref = checkobject(L, 1);
609         ServerActiveObject *co = getobject(ref);
610         if (co == NULL)
611                 return 0;
612
613         // Do it
614         if (!lua_isnil(L, 2)) {
615                 float frame_speed = lua_tonumber(L, 2);
616                 co->setAnimationSpeed(frame_speed);
617                 lua_pushboolean(L, true);
618         } else {
619                 lua_pushboolean(L, false);
620         }
621         return 1;
622 }
623
624 // set_bone_position(self, std::string bone, v3f position, v3f rotation)
625 int ObjectRef::l_set_bone_position(lua_State *L)
626 {
627         NO_MAP_LOCK_REQUIRED;
628         ObjectRef *ref = checkobject(L, 1);
629         ServerActiveObject *co = getobject(ref);
630         if (co == NULL) return 0;
631         // Do it
632         std::string bone;
633         if (!lua_isnil(L, 2))
634                 bone = readParam<std::string>(L, 2);
635         v3f position = v3f(0, 0, 0);
636         if (!lua_isnil(L, 3))
637                 position = check_v3f(L, 3);
638         v3f rotation = v3f(0, 0, 0);
639         if (!lua_isnil(L, 4))
640                 rotation = check_v3f(L, 4);
641         co->setBonePosition(bone, position, rotation);
642         return 0;
643 }
644
645 // get_bone_position(self, bone)
646 int ObjectRef::l_get_bone_position(lua_State *L)
647 {
648         NO_MAP_LOCK_REQUIRED;
649         ObjectRef *ref = checkobject(L, 1);
650         ServerActiveObject *co = getobject(ref);
651         if (co == NULL)
652                 return 0;
653         // Do it
654         std::string bone;
655         if (!lua_isnil(L, 2))
656                 bone = readParam<std::string>(L, 2);
657
658         v3f position = v3f(0, 0, 0);
659         v3f rotation = v3f(0, 0, 0);
660         co->getBonePosition(bone, &position, &rotation);
661
662         push_v3f(L, position);
663         push_v3f(L, rotation);
664         return 2;
665 }
666
667 // set_attach(self, parent, bone, position, rotation)
668 int ObjectRef::l_set_attach(lua_State *L)
669 {
670         GET_ENV_PTR;
671
672         ObjectRef *ref = checkobject(L, 1);
673         ObjectRef *parent_ref = checkobject(L, 2);
674         ServerActiveObject *co = getobject(ref);
675         ServerActiveObject *parent = getobject(parent_ref);
676         if (co == NULL)
677                 return 0;
678
679         if (parent == NULL)
680                 return 0;
681
682         if (co == parent)
683                 throw LuaError("ObjectRef::set_attach: attaching object to itself is not allowed.");
684
685         // Do it
686         int parent_id = 0;
687         std::string bone;
688         v3f position = v3f(0, 0, 0);
689         v3f rotation = v3f(0, 0, 0);
690         co->getAttachment(&parent_id, &bone, &position, &rotation);
691         if (parent_id) {
692                 ServerActiveObject *old_parent = env->getActiveObject(parent_id);
693                 old_parent->removeAttachmentChild(co->getId());
694         }
695
696         bone = "";
697         if (!lua_isnil(L, 3))
698                 bone = readParam<std::string>(L, 3);
699         position = v3f(0, 0, 0);
700         if (!lua_isnil(L, 4))
701                 position = read_v3f(L, 4);
702         rotation = v3f(0, 0, 0);
703         if (!lua_isnil(L, 5))
704                 rotation = read_v3f(L, 5);
705         co->setAttachment(parent->getId(), bone, position, rotation);
706         parent->addAttachmentChild(co->getId());
707         return 0;
708 }
709
710 // get_attach(self)
711 int ObjectRef::l_get_attach(lua_State *L)
712 {
713         GET_ENV_PTR;
714
715         ObjectRef *ref = checkobject(L, 1);
716         ServerActiveObject *co = getobject(ref);
717         if (co == NULL)
718                 return 0;
719
720         // Do it
721         int parent_id = 0;
722         std::string bone;
723         v3f position = v3f(0, 0, 0);
724         v3f rotation = v3f(0, 0, 0);
725         co->getAttachment(&parent_id, &bone, &position, &rotation);
726         if (!parent_id)
727                 return 0;
728         ServerActiveObject *parent = env->getActiveObject(parent_id);
729
730         getScriptApiBase(L)->objectrefGetOrCreate(L, parent);
731         lua_pushlstring(L, bone.c_str(), bone.size());
732         push_v3f(L, position);
733         push_v3f(L, rotation);
734         return 4;
735 }
736
737 // set_detach(self)
738 int ObjectRef::l_set_detach(lua_State *L)
739 {
740         GET_ENV_PTR;
741
742         ObjectRef *ref = checkobject(L, 1);
743         ServerActiveObject *co = getobject(ref);
744         if (co == NULL)
745                 return 0;
746
747         co->clearParentAttachment();
748         return 0;
749 }
750
751 // set_properties(self, properties)
752 int ObjectRef::l_set_properties(lua_State *L)
753 {
754         NO_MAP_LOCK_REQUIRED;
755         ObjectRef *ref = checkobject(L, 1);
756         ServerActiveObject *co = getobject(ref);
757         if (!co)
758                 return 0;
759
760         ObjectProperties *prop = co->accessObjectProperties();
761         if (!prop)
762                 return 0;
763
764         read_object_properties(L, 2, co, prop, getServer(L)->idef());
765         co->notifyObjectPropertiesModified();
766         return 0;
767 }
768
769 // get_properties(self)
770 int ObjectRef::l_get_properties(lua_State *L)
771 {
772         NO_MAP_LOCK_REQUIRED;
773         ObjectRef *ref = checkobject(L, 1);
774         ServerActiveObject *co = getobject(ref);
775         if (co == NULL)
776                 return 0;
777         ObjectProperties *prop = co->accessObjectProperties();
778         if (!prop)
779                 return 0;
780         push_object_properties(L, prop);
781         return 1;
782 }
783
784 // is_player(self)
785 int ObjectRef::l_is_player(lua_State *L)
786 {
787         NO_MAP_LOCK_REQUIRED;
788         ObjectRef *ref = checkobject(L, 1);
789         RemotePlayer *player = getplayer(ref);
790         lua_pushboolean(L, (player != NULL));
791         return 1;
792 }
793
794 // set_nametag_attributes(self, attributes)
795 int ObjectRef::l_set_nametag_attributes(lua_State *L)
796 {
797         NO_MAP_LOCK_REQUIRED;
798         ObjectRef *ref = checkobject(L, 1);
799         ServerActiveObject *co = getobject(ref);
800
801         if (co == NULL)
802                 return 0;
803         ObjectProperties *prop = co->accessObjectProperties();
804         if (!prop)
805                 return 0;
806
807         lua_getfield(L, 2, "color");
808         if (!lua_isnil(L, -1)) {
809                 video::SColor color = prop->nametag_color;
810                 read_color(L, -1, &color);
811                 prop->nametag_color = color;
812         }
813         lua_pop(L, 1);
814
815         std::string nametag = getstringfield_default(L, 2, "text", "");
816         prop->nametag = nametag;
817
818         co->notifyObjectPropertiesModified();
819         lua_pushboolean(L, true);
820         return 1;
821 }
822
823 // get_nametag_attributes(self)
824 int ObjectRef::l_get_nametag_attributes(lua_State *L)
825 {
826         NO_MAP_LOCK_REQUIRED;
827         ObjectRef *ref = checkobject(L, 1);
828         ServerActiveObject *co = getobject(ref);
829
830         if (co == NULL)
831                 return 0;
832         ObjectProperties *prop = co->accessObjectProperties();
833         if (!prop)
834                 return 0;
835
836         video::SColor color = prop->nametag_color;
837
838         lua_newtable(L);
839         push_ARGB8(L, color);
840         lua_setfield(L, -2, "color");
841         lua_pushstring(L, prop->nametag.c_str());
842         lua_setfield(L, -2, "text");
843         return 1;
844 }
845
846 /* LuaEntitySAO-only */
847
848 // set_velocity(self, {x=num, y=num, z=num})
849 int ObjectRef::l_set_velocity(lua_State *L)
850 {
851         NO_MAP_LOCK_REQUIRED;
852         ObjectRef *ref = checkobject(L, 1);
853         LuaEntitySAO *co = getluaobject(ref);
854         if (co == NULL) return 0;
855         v3f pos = checkFloatPos(L, 2);
856         // Do it
857         co->setVelocity(pos);
858         return 0;
859 }
860
861 // add_velocity(self, {x=num, y=num, z=num})
862 int ObjectRef::l_add_velocity(lua_State *L)
863 {
864         NO_MAP_LOCK_REQUIRED;
865         ObjectRef *ref = checkobject(L, 1);
866         LuaEntitySAO *co = getluaobject(ref);
867         if (!co)
868                 return 0;
869         v3f pos = checkFloatPos(L, 2);
870         // Do it
871         co->addVelocity(pos);
872         return 0;
873 }
874
875 // get_velocity(self)
876 int ObjectRef::l_get_velocity(lua_State *L)
877 {
878         NO_MAP_LOCK_REQUIRED;
879         ObjectRef *ref = checkobject(L, 1);
880         LuaEntitySAO *co = getluaobject(ref);
881         if (co == NULL) return 0;
882         // Do it
883         v3f v = co->getVelocity();
884         pushFloatPos(L, v);
885         return 1;
886 }
887
888 // set_acceleration(self, {x=num, y=num, z=num})
889 int ObjectRef::l_set_acceleration(lua_State *L)
890 {
891         NO_MAP_LOCK_REQUIRED;
892         ObjectRef *ref = checkobject(L, 1);
893         LuaEntitySAO *co = getluaobject(ref);
894         if (co == NULL) return 0;
895         // pos
896         v3f pos = checkFloatPos(L, 2);
897         // Do it
898         co->setAcceleration(pos);
899         return 0;
900 }
901
902 // get_acceleration(self)
903 int ObjectRef::l_get_acceleration(lua_State *L)
904 {
905         NO_MAP_LOCK_REQUIRED;
906         ObjectRef *ref = checkobject(L, 1);
907         LuaEntitySAO *co = getluaobject(ref);
908         if (co == NULL) return 0;
909         // Do it
910         v3f v = co->getAcceleration();
911         pushFloatPos(L, v);
912         return 1;
913 }
914
915 // set_rotation(self, {x=num, y=num, z=num})
916 // Each 'num' is in radians
917 int ObjectRef::l_set_rotation(lua_State *L)
918 {
919         NO_MAP_LOCK_REQUIRED;
920         ObjectRef *ref = checkobject(L, 1);
921         LuaEntitySAO *co = getluaobject(ref);
922         if (!co)
923                 return 0;
924
925         v3f rotation = check_v3f(L, 2) * core::RADTODEG;
926         co->setRotation(rotation);
927         return 0;
928 }
929
930 // get_rotation(self)
931 // returns: {x=num, y=num, z=num}
932 // Each 'num' is in radians
933 int ObjectRef::l_get_rotation(lua_State *L)
934 {
935         NO_MAP_LOCK_REQUIRED;
936         ObjectRef *ref = checkobject(L, 1);
937         LuaEntitySAO *co = getluaobject(ref);
938         if (!co)
939                 return 0;
940
941         lua_newtable(L);
942         v3f rotation = co->getRotation() * core::DEGTORAD;
943         push_v3f(L, rotation);
944         return 1;
945 }
946
947 // set_yaw(self, radians)
948 int ObjectRef::l_set_yaw(lua_State *L)
949 {
950         NO_MAP_LOCK_REQUIRED;
951         ObjectRef *ref = checkobject(L, 1);
952         LuaEntitySAO *co = getluaobject(ref);
953
954         if (co == NULL) return 0;
955         if (isNaN(L, 2))
956                 throw LuaError("ObjectRef::set_yaw: NaN value is not allowed.");
957
958         float yaw = readParam<float>(L, 2) * core::RADTODEG;
959         co->setRotation(v3f(0, yaw, 0));
960         return 0;
961 }
962
963 // get_yaw(self)
964 int ObjectRef::l_get_yaw(lua_State *L)
965 {
966         NO_MAP_LOCK_REQUIRED;
967         ObjectRef *ref = checkobject(L, 1);
968         LuaEntitySAO *co = getluaobject(ref);
969         if (!co)
970                 return 0;
971
972         float yaw = co->getRotation().Y * core::DEGTORAD;
973         lua_pushnumber(L, yaw);
974         return 1;
975 }
976
977 // set_texture_mod(self, mod)
978 int ObjectRef::l_set_texture_mod(lua_State *L)
979 {
980         NO_MAP_LOCK_REQUIRED;
981         ObjectRef *ref = checkobject(L, 1);
982         LuaEntitySAO *co = getluaobject(ref);
983         if (co == NULL) return 0;
984         // Do it
985         std::string mod = luaL_checkstring(L, 2);
986         co->setTextureMod(mod);
987         return 0;
988 }
989
990 // get_texture_mod(self)
991 int ObjectRef::l_get_texture_mod(lua_State *L)
992 {
993         NO_MAP_LOCK_REQUIRED;
994         ObjectRef *ref = checkobject(L, 1);
995         LuaEntitySAO *co = getluaobject(ref);
996         if (co == NULL) return 0;
997         // Do it
998         std::string mod = co->getTextureMod();
999         lua_pushstring(L, mod.c_str());
1000         return 1;
1001 }
1002
1003 // set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
1004 //           select_horiz_by_yawpitch=false)
1005 int ObjectRef::l_set_sprite(lua_State *L)
1006 {
1007         NO_MAP_LOCK_REQUIRED;
1008         ObjectRef *ref = checkobject(L, 1);
1009         LuaEntitySAO *co = getluaobject(ref);
1010         if (co == NULL) return 0;
1011         // Do it
1012         v2s16 p(0,0);
1013         if (!lua_isnil(L, 2))
1014                 p = readParam<v2s16>(L, 2);
1015         int num_frames = 1;
1016         if (!lua_isnil(L, 3))
1017                 num_frames = lua_tonumber(L, 3);
1018         float framelength = 0.2;
1019         if (!lua_isnil(L, 4))
1020                 framelength = lua_tonumber(L, 4);
1021         bool select_horiz_by_yawpitch = false;
1022         if (!lua_isnil(L, 5))
1023                 select_horiz_by_yawpitch = readParam<bool>(L, 5);
1024         co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
1025         return 0;
1026 }
1027
1028 // DEPRECATED
1029 // get_entity_name(self)
1030 int ObjectRef::l_get_entity_name(lua_State *L)
1031 {
1032         NO_MAP_LOCK_REQUIRED;
1033         ObjectRef *ref = checkobject(L, 1);
1034         LuaEntitySAO *co = getluaobject(ref);
1035         log_deprecated(L,"Deprecated call to \"get_entity_name");
1036         if (co == NULL) return 0;
1037         // Do it
1038         std::string name = co->getName();
1039         lua_pushstring(L, name.c_str());
1040         return 1;
1041 }
1042
1043 // get_luaentity(self)
1044 int ObjectRef::l_get_luaentity(lua_State *L)
1045 {
1046         NO_MAP_LOCK_REQUIRED;
1047         ObjectRef *ref = checkobject(L, 1);
1048         LuaEntitySAO *co = getluaobject(ref);
1049         if (co == NULL) return 0;
1050         // Do it
1051         luaentity_get(L, co->getId());
1052         return 1;
1053 }
1054
1055 /* Player-only */
1056
1057 // is_player_connected(self)
1058 int ObjectRef::l_is_player_connected(lua_State *L)
1059 {
1060         NO_MAP_LOCK_REQUIRED;
1061         // This method was once added for a bugfix, but never documented
1062         log_deprecated(L, "is_player_connected is undocumented and "
1063                 "will be removed in a future release");
1064         ObjectRef *ref = checkobject(L, 1);
1065         RemotePlayer *player = getplayer(ref);
1066         lua_pushboolean(L, (player != NULL && player->getPeerId() != PEER_ID_INEXISTENT));
1067         return 1;
1068 }
1069
1070 // get_player_name(self)
1071 int ObjectRef::l_get_player_name(lua_State *L)
1072 {
1073         NO_MAP_LOCK_REQUIRED;
1074         ObjectRef *ref = checkobject(L, 1);
1075         RemotePlayer *player = getplayer(ref);
1076         if (player == NULL) {
1077                 lua_pushlstring(L, "", 0);
1078                 return 1;
1079         }
1080         // Do it
1081         lua_pushstring(L, player->getName());
1082         return 1;
1083 }
1084
1085 // get_player_velocity(self)
1086 int ObjectRef::l_get_player_velocity(lua_State *L)
1087 {
1088         NO_MAP_LOCK_REQUIRED;
1089         ObjectRef *ref = checkobject(L, 1);
1090         RemotePlayer *player = getplayer(ref);
1091         if (player == NULL) {
1092                 lua_pushnil(L);
1093                 return 1;
1094         }
1095         // Do it
1096         push_v3f(L, player->getSpeed() / BS);
1097         return 1;
1098 }
1099
1100 // add_player_velocity(self, {x=num, y=num, z=num})
1101 int ObjectRef::l_add_player_velocity(lua_State *L)
1102 {
1103         NO_MAP_LOCK_REQUIRED;
1104         ObjectRef *ref = checkobject(L, 1);
1105         v3f vel = checkFloatPos(L, 2);
1106
1107         PlayerSAO *co = getplayersao(ref);
1108         if (!co)
1109                 return 0;
1110
1111         // Do it
1112         co->setMaxSpeedOverride(vel);
1113         getServer(L)->SendPlayerSpeed(co->getPeerID(), vel);
1114         return 0;
1115 }
1116
1117 // get_look_dir(self)
1118 int ObjectRef::l_get_look_dir(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         float pitch = co->getRadLookPitchDep();
1126         float yaw = co->getRadYawDep();
1127         v3f v(std::cos(pitch) * std::cos(yaw), std::sin(pitch), std::cos(pitch) *
1128                 std::sin(yaw));
1129         push_v3f(L, v);
1130         return 1;
1131 }
1132
1133 // DEPRECATED
1134 // get_look_pitch(self)
1135 int ObjectRef::l_get_look_pitch(lua_State *L)
1136 {
1137         NO_MAP_LOCK_REQUIRED;
1138
1139         log_deprecated(L,
1140                 "Deprecated call to get_look_pitch, use get_look_vertical instead");
1141
1142         ObjectRef *ref = checkobject(L, 1);
1143         PlayerSAO* co = getplayersao(ref);
1144         if (co == NULL) return 0;
1145         // Do it
1146         lua_pushnumber(L, co->getRadLookPitchDep());
1147         return 1;
1148 }
1149
1150 // DEPRECATED
1151 // get_look_yaw(self)
1152 int ObjectRef::l_get_look_yaw(lua_State *L)
1153 {
1154         NO_MAP_LOCK_REQUIRED;
1155
1156         log_deprecated(L,
1157                 "Deprecated call to get_look_yaw, use get_look_horizontal instead");
1158
1159         ObjectRef *ref = checkobject(L, 1);
1160         PlayerSAO* co = getplayersao(ref);
1161         if (co == NULL) return 0;
1162         // Do it
1163         lua_pushnumber(L, co->getRadYawDep());
1164         return 1;
1165 }
1166
1167 // get_look_pitch2(self)
1168 int ObjectRef::l_get_look_vertical(lua_State *L)
1169 {
1170         NO_MAP_LOCK_REQUIRED;
1171         ObjectRef *ref = checkobject(L, 1);
1172         PlayerSAO* co = getplayersao(ref);
1173         if (co == NULL) return 0;
1174         // Do it
1175         lua_pushnumber(L, co->getRadLookPitch());
1176         return 1;
1177 }
1178
1179 // get_look_yaw2(self)
1180 int ObjectRef::l_get_look_horizontal(lua_State *L)
1181 {
1182         NO_MAP_LOCK_REQUIRED;
1183         ObjectRef *ref = checkobject(L, 1);
1184         PlayerSAO* co = getplayersao(ref);
1185         if (co == NULL) return 0;
1186         // Do it
1187         lua_pushnumber(L, co->getRadRotation().Y);
1188         return 1;
1189 }
1190
1191 // set_look_vertical(self, radians)
1192 int ObjectRef::l_set_look_vertical(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         float pitch = readParam<float>(L, 2) * core::RADTODEG;
1199         // Do it
1200         co->setLookPitchAndSend(pitch);
1201         return 1;
1202 }
1203
1204 // set_look_horizontal(self, radians)
1205 int ObjectRef::l_set_look_horizontal(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         float yaw = readParam<float>(L, 2) * core::RADTODEG;
1212         // Do it
1213         co->setPlayerYawAndSend(yaw);
1214         return 1;
1215 }
1216
1217 // DEPRECATED
1218 // set_look_pitch(self, radians)
1219 int ObjectRef::l_set_look_pitch(lua_State *L)
1220 {
1221         NO_MAP_LOCK_REQUIRED;
1222
1223         log_deprecated(L,
1224                 "Deprecated call to set_look_pitch, use set_look_vertical instead.");
1225
1226         ObjectRef *ref = checkobject(L, 1);
1227         PlayerSAO* co = getplayersao(ref);
1228         if (co == NULL) return 0;
1229         float pitch = readParam<float>(L, 2) * core::RADTODEG;
1230         // Do it
1231         co->setLookPitchAndSend(pitch);
1232         return 1;
1233 }
1234
1235 // DEPRECATED
1236 // set_look_yaw(self, radians)
1237 int ObjectRef::l_set_look_yaw(lua_State *L)
1238 {
1239         NO_MAP_LOCK_REQUIRED;
1240
1241         log_deprecated(L,
1242                 "Deprecated call to set_look_yaw, use set_look_horizontal instead.");
1243
1244         ObjectRef *ref = checkobject(L, 1);
1245         PlayerSAO* co = getplayersao(ref);
1246         if (co == NULL) return 0;
1247         float yaw = readParam<float>(L, 2) * core::RADTODEG;
1248         // Do it
1249         co->setPlayerYawAndSend(yaw);
1250         return 1;
1251 }
1252
1253 // set_fov(self, degrees[, is_multiplier, transition_time])
1254 int ObjectRef::l_set_fov(lua_State *L)
1255 {
1256         NO_MAP_LOCK_REQUIRED;
1257         ObjectRef *ref = checkobject(L, 1);
1258         RemotePlayer *player = getplayer(ref);
1259         if (!player)
1260                 return 0;
1261
1262         player->setFov({
1263                 static_cast<f32>(luaL_checknumber(L, 2)),
1264                 readParam<bool>(L, 3, false),
1265                 lua_isnumber(L, 4) ? static_cast<f32>(luaL_checknumber(L, 4)) : 0.0f
1266         });
1267         getServer(L)->SendPlayerFov(player->getPeerId());
1268
1269         return 0;
1270 }
1271
1272 // get_fov(self)
1273 int ObjectRef::l_get_fov(lua_State *L)
1274 {
1275         NO_MAP_LOCK_REQUIRED;
1276         ObjectRef *ref = checkobject(L, 1);
1277         RemotePlayer *player = getplayer(ref);
1278         if (!player)
1279                 return 0;
1280
1281         PlayerFovSpec fov_spec = player->getFov();
1282         lua_pushnumber(L, fov_spec.fov);
1283         lua_pushboolean(L, fov_spec.is_multiplier);
1284         lua_pushnumber(L, fov_spec.transition_time);
1285
1286         return 3;
1287 }
1288
1289 // set_breath(self, breath)
1290 int ObjectRef::l_set_breath(lua_State *L)
1291 {
1292         NO_MAP_LOCK_REQUIRED;
1293         ObjectRef *ref = checkobject(L, 1);
1294         PlayerSAO* co = getplayersao(ref);
1295         if (co == NULL) return 0;
1296         u16 breath = luaL_checknumber(L, 2);
1297         co->setBreath(breath);
1298
1299         return 0;
1300 }
1301
1302 // get_breath(self)
1303 int ObjectRef::l_get_breath(lua_State *L)
1304 {
1305         NO_MAP_LOCK_REQUIRED;
1306         ObjectRef *ref = checkobject(L, 1);
1307         PlayerSAO* co = getplayersao(ref);
1308         if (co == NULL) return 0;
1309         // Do it
1310         u16 breath = co->getBreath();
1311         lua_pushinteger (L, breath);
1312         return 1;
1313 }
1314
1315 // set_attribute(self, attribute, value)
1316 int ObjectRef::l_set_attribute(lua_State *L)
1317 {
1318         log_deprecated(L,
1319                 "Deprecated call to set_attribute, use MetaDataRef methods instead.");
1320
1321         ObjectRef *ref = checkobject(L, 1);
1322         PlayerSAO* co = getplayersao(ref);
1323         if (co == NULL)
1324                 return 0;
1325
1326         std::string attr = luaL_checkstring(L, 2);
1327         if (lua_isnil(L, 3)) {
1328                 co->getMeta().removeString(attr);
1329         } else {
1330                 std::string value = luaL_checkstring(L, 3);
1331                 co->getMeta().setString(attr, value);
1332         }
1333         return 1;
1334 }
1335
1336 // get_attribute(self, attribute)
1337 int ObjectRef::l_get_attribute(lua_State *L)
1338 {
1339         log_deprecated(L,
1340                 "Deprecated call to get_attribute, use MetaDataRef methods instead.");
1341
1342         ObjectRef *ref = checkobject(L, 1);
1343         PlayerSAO* co = getplayersao(ref);
1344         if (co == NULL)
1345                 return 0;
1346
1347         std::string attr = luaL_checkstring(L, 2);
1348
1349         std::string value;
1350         if (co->getMeta().getStringToRef(attr, value)) {
1351                 lua_pushstring(L, value.c_str());
1352                 return 1;
1353         }
1354
1355         return 0;
1356 }
1357
1358
1359 // get_meta(self, attribute)
1360 int ObjectRef::l_get_meta(lua_State *L)
1361 {
1362         ObjectRef *ref = checkobject(L, 1);
1363         PlayerSAO *co = getplayersao(ref);
1364         if (co == NULL)
1365                 return 0;
1366
1367         PlayerMetaRef::create(L, &co->getMeta());
1368         return 1;
1369 }
1370
1371
1372 // set_inventory_formspec(self, formspec)
1373 int ObjectRef::l_set_inventory_formspec(lua_State *L)
1374 {
1375         NO_MAP_LOCK_REQUIRED;
1376         ObjectRef *ref = checkobject(L, 1);
1377         RemotePlayer *player = getplayer(ref);
1378         if (player == NULL) return 0;
1379         std::string formspec = luaL_checkstring(L, 2);
1380
1381         player->inventory_formspec = formspec;
1382         getServer(L)->reportInventoryFormspecModified(player->getName());
1383         lua_pushboolean(L, true);
1384         return 1;
1385 }
1386
1387 // get_inventory_formspec(self) -> formspec
1388 int ObjectRef::l_get_inventory_formspec(lua_State *L)
1389 {
1390         NO_MAP_LOCK_REQUIRED;
1391         ObjectRef *ref = checkobject(L, 1);
1392         RemotePlayer *player = getplayer(ref);
1393         if (player == NULL) return 0;
1394
1395         std::string formspec = player->inventory_formspec;
1396         lua_pushlstring(L, formspec.c_str(), formspec.size());
1397         return 1;
1398 }
1399
1400 // set_formspec_prepend(self, formspec)
1401 int ObjectRef::l_set_formspec_prepend(lua_State *L)
1402 {
1403         NO_MAP_LOCK_REQUIRED;
1404         ObjectRef *ref = checkobject(L, 1);
1405         RemotePlayer *player = getplayer(ref);
1406         if (player == NULL)
1407                 return 0;
1408
1409         std::string formspec = luaL_checkstring(L, 2);
1410
1411         player->formspec_prepend = formspec;
1412         getServer(L)->reportFormspecPrependModified(player->getName());
1413         lua_pushboolean(L, true);
1414         return 1;
1415 }
1416
1417 // get_formspec_prepend(self) -> formspec
1418 int ObjectRef::l_get_formspec_prepend(lua_State *L)
1419 {
1420         NO_MAP_LOCK_REQUIRED;
1421         ObjectRef *ref = checkobject(L, 1);
1422         RemotePlayer *player = getplayer(ref);
1423         if (player == NULL)
1424                  return 0;
1425
1426         std::string formspec = player->formspec_prepend;
1427         lua_pushlstring(L, formspec.c_str(), formspec.size());
1428         return 1;
1429 }
1430
1431 // get_player_control(self)
1432 int ObjectRef::l_get_player_control(lua_State *L)
1433 {
1434         NO_MAP_LOCK_REQUIRED;
1435         ObjectRef *ref = checkobject(L, 1);
1436         RemotePlayer *player = getplayer(ref);
1437         if (player == NULL) {
1438                 lua_pushlstring(L, "", 0);
1439                 return 1;
1440         }
1441
1442         const PlayerControl &control = player->getPlayerControl();
1443         lua_newtable(L);
1444         lua_pushboolean(L, control.up);
1445         lua_setfield(L, -2, "up");
1446         lua_pushboolean(L, control.down);
1447         lua_setfield(L, -2, "down");
1448         lua_pushboolean(L, control.left);
1449         lua_setfield(L, -2, "left");
1450         lua_pushboolean(L, control.right);
1451         lua_setfield(L, -2, "right");
1452         lua_pushboolean(L, control.jump);
1453         lua_setfield(L, -2, "jump");
1454         lua_pushboolean(L, control.aux1);
1455         lua_setfield(L, -2, "aux1");
1456         lua_pushboolean(L, control.sneak);
1457         lua_setfield(L, -2, "sneak");
1458         lua_pushboolean(L, control.LMB);
1459         lua_setfield(L, -2, "LMB");
1460         lua_pushboolean(L, control.RMB);
1461         lua_setfield(L, -2, "RMB");
1462         lua_pushboolean(L, control.zoom);
1463         lua_setfield(L, -2, "zoom");
1464         return 1;
1465 }
1466
1467 // get_player_control_bits(self)
1468 int ObjectRef::l_get_player_control_bits(lua_State *L)
1469 {
1470         NO_MAP_LOCK_REQUIRED;
1471         ObjectRef *ref = checkobject(L, 1);
1472         RemotePlayer *player = getplayer(ref);
1473         if (player == NULL) {
1474                 lua_pushlstring(L, "", 0);
1475                 return 1;
1476         }
1477         // Do it
1478         lua_pushnumber(L, player->keyPressed);
1479         return 1;
1480 }
1481
1482 // hud_add(self, form)
1483 int ObjectRef::l_hud_add(lua_State *L)
1484 {
1485         NO_MAP_LOCK_REQUIRED;
1486         ObjectRef *ref = checkobject(L, 1);
1487         RemotePlayer *player = getplayer(ref);
1488         if (player == NULL)
1489                 return 0;
1490
1491         HudElement *elem = new HudElement;
1492         read_hud_element(L, elem);
1493
1494         u32 id = getServer(L)->hudAdd(player, elem);
1495         if (id == U32_MAX) {
1496                 delete elem;
1497                 return 0;
1498         }
1499
1500         lua_pushnumber(L, id);
1501         return 1;
1502 }
1503
1504 // hud_remove(self, id)
1505 int ObjectRef::l_hud_remove(lua_State *L)
1506 {
1507         NO_MAP_LOCK_REQUIRED;
1508         ObjectRef *ref = checkobject(L, 1);
1509         RemotePlayer *player = getplayer(ref);
1510         if (player == NULL)
1511                 return 0;
1512
1513         u32 id = -1;
1514         if (!lua_isnil(L, 2))
1515                 id = lua_tonumber(L, 2);
1516
1517         if (!getServer(L)->hudRemove(player, id))
1518                 return 0;
1519
1520         lua_pushboolean(L, true);
1521         return 1;
1522 }
1523
1524 // hud_change(self, id, stat, data)
1525 int ObjectRef::l_hud_change(lua_State *L)
1526 {
1527         NO_MAP_LOCK_REQUIRED;
1528         ObjectRef *ref = checkobject(L, 1);
1529         RemotePlayer *player = getplayer(ref);
1530         if (player == NULL)
1531                 return 0;
1532
1533         u32 id = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : -1;
1534
1535         HudElement *e = player->getHud(id);
1536         if (!e)
1537                 return 0;
1538
1539         void *value = NULL;
1540         HudElementStat stat = read_hud_change(L, e, &value);
1541
1542         getServer(L)->hudChange(player, id, stat, value);
1543
1544         lua_pushboolean(L, true);
1545         return 1;
1546 }
1547
1548 // hud_get(self, id)
1549 int ObjectRef::l_hud_get(lua_State *L)
1550 {
1551         NO_MAP_LOCK_REQUIRED;
1552         ObjectRef *ref = checkobject(L, 1);
1553         RemotePlayer *player = getplayer(ref);
1554         if (player == NULL)
1555                 return 0;
1556
1557         u32 id = lua_tonumber(L, -1);
1558
1559         HudElement *e = player->getHud(id);
1560         if (!e)
1561                 return 0;
1562         push_hud_element(L, e);
1563         return 1;
1564 }
1565
1566 // hud_set_flags(self, flags)
1567 int ObjectRef::l_hud_set_flags(lua_State *L)
1568 {
1569         NO_MAP_LOCK_REQUIRED;
1570         ObjectRef *ref = checkobject(L, 1);
1571         RemotePlayer *player = getplayer(ref);
1572         if (player == NULL)
1573                 return 0;
1574
1575         u32 flags = 0;
1576         u32 mask  = 0;
1577         bool flag;
1578
1579         const EnumString *esp = es_HudBuiltinElement;
1580         for (int i = 0; esp[i].str; i++) {
1581                 if (getboolfield(L, 2, esp[i].str, flag)) {
1582                         flags |= esp[i].num * flag;
1583                         mask  |= esp[i].num;
1584                 }
1585         }
1586         if (!getServer(L)->hudSetFlags(player, flags, mask))
1587                 return 0;
1588
1589         lua_pushboolean(L, true);
1590         return 1;
1591 }
1592
1593 int ObjectRef::l_hud_get_flags(lua_State *L)
1594 {
1595         NO_MAP_LOCK_REQUIRED;
1596         ObjectRef *ref = checkobject(L, 1);
1597         RemotePlayer *player = getplayer(ref);
1598         if (player == NULL)
1599                 return 0;
1600
1601         lua_newtable(L);
1602         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
1603         lua_setfield(L, -2, "hotbar");
1604         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
1605         lua_setfield(L, -2, "healthbar");
1606         lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
1607         lua_setfield(L, -2, "crosshair");
1608         lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
1609         lua_setfield(L, -2, "wielditem");
1610         lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
1611         lua_setfield(L, -2, "breathbar");
1612         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1613         lua_setfield(L, -2, "minimap");
1614         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1615         lua_setfield(L, -2, "minimap_radar");
1616
1617         return 1;
1618 }
1619
1620 // hud_set_hotbar_itemcount(self, hotbar_itemcount)
1621 int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
1622 {
1623         NO_MAP_LOCK_REQUIRED;
1624         ObjectRef *ref = checkobject(L, 1);
1625         RemotePlayer *player = getplayer(ref);
1626         if (player == NULL)
1627                 return 0;
1628
1629         s32 hotbar_itemcount = lua_tonumber(L, 2);
1630
1631         if (!getServer(L)->hudSetHotbarItemcount(player, hotbar_itemcount))
1632                 return 0;
1633
1634         lua_pushboolean(L, true);
1635         return 1;
1636 }
1637
1638 // hud_get_hotbar_itemcount(self)
1639 int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
1640 {
1641         NO_MAP_LOCK_REQUIRED;
1642         ObjectRef *ref = checkobject(L, 1);
1643         RemotePlayer *player = getplayer(ref);
1644         if (player == NULL)
1645                 return 0;
1646
1647         lua_pushnumber(L, player->getHotbarItemcount());
1648         return 1;
1649 }
1650
1651 // hud_set_hotbar_image(self, name)
1652 int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
1653 {
1654         NO_MAP_LOCK_REQUIRED;
1655         ObjectRef *ref = checkobject(L, 1);
1656         RemotePlayer *player = getplayer(ref);
1657         if (player == NULL)
1658                 return 0;
1659
1660         std::string name = readParam<std::string>(L, 2);
1661
1662         getServer(L)->hudSetHotbarImage(player, name);
1663         return 1;
1664 }
1665
1666 // hud_get_hotbar_image(self)
1667 int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
1668 {
1669         NO_MAP_LOCK_REQUIRED;
1670         ObjectRef *ref = checkobject(L, 1);
1671         RemotePlayer *player = getplayer(ref);
1672         if (player == NULL)
1673                 return 0;
1674
1675         const std::string &name = player->getHotbarImage();
1676         lua_pushlstring(L, name.c_str(), name.size());
1677         return 1;
1678 }
1679
1680 // hud_set_hotbar_selected_image(self, name)
1681 int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
1682 {
1683         NO_MAP_LOCK_REQUIRED;
1684         ObjectRef *ref = checkobject(L, 1);
1685         RemotePlayer *player = getplayer(ref);
1686         if (player == NULL)
1687                 return 0;
1688
1689         std::string name = readParam<std::string>(L, 2);
1690
1691         getServer(L)->hudSetHotbarSelectedImage(player, name);
1692         return 1;
1693 }
1694
1695 // hud_get_hotbar_selected_image(self)
1696 int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
1697 {
1698         NO_MAP_LOCK_REQUIRED;
1699         ObjectRef *ref = checkobject(L, 1);
1700         RemotePlayer *player = getplayer(ref);
1701         if (player == NULL)
1702                 return 0;
1703
1704         const std::string &name = player->getHotbarSelectedImage();
1705         lua_pushlstring(L, name.c_str(), name.size());
1706         return 1;
1707 }
1708
1709 // set_sky(self, {base_color=, type=, textures=, clouds=, sky_colors={}})
1710 int ObjectRef::l_set_sky(lua_State *L)
1711 {
1712         NO_MAP_LOCK_REQUIRED;
1713         ObjectRef *ref = checkobject(L, 1);
1714         RemotePlayer *player = getplayer(ref);
1715         if (!player)
1716                 return 0;
1717
1718         bool is_colorspec = is_color_table(L, 2);
1719
1720         SkyboxParams skybox_params = player->getSkyParams();
1721         if (lua_istable(L, 2) && !is_colorspec) {
1722                 lua_getfield(L, 2, "base_color");
1723                 if (!lua_isnil(L, -1))
1724                         read_color(L, -1, &skybox_params.bgcolor);
1725                 lua_pop(L, 1);
1726
1727                 lua_getfield(L, 2, "type");
1728                 if (!lua_isnil(L, -1))
1729                         skybox_params.type = luaL_checkstring(L, -1);
1730                 lua_pop(L, 1);
1731
1732                 lua_getfield(L, 2, "textures");
1733                 skybox_params.textures.clear();
1734                 if (lua_istable(L, -1) && skybox_params.type == "skybox") {
1735                         lua_pushnil(L);
1736                         while (lua_next(L, -2) != 0) {
1737                                 // Key is at index -2 and value at index -1
1738                                 skybox_params.textures.emplace_back(readParam<std::string>(L, -1));
1739                                 // Removes the value, but keeps the key for iteration
1740                                 lua_pop(L, 1);
1741                         }
1742                 }
1743                 lua_pop(L, 1);
1744
1745                 /*
1746                 We want to avoid crashes, so we're checking even if we're not using them.
1747                 However, we want to ensure that the skybox can be set to nil when
1748                 using "regular" or "plain" skybox modes as textures aren't needed.
1749                 */
1750
1751                 if (skybox_params.textures.size() != 6 && skybox_params.textures.size() > 0)
1752                         throw LuaError("Skybox expects 6 textures!");
1753
1754                 skybox_params.clouds = getboolfield_default(L, 2,
1755                         "clouds", skybox_params.clouds);
1756
1757                 lua_getfield(L, 2, "sky_color");
1758                 if (lua_istable(L, -1)) {
1759                         lua_getfield(L, -1, "day_sky");
1760                         read_color(L, -1, &skybox_params.sky_color.day_sky);
1761                         lua_pop(L, 1);
1762
1763                         lua_getfield(L, -1, "day_horizon");
1764                         read_color(L, -1, &skybox_params.sky_color.day_horizon);
1765                         lua_pop(L, 1);
1766
1767                         lua_getfield(L, -1, "dawn_sky");
1768                         read_color(L, -1, &skybox_params.sky_color.dawn_sky);
1769                         lua_pop(L, 1);
1770
1771                         lua_getfield(L, -1, "dawn_horizon");
1772                         read_color(L, -1, &skybox_params.sky_color.dawn_horizon);
1773                         lua_pop(L, 1);
1774
1775                         lua_getfield(L, -1, "night_sky");
1776                         read_color(L, -1, &skybox_params.sky_color.night_sky);
1777                         lua_pop(L, 1);
1778
1779                         lua_getfield(L, -1, "night_horizon");
1780                         read_color(L, -1, &skybox_params.sky_color.night_horizon);
1781                         lua_pop(L, 1);
1782
1783                         lua_getfield(L, -1, "indoors");
1784                         read_color(L, -1, &skybox_params.sky_color.indoors);
1785                         lua_pop(L, 1);
1786
1787                         // Prevent flickering clouds at dawn/dusk:
1788                         skybox_params.fog_sun_tint = video::SColor(255, 255, 255, 255);
1789                         lua_getfield(L, -1, "fog_sun_tint");
1790                         read_color(L, -1, &skybox_params.fog_sun_tint);
1791                         lua_pop(L, 1);
1792
1793                         skybox_params.fog_moon_tint = video::SColor(255, 255, 255, 255);
1794                         lua_getfield(L, -1, "fog_moon_tint");
1795                         read_color(L, -1, &skybox_params.fog_moon_tint);
1796                         lua_pop(L, 1);
1797
1798                         lua_getfield(L, -1, "fog_tint_type");
1799                         if (!lua_isnil(L, -1))
1800                                 skybox_params.fog_tint_type = luaL_checkstring(L, -1);
1801                         lua_pop(L, 1);
1802
1803                         // Because we need to leave the "sky_color" table.
1804                         lua_pop(L, 1);
1805                 }
1806         } else {
1807                 // Handle old set_sky calls, and log deprecated:
1808                 log_deprecated(L, "Deprecated call to set_sky, please check lua_api.txt");
1809
1810                 // Fix sun, moon and stars showing when classic textured skyboxes are used
1811                 SunParams sun_params = player->getSunParams();
1812                 MoonParams moon_params = player->getMoonParams();
1813                 StarParams star_params = player->getStarParams();
1814
1815                 // Prevent erroneous background colors
1816                 skybox_params.bgcolor = video::SColor(255, 255, 255, 255);
1817                 read_color(L, 2, &skybox_params.bgcolor);
1818
1819                 skybox_params.type = luaL_checkstring(L, 3);
1820
1821                 // Preserve old behaviour of the sun, moon and stars
1822                 // when using the old set_sky call.
1823                 if (skybox_params.type == "regular") {
1824                         sun_params.visible = true;
1825                         sun_params.sunrise_visible = true;
1826                         moon_params.visible = true;
1827                         star_params.visible = true;
1828                 } else {
1829                         sun_params.visible = false;
1830                         sun_params.sunrise_visible = false;
1831                         moon_params.visible = false;
1832                         star_params.visible = false;
1833                 }
1834
1835                 skybox_params.textures.clear();
1836                 if (lua_istable(L, 4)) {
1837                         lua_pushnil(L);
1838                         while (lua_next(L, 4) != 0) {
1839                         // Key at index -2, and value at index -1
1840                                 if (lua_isstring(L, -1))
1841                                         skybox_params.textures.emplace_back(readParam<std::string>(L, -1));
1842                                 else
1843                                         skybox_params.textures.emplace_back("");
1844                                 // Remove the value, keep the key for the next iteration
1845                                 lua_pop(L, 1);
1846                         }
1847                 }
1848                 if (skybox_params.type == "skybox" && skybox_params.textures.size() != 6)
1849                         throw LuaError("Skybox expects 6 textures.");
1850
1851                 skybox_params.clouds = true;
1852                 if (lua_isboolean(L, 5))
1853                         skybox_params.clouds = readParam<bool>(L, 5);
1854
1855                 getServer(L)->setSun(player, sun_params);
1856                 getServer(L)->setMoon(player, moon_params);
1857                 getServer(L)->setStars(player, star_params);
1858         }
1859         getServer(L)->setSky(player, skybox_params);
1860         lua_pushboolean(L, true);
1861         return 1;
1862 }
1863
1864 // get_sky(self)
1865 int ObjectRef::l_get_sky(lua_State *L)
1866 {
1867         NO_MAP_LOCK_REQUIRED;
1868         ObjectRef *ref = checkobject(L, 1);
1869         RemotePlayer *player = getplayer(ref);
1870
1871         if (!player)
1872                 return 0;
1873         SkyboxParams skybox_params;
1874         skybox_params = player->getSkyParams();
1875
1876         push_ARGB8(L, skybox_params.bgcolor);
1877         lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
1878
1879         lua_newtable(L);
1880         s16 i = 1;
1881         for (const std::string& texture : skybox_params.textures) {
1882                 lua_pushlstring(L, texture.c_str(), texture.size());
1883                 lua_rawseti(L, -2, i++);
1884         }
1885         lua_pushboolean(L, skybox_params.clouds);
1886         return 4;
1887 }
1888
1889 // get_sky_color(self)
1890 int ObjectRef::l_get_sky_color(lua_State *L)
1891 {
1892         NO_MAP_LOCK_REQUIRED;
1893         ObjectRef *ref = checkobject(L, 1);
1894         RemotePlayer *player = getplayer(ref);
1895
1896         if (!player)
1897                 return 0;
1898
1899         const SkyboxParams& skybox_params = player->getSkyParams();
1900
1901         lua_newtable(L);
1902         if (skybox_params.type == "regular") {
1903                 push_ARGB8(L, skybox_params.sky_color.day_sky);
1904                 lua_setfield(L, -2, "day_sky");
1905                 push_ARGB8(L, skybox_params.sky_color.day_horizon);
1906                 lua_setfield(L, -2, "day_horizon");
1907                 push_ARGB8(L, skybox_params.sky_color.dawn_sky);
1908                 lua_setfield(L, -2, "dawn_sky");
1909                 push_ARGB8(L, skybox_params.sky_color.dawn_horizon);
1910                 lua_setfield(L, -2, "dawn_horizon");
1911                 push_ARGB8(L, skybox_params.sky_color.night_sky);
1912                 lua_setfield(L, -2, "night_sky");
1913                 push_ARGB8(L, skybox_params.sky_color.night_horizon);
1914                 lua_setfield(L, -2, "night_horizon");
1915                 push_ARGB8(L, skybox_params.sky_color.indoors);
1916                 lua_setfield(L, -2, "indoors");
1917         }
1918         push_ARGB8(L, skybox_params.fog_sun_tint);
1919         lua_setfield(L, -2, "fog_sun_tint");
1920         push_ARGB8(L, skybox_params.fog_moon_tint);
1921         lua_setfield(L, -2, "fog_moon_tint");
1922         lua_pushstring(L, skybox_params.fog_tint_type.c_str());
1923         lua_setfield(L, -2, "fog_tint_type");
1924         return 1;
1925 }
1926
1927 // set_sun(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=})
1928 int ObjectRef::l_set_sun(lua_State *L)
1929 {
1930         NO_MAP_LOCK_REQUIRED;
1931         ObjectRef *ref = checkobject(L, 1);
1932         RemotePlayer *player = getplayer(ref);
1933         if (!player)
1934                 return 0;
1935
1936         if (!lua_istable(L, 2))
1937                 return 0;
1938
1939         SunParams sun_params = player->getSunParams();
1940
1941         sun_params.visible = getboolfield_default(L, 2,
1942                         "visible", sun_params.visible);
1943         sun_params.texture = getstringfield_default(L, 2,
1944                         "texture", sun_params.texture);
1945         sun_params.tonemap = getstringfield_default(L, 2,
1946                         "tonemap", sun_params.tonemap);
1947         sun_params.sunrise = getstringfield_default(L, 2,
1948                         "sunrise", sun_params.sunrise);
1949         sun_params.sunrise_visible = getboolfield_default(L, 2,
1950                         "sunrise_visible", sun_params.sunrise_visible);
1951         sun_params.scale = getfloatfield_default(L, 2,
1952                         "scale", sun_params.scale);
1953
1954         getServer(L)->setSun(player, sun_params);
1955         lua_pushboolean(L, true);
1956         return 1;
1957 }
1958
1959 //get_sun(self)
1960 int ObjectRef::l_get_sun(lua_State *L)
1961 {
1962         NO_MAP_LOCK_REQUIRED;
1963         ObjectRef *ref = checkobject(L, 1);
1964         RemotePlayer *player = getplayer(ref);
1965         if (!player)
1966                 return 0;
1967         const SunParams &sun_params = player->getSunParams();
1968
1969         lua_newtable(L);
1970         lua_pushboolean(L, sun_params.visible);
1971         lua_setfield(L, -2, "visible");
1972         lua_pushstring(L, sun_params.texture.c_str());
1973         lua_setfield(L, -2, "texture");
1974         lua_pushstring(L, sun_params.tonemap.c_str());
1975         lua_setfield(L, -2, "tonemap");
1976         lua_pushstring(L, sun_params.sunrise.c_str());
1977         lua_setfield(L, -2, "sunrise");
1978         lua_pushboolean(L, sun_params.sunrise_visible);
1979         lua_setfield(L, -2, "sunrise_visible");
1980         lua_pushnumber(L, sun_params.scale);
1981         lua_setfield(L, -2, "scale");
1982
1983         return 1;
1984 }
1985
1986 // set_moon(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=})
1987 int ObjectRef::l_set_moon(lua_State *L)
1988 {
1989         NO_MAP_LOCK_REQUIRED;
1990         ObjectRef *ref = checkobject(L, 1);
1991         RemotePlayer *player = getplayer(ref);
1992         if (!player)
1993                 return 0;
1994         if (!lua_istable(L, 2))
1995                 return 0;
1996
1997         MoonParams moon_params = player->getMoonParams();
1998
1999         moon_params.visible = getboolfield_default(L, 2,
2000                 "visible", moon_params.visible);
2001         moon_params.texture = getstringfield_default(L, 2,
2002                 "texture", moon_params.texture);
2003         moon_params.tonemap = getstringfield_default(L, 2,
2004                 "tonemap", moon_params.tonemap);
2005         moon_params.scale = getfloatfield_default(L, 2,
2006                 "scale", moon_params.scale);
2007
2008         getServer(L)->setMoon(player, moon_params);
2009         lua_pushboolean(L, true);
2010         return 1;
2011 }
2012
2013 // get_moon(self)
2014 int ObjectRef::l_get_moon(lua_State *L)
2015 {
2016         NO_MAP_LOCK_REQUIRED;
2017         ObjectRef *ref = checkobject(L, 1);
2018         RemotePlayer *player = getplayer(ref);
2019         if (!player)
2020                 return 0;
2021         const MoonParams &moon_params = player->getMoonParams();
2022
2023         lua_newtable(L);
2024         lua_pushboolean(L, moon_params.visible);
2025         lua_setfield(L, -2, "visible");
2026         lua_pushstring(L, moon_params.texture.c_str());
2027         lua_setfield(L, -2, "texture");
2028         lua_pushstring(L, moon_params.tonemap.c_str());
2029         lua_setfield(L, -2, "tonemap");
2030         lua_pushnumber(L, moon_params.scale);
2031         lua_setfield(L, -2, "scale");
2032
2033         return 1;
2034 }
2035
2036 // set_stars(self, {visible, count=, starcolor=, rotation=, scale=})
2037 int ObjectRef::l_set_stars(lua_State *L)
2038 {
2039         NO_MAP_LOCK_REQUIRED;
2040         ObjectRef *ref = checkobject(L, 1);
2041         RemotePlayer *player = getplayer(ref);
2042         if (!player)
2043                 return 0;
2044         if (!lua_istable(L, 2))
2045                 return 0;
2046
2047         StarParams star_params = player->getStarParams();
2048
2049         star_params.visible = getboolfield_default(L, 2,
2050                 "visible", star_params.visible);
2051         star_params.count = getintfield_default(L, 2,
2052                 "count", star_params.count);
2053
2054         lua_getfield(L, 2, "star_color");
2055         if (!lua_isnil(L, -1))
2056                 read_color(L, -1, &star_params.starcolor);
2057         lua_pop(L, 1);
2058
2059         star_params.scale = getfloatfield_default(L, 2,
2060                 "scale", star_params.scale);
2061
2062         getServer(L)->setStars(player, star_params);
2063         lua_pushboolean(L, true);
2064         return 1;
2065 }
2066
2067 // get_stars(self)
2068 int ObjectRef::l_get_stars(lua_State *L)
2069 {
2070         NO_MAP_LOCK_REQUIRED;
2071         ObjectRef *ref = checkobject(L, 1);
2072         RemotePlayer *player = getplayer(ref);
2073         if (!player)
2074                 return 0;
2075         const StarParams &star_params = player->getStarParams();
2076
2077         lua_newtable(L);
2078         lua_pushboolean(L, star_params.visible);
2079         lua_setfield(L, -2, "visible");
2080         lua_pushnumber(L, star_params.count);
2081         lua_setfield(L, -2, "count");
2082         push_ARGB8(L, star_params.starcolor);
2083         lua_setfield(L, -2, "star_color");
2084         lua_pushnumber(L, star_params.scale);
2085         lua_setfield(L, -2, "scale");
2086
2087         return 1;
2088 }
2089
2090 // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
2091 int ObjectRef::l_set_clouds(lua_State *L)
2092 {
2093         NO_MAP_LOCK_REQUIRED;
2094         ObjectRef *ref = checkobject(L, 1);
2095         RemotePlayer *player = getplayer(ref);
2096         if (!player)
2097                 return 0;
2098         if (!lua_istable(L, 2))
2099                 return 0;
2100
2101         CloudParams cloud_params = player->getCloudParams();
2102
2103         cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
2104
2105         lua_getfield(L, 2, "color");
2106         if (!lua_isnil(L, -1))
2107                 read_color(L, -1, &cloud_params.color_bright);
2108         lua_pop(L, 1);
2109         lua_getfield(L, 2, "ambient");
2110         if (!lua_isnil(L, -1))
2111                 read_color(L, -1, &cloud_params.color_ambient);
2112         lua_pop(L, 1);
2113
2114         cloud_params.height    = getfloatfield_default(L, 2, "height",    cloud_params.height   );
2115         cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
2116
2117         lua_getfield(L, 2, "speed");
2118         if (lua_istable(L, -1)) {
2119                 v2f new_speed;
2120                 new_speed.X = getfloatfield_default(L, -1, "x", 0);
2121                 new_speed.Y = getfloatfield_default(L, -1, "z", 0);
2122                 cloud_params.speed = new_speed;
2123         }
2124         lua_pop(L, 1);
2125
2126         getServer(L)->setClouds(player, cloud_params);
2127         lua_pushboolean(L, true);
2128         return 1;
2129 }
2130
2131 int ObjectRef::l_get_clouds(lua_State *L)
2132 {
2133         NO_MAP_LOCK_REQUIRED;
2134         ObjectRef *ref = checkobject(L, 1);
2135         RemotePlayer *player = getplayer(ref);
2136         if (!player)
2137                 return 0;
2138         const CloudParams &cloud_params = player->getCloudParams();
2139
2140         lua_newtable(L);
2141         lua_pushnumber(L, cloud_params.density);
2142         lua_setfield(L, -2, "density");
2143         push_ARGB8(L, cloud_params.color_bright);
2144         lua_setfield(L, -2, "color");
2145         push_ARGB8(L, cloud_params.color_ambient);
2146         lua_setfield(L, -2, "ambient");
2147         lua_pushnumber(L, cloud_params.height);
2148         lua_setfield(L, -2, "height");
2149         lua_pushnumber(L, cloud_params.thickness);
2150         lua_setfield(L, -2, "thickness");
2151         lua_newtable(L);
2152         lua_pushnumber(L, cloud_params.speed.X);
2153         lua_setfield(L, -2, "x");
2154         lua_pushnumber(L, cloud_params.speed.Y);
2155         lua_setfield(L, -2, "y");
2156         lua_setfield(L, -2, "speed");
2157
2158         return 1;
2159 }
2160
2161
2162 // override_day_night_ratio(self, brightness=0...1)
2163 int ObjectRef::l_override_day_night_ratio(lua_State *L)
2164 {
2165         NO_MAP_LOCK_REQUIRED;
2166         ObjectRef *ref = checkobject(L, 1);
2167         RemotePlayer *player = getplayer(ref);
2168         if (player == NULL)
2169                 return 0;
2170
2171         bool do_override = false;
2172         float ratio = 0.0f;
2173         if (!lua_isnil(L, 2)) {
2174                 do_override = true;
2175                 ratio = readParam<float>(L, 2);
2176         }
2177
2178         getServer(L)->overrideDayNightRatio(player, do_override, ratio);
2179         lua_pushboolean(L, true);
2180         return 1;
2181 }
2182
2183 // get_day_night_ratio(self)
2184 int ObjectRef::l_get_day_night_ratio(lua_State *L)
2185 {
2186         NO_MAP_LOCK_REQUIRED;
2187         ObjectRef *ref = checkobject(L, 1);
2188         RemotePlayer *player = getplayer(ref);
2189         if (player == NULL)
2190                 return 0;
2191
2192         bool do_override;
2193         float ratio;
2194         player->getDayNightRatio(&do_override, &ratio);
2195
2196         if (do_override)
2197                 lua_pushnumber(L, ratio);
2198         else
2199                 lua_pushnil(L);
2200
2201         return 1;
2202 }
2203
2204 ObjectRef::ObjectRef(ServerActiveObject *object):
2205         m_object(object)
2206 {
2207         //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
2208 }
2209
2210 // Creates an ObjectRef and leaves it on top of stack
2211 // Not callable from Lua; all references are created on the C side.
2212 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
2213 {
2214         ObjectRef *o = new ObjectRef(object);
2215         //infostream<<"ObjectRef::create: o="<<o<<std::endl;
2216         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
2217         luaL_getmetatable(L, className);
2218         lua_setmetatable(L, -2);
2219 }
2220
2221 void ObjectRef::set_null(lua_State *L)
2222 {
2223         ObjectRef *o = checkobject(L, -1);
2224         o->m_object = NULL;
2225 }
2226
2227 void ObjectRef::Register(lua_State *L)
2228 {
2229         lua_newtable(L);
2230         int methodtable = lua_gettop(L);
2231         luaL_newmetatable(L, className);
2232         int metatable = lua_gettop(L);
2233
2234         lua_pushliteral(L, "__metatable");
2235         lua_pushvalue(L, methodtable);
2236         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
2237
2238         lua_pushliteral(L, "__index");
2239         lua_pushvalue(L, methodtable);
2240         lua_settable(L, metatable);
2241
2242         lua_pushliteral(L, "__gc");
2243         lua_pushcfunction(L, gc_object);
2244         lua_settable(L, metatable);
2245
2246         lua_pop(L, 1);  // drop metatable
2247
2248         markAliasDeprecated(methods);
2249         luaL_openlib(L, 0, methods, 0);  // fill methodtable
2250         lua_pop(L, 1);  // drop methodtable
2251
2252         // Cannot be created from Lua
2253         //lua_register(L, className, create_object);
2254 }
2255
2256 const char ObjectRef::className[] = "ObjectRef";
2257 luaL_Reg ObjectRef::methods[] = {
2258         // ServerActiveObject
2259         luamethod(ObjectRef, remove),
2260         luamethod_aliased(ObjectRef, get_pos, getpos),
2261         luamethod_aliased(ObjectRef, set_pos, setpos),
2262         luamethod_aliased(ObjectRef, move_to, moveto),
2263         luamethod(ObjectRef, punch),
2264         luamethod(ObjectRef, right_click),
2265         luamethod(ObjectRef, set_hp),
2266         luamethod(ObjectRef, get_hp),
2267         luamethod(ObjectRef, get_inventory),
2268         luamethod(ObjectRef, get_wield_list),
2269         luamethod(ObjectRef, get_wield_index),
2270         luamethod(ObjectRef, get_wielded_item),
2271         luamethod(ObjectRef, set_wielded_item),
2272         luamethod(ObjectRef, set_armor_groups),
2273         luamethod(ObjectRef, get_armor_groups),
2274         luamethod(ObjectRef, set_animation),
2275         luamethod(ObjectRef, get_animation),
2276         luamethod(ObjectRef, set_animation_frame_speed),
2277         luamethod(ObjectRef, set_bone_position),
2278         luamethod(ObjectRef, get_bone_position),
2279         luamethod(ObjectRef, set_attach),
2280         luamethod(ObjectRef, get_attach),
2281         luamethod(ObjectRef, set_detach),
2282         luamethod(ObjectRef, set_properties),
2283         luamethod(ObjectRef, get_properties),
2284         luamethod(ObjectRef, set_nametag_attributes),
2285         luamethod(ObjectRef, get_nametag_attributes),
2286         // LuaEntitySAO-only
2287         luamethod_aliased(ObjectRef, set_velocity, setvelocity),
2288         luamethod(ObjectRef, add_velocity),
2289         luamethod_aliased(ObjectRef, get_velocity, getvelocity),
2290         luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
2291         luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
2292         luamethod_aliased(ObjectRef, set_yaw, setyaw),
2293         luamethod_aliased(ObjectRef, get_yaw, getyaw),
2294         luamethod(ObjectRef, set_rotation),
2295         luamethod(ObjectRef, get_rotation),
2296         luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
2297         luamethod_aliased(ObjectRef, set_sprite, setsprite),
2298         luamethod(ObjectRef, get_entity_name),
2299         luamethod(ObjectRef, get_luaentity),
2300         // Player-only
2301         luamethod(ObjectRef, is_player),
2302         luamethod(ObjectRef, is_player_connected),
2303         luamethod(ObjectRef, get_player_name),
2304         luamethod(ObjectRef, get_player_velocity),
2305         luamethod(ObjectRef, add_player_velocity),
2306         luamethod(ObjectRef, get_look_dir),
2307         luamethod(ObjectRef, get_look_pitch),
2308         luamethod(ObjectRef, get_look_yaw),
2309         luamethod(ObjectRef, get_look_vertical),
2310         luamethod(ObjectRef, get_look_horizontal),
2311         luamethod(ObjectRef, set_look_horizontal),
2312         luamethod(ObjectRef, set_look_vertical),
2313         luamethod(ObjectRef, set_look_yaw),
2314         luamethod(ObjectRef, set_look_pitch),
2315         luamethod(ObjectRef, get_fov),
2316         luamethod(ObjectRef, set_fov),
2317         luamethod(ObjectRef, get_breath),
2318         luamethod(ObjectRef, set_breath),
2319         luamethod(ObjectRef, get_attribute),
2320         luamethod(ObjectRef, set_attribute),
2321         luamethod(ObjectRef, get_meta),
2322         luamethod(ObjectRef, set_inventory_formspec),
2323         luamethod(ObjectRef, get_inventory_formspec),
2324         luamethod(ObjectRef, set_formspec_prepend),
2325         luamethod(ObjectRef, get_formspec_prepend),
2326         luamethod(ObjectRef, get_player_control),
2327         luamethod(ObjectRef, get_player_control_bits),
2328         luamethod(ObjectRef, set_physics_override),
2329         luamethod(ObjectRef, get_physics_override),
2330         luamethod(ObjectRef, hud_add),
2331         luamethod(ObjectRef, hud_remove),
2332         luamethod(ObjectRef, hud_change),
2333         luamethod(ObjectRef, hud_get),
2334         luamethod(ObjectRef, hud_set_flags),
2335         luamethod(ObjectRef, hud_get_flags),
2336         luamethod(ObjectRef, hud_set_hotbar_itemcount),
2337         luamethod(ObjectRef, hud_get_hotbar_itemcount),
2338         luamethod(ObjectRef, hud_set_hotbar_image),
2339         luamethod(ObjectRef, hud_get_hotbar_image),
2340         luamethod(ObjectRef, hud_set_hotbar_selected_image),
2341         luamethod(ObjectRef, hud_get_hotbar_selected_image),
2342         luamethod(ObjectRef, set_sky),
2343         luamethod(ObjectRef, get_sky),
2344         luamethod(ObjectRef, get_sky_color),
2345         luamethod(ObjectRef, set_sun),
2346         luamethod(ObjectRef, get_sun),
2347         luamethod(ObjectRef, set_moon),
2348         luamethod(ObjectRef, get_moon),
2349         luamethod(ObjectRef, set_stars),
2350         luamethod(ObjectRef, get_stars),
2351         luamethod(ObjectRef, set_clouds),
2352         luamethod(ObjectRef, get_clouds),
2353         luamethod(ObjectRef, override_day_night_ratio),
2354         luamethod(ObjectRef, get_day_night_ratio),
2355         luamethod(ObjectRef, set_local_animation),
2356         luamethod(ObjectRef, get_local_animation),
2357         luamethod(ObjectRef, set_eye_offset),
2358         luamethod(ObjectRef, get_eye_offset),
2359         luamethod(ObjectRef, send_mapblock),
2360         {0,0}
2361 };