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