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