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