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