]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_object.cpp
b7185f7ec5a98f711cfdd2ea0473e28f50258d17
[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         u16 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         if (player == nullptr) {
1371                 lua_pushlstring(L, "", 0);
1372                 return 1;
1373         }
1374
1375         const PlayerControl &control = player->getPlayerControl();
1376         lua_newtable(L);
1377         lua_pushboolean(L, player->keyPressed & (1 << 0));
1378         lua_setfield(L, -2, "up");
1379         lua_pushboolean(L, player->keyPressed & (1 << 1));
1380         lua_setfield(L, -2, "down");
1381         lua_pushboolean(L, player->keyPressed & (1 << 2));
1382         lua_setfield(L, -2, "left");
1383         lua_pushboolean(L, player->keyPressed & (1 << 3));
1384         lua_setfield(L, -2, "right");
1385         lua_pushboolean(L, control.jump);
1386         lua_setfield(L, -2, "jump");
1387         lua_pushboolean(L, control.aux1);
1388         lua_setfield(L, -2, "aux1");
1389         lua_pushboolean(L, control.sneak);
1390         lua_setfield(L, -2, "sneak");
1391         lua_pushboolean(L, control.dig);
1392         lua_setfield(L, -2, "dig");
1393         lua_pushboolean(L, control.place);
1394         lua_setfield(L, -2, "place");
1395         // Legacy fields to ensure mod compatibility
1396         lua_pushboolean(L, control.dig);
1397         lua_setfield(L, -2, "LMB");
1398         lua_pushboolean(L, control.place);
1399         lua_setfield(L, -2, "RMB");
1400         lua_pushboolean(L, control.zoom);
1401         lua_setfield(L, -2, "zoom");
1402         return 1;
1403 }
1404
1405 // get_player_control_bits(self)
1406 int ObjectRef::l_get_player_control_bits(lua_State *L)
1407 {
1408         NO_MAP_LOCK_REQUIRED;
1409         ObjectRef *ref = checkobject(L, 1);
1410         RemotePlayer *player = getplayer(ref);
1411         if (player == nullptr) {
1412                 lua_pushlstring(L, "", 0);
1413                 return 1;
1414         }
1415
1416         lua_pushnumber(L, player->keyPressed);
1417         return 1;
1418 }
1419
1420 // set_physics_override(self, override_table)
1421 int ObjectRef::l_set_physics_override(lua_State *L)
1422 {
1423         NO_MAP_LOCK_REQUIRED;
1424         ObjectRef *ref = checkobject(L, 1);
1425         PlayerSAO *playersao = getplayersao(ref);
1426         if (playersao == nullptr)
1427                 return 0;
1428
1429         if (lua_istable(L, 2)) {
1430                 bool modified = false;
1431                 modified |= getfloatfield(L, 2, "speed", playersao->m_physics_override_speed);
1432                 modified |= getfloatfield(L, 2, "jump", playersao->m_physics_override_jump);
1433                 modified |= getfloatfield(L, 2, "gravity", playersao->m_physics_override_gravity);
1434                 modified |= getboolfield(L, 2, "sneak", playersao->m_physics_override_sneak);
1435                 modified |= getboolfield(L, 2, "sneak_glitch", playersao->m_physics_override_sneak_glitch);
1436                 modified |= getboolfield(L, 2, "new_move", playersao->m_physics_override_new_move);
1437                 if (modified)
1438                         playersao->m_physics_override_sent = false;
1439         } else {
1440                 // old, non-table format
1441                 // TODO: Remove this code after version 5.4.0
1442                 log_deprecated(L, "Deprecated use of set_physics_override(num, num, num)");
1443
1444                 if (!lua_isnil(L, 2)) {
1445                         playersao->m_physics_override_speed = lua_tonumber(L, 2);
1446                         playersao->m_physics_override_sent = false;
1447                 }
1448                 if (!lua_isnil(L, 3)) {
1449                         playersao->m_physics_override_jump = lua_tonumber(L, 3);
1450                         playersao->m_physics_override_sent = false;
1451                 }
1452                 if (!lua_isnil(L, 4)) {
1453                         playersao->m_physics_override_gravity = lua_tonumber(L, 4);
1454                         playersao->m_physics_override_sent = false;
1455                 }
1456         }
1457         return 0;
1458 }
1459
1460 // get_physics_override(self)
1461 int ObjectRef::l_get_physics_override(lua_State *L)
1462 {
1463         NO_MAP_LOCK_REQUIRED;
1464         ObjectRef *ref = checkobject(L, 1);
1465         PlayerSAO *playersao = getplayersao(ref);
1466         if (playersao == nullptr)
1467                 return 0;
1468
1469         lua_newtable(L);
1470         lua_pushnumber(L, playersao->m_physics_override_speed);
1471         lua_setfield(L, -2, "speed");
1472         lua_pushnumber(L, playersao->m_physics_override_jump);
1473         lua_setfield(L, -2, "jump");
1474         lua_pushnumber(L, playersao->m_physics_override_gravity);
1475         lua_setfield(L, -2, "gravity");
1476         lua_pushboolean(L, playersao->m_physics_override_sneak);
1477         lua_setfield(L, -2, "sneak");
1478         lua_pushboolean(L, playersao->m_physics_override_sneak_glitch);
1479         lua_setfield(L, -2, "sneak_glitch");
1480         lua_pushboolean(L, playersao->m_physics_override_new_move);
1481         lua_setfield(L, -2, "new_move");
1482         return 1;
1483 }
1484
1485 // hud_add(self, hud)
1486 int ObjectRef::l_hud_add(lua_State *L)
1487 {
1488         NO_MAP_LOCK_REQUIRED;
1489         ObjectRef *ref = checkobject(L, 1);
1490         RemotePlayer *player = getplayer(ref);
1491         if (player == nullptr)
1492                 return 0;
1493
1494         HudElement *elem = new HudElement;
1495         read_hud_element(L, elem);
1496
1497         u32 id = getServer(L)->hudAdd(player, elem);
1498         if (id == U32_MAX) {
1499                 delete elem;
1500                 return 0;
1501         }
1502
1503         lua_pushnumber(L, id);
1504         return 1;
1505 }
1506
1507 // hud_remove(self, id)
1508 int ObjectRef::l_hud_remove(lua_State *L)
1509 {
1510         NO_MAP_LOCK_REQUIRED;
1511         ObjectRef *ref = checkobject(L, 1);
1512         RemotePlayer *player = getplayer(ref);
1513         if (player == nullptr)
1514                 return 0;
1515
1516         u32 id = luaL_checkint(L, 2);
1517
1518         if (!getServer(L)->hudRemove(player, id))
1519                 return 0;
1520
1521         lua_pushboolean(L, true);
1522         return 1;
1523 }
1524
1525 // hud_change(self, id, stat, data)
1526 int ObjectRef::l_hud_change(lua_State *L)
1527 {
1528         NO_MAP_LOCK_REQUIRED;
1529         ObjectRef *ref = checkobject(L, 1);
1530         RemotePlayer *player = getplayer(ref);
1531         if (player == nullptr)
1532                 return 0;
1533
1534         u32 id = luaL_checkint(L, 2);
1535
1536         HudElement *elem = player->getHud(id);
1537         if (elem == nullptr)
1538                 return 0;
1539
1540         HudElementStat stat;
1541         void *value = nullptr;
1542         bool ok = read_hud_change(L, stat, elem, &value);
1543
1544         if (ok)
1545                 getServer(L)->hudChange(player, id, stat, value);
1546
1547         lua_pushboolean(L, ok);
1548         return 1;
1549 }
1550
1551 // hud_get(self, id)
1552 int ObjectRef::l_hud_get(lua_State *L)
1553 {
1554         NO_MAP_LOCK_REQUIRED;
1555         ObjectRef *ref = checkobject(L, 1);
1556         RemotePlayer *player = getplayer(ref);
1557         if (player == nullptr)
1558                 return 0;
1559
1560         u32 id = luaL_checkint(L, 2);
1561
1562         HudElement *elem = player->getHud(id);
1563         if (elem == nullptr)
1564                 return 0;
1565
1566         push_hud_element(L, elem);
1567         return 1;
1568 }
1569
1570 // hud_set_flags(self, flags)
1571 int ObjectRef::l_hud_set_flags(lua_State *L)
1572 {
1573         NO_MAP_LOCK_REQUIRED;
1574         ObjectRef *ref = checkobject(L, 1);
1575         RemotePlayer *player = getplayer(ref);
1576         if (player == nullptr)
1577                 return 0;
1578
1579         u32 flags = 0;
1580         u32 mask  = 0;
1581         bool flag;
1582
1583         const EnumString *esp = es_HudBuiltinElement;
1584         for (int i = 0; esp[i].str; i++) {
1585                 if (getboolfield(L, 2, esp[i].str, flag)) {
1586                         flags |= esp[i].num * flag;
1587                         mask  |= esp[i].num;
1588                 }
1589         }
1590         if (!getServer(L)->hudSetFlags(player, flags, mask))
1591                 return 0;
1592
1593         lua_pushboolean(L, true);
1594         return 1;
1595 }
1596
1597 // hud_get_flags(self)
1598 int ObjectRef::l_hud_get_flags(lua_State *L)
1599 {
1600         NO_MAP_LOCK_REQUIRED;
1601         ObjectRef *ref = checkobject(L, 1);
1602         RemotePlayer *player = getplayer(ref);
1603         if (player == nullptr)
1604                 return 0;
1605
1606         lua_newtable(L);
1607         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
1608         lua_setfield(L, -2, "hotbar");
1609         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
1610         lua_setfield(L, -2, "healthbar");
1611         lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
1612         lua_setfield(L, -2, "crosshair");
1613         lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
1614         lua_setfield(L, -2, "wielditem");
1615         lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
1616         lua_setfield(L, -2, "breathbar");
1617         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1618         lua_setfield(L, -2, "minimap");
1619         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1620         lua_setfield(L, -2, "minimap_radar");
1621         return 1;
1622 }
1623
1624 // hud_set_hotbar_itemcount(self, hotbar_itemcount)
1625 int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
1626 {
1627         NO_MAP_LOCK_REQUIRED;
1628         ObjectRef *ref = checkobject(L, 1);
1629         RemotePlayer *player = getplayer(ref);
1630         if (player == nullptr)
1631                 return 0;
1632
1633         s32 hotbar_itemcount = luaL_checkint(L, 2);
1634
1635         if (!getServer(L)->hudSetHotbarItemcount(player, hotbar_itemcount))
1636                 return 0;
1637
1638         lua_pushboolean(L, true);
1639         return 1;
1640 }
1641
1642 // hud_get_hotbar_itemcount(self)
1643 int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
1644 {
1645         NO_MAP_LOCK_REQUIRED;
1646         ObjectRef *ref = checkobject(L, 1);
1647         RemotePlayer *player = getplayer(ref);
1648         if (player == nullptr)
1649                 return 0;
1650
1651         lua_pushnumber(L, player->getHotbarItemcount());
1652         return 1;
1653 }
1654
1655 // hud_set_hotbar_image(self, name)
1656 int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
1657 {
1658         NO_MAP_LOCK_REQUIRED;
1659         ObjectRef *ref = checkobject(L, 1);
1660         RemotePlayer *player = getplayer(ref);
1661         if (player == nullptr)
1662                 return 0;
1663
1664         std::string name = readParam<std::string>(L, 2);
1665
1666         getServer(L)->hudSetHotbarImage(player, name);
1667         return 1;
1668 }
1669
1670 // hud_get_hotbar_image(self)
1671 int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
1672 {
1673         NO_MAP_LOCK_REQUIRED;
1674         ObjectRef *ref = checkobject(L, 1);
1675         RemotePlayer *player = getplayer(ref);
1676         if (player == nullptr)
1677                 return 0;
1678
1679         const std::string &name = player->getHotbarImage();
1680
1681         lua_pushlstring(L, name.c_str(), name.size());
1682         return 1;
1683 }
1684
1685 // hud_set_hotbar_selected_image(self, name)
1686 int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
1687 {
1688         NO_MAP_LOCK_REQUIRED;
1689         ObjectRef *ref = checkobject(L, 1);
1690         RemotePlayer *player = getplayer(ref);
1691         if (player == nullptr)
1692                 return 0;
1693
1694         std::string name = readParam<std::string>(L, 2);
1695
1696         getServer(L)->hudSetHotbarSelectedImage(player, name);
1697         return 1;
1698 }
1699
1700 // hud_get_hotbar_selected_image(self)
1701 int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
1702 {
1703         NO_MAP_LOCK_REQUIRED;
1704         ObjectRef *ref = checkobject(L, 1);
1705         RemotePlayer *player = getplayer(ref);
1706         if (player == nullptr)
1707                 return 0;
1708
1709         const std::string &name = player->getHotbarSelectedImage();
1710
1711         lua_pushlstring(L, name.c_str(), name.size());
1712         return 1;
1713 }
1714
1715 // set_sky(self, sky_parameters)
1716 int ObjectRef::l_set_sky(lua_State *L)
1717 {
1718         NO_MAP_LOCK_REQUIRED;
1719         ObjectRef *ref = checkobject(L, 1);
1720         RemotePlayer *player = getplayer(ref);
1721         if (player == nullptr)
1722                 return 0;
1723
1724         SkyboxParams sky_params = player->getSkyParams();
1725         bool is_colorspec = is_color_table(L, 2);
1726
1727         if (lua_istable(L, 2) && !is_colorspec) {
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                 /*
1752                 We want to avoid crashes, so we're checking even if we're not using them.
1753                 However, we want to ensure that the skybox can be set to nil when
1754                 using "regular" or "plain" skybox modes as textures aren't needed.
1755                 */
1756
1757                 if (sky_params.textures.size() != 6 && sky_params.textures.size() > 0)
1758                         throw LuaError("Skybox expects 6 textures!");
1759
1760                 sky_params.clouds = getboolfield_default(L, 2,
1761                         "clouds", sky_params.clouds);
1762
1763                 lua_getfield(L, 2, "sky_color");
1764                 if (lua_istable(L, -1)) {
1765                         lua_getfield(L, -1, "day_sky");
1766                         read_color(L, -1, &sky_params.sky_color.day_sky);
1767                         lua_pop(L, 1);
1768
1769                         lua_getfield(L, -1, "day_horizon");
1770                         read_color(L, -1, &sky_params.sky_color.day_horizon);
1771                         lua_pop(L, 1);
1772
1773                         lua_getfield(L, -1, "dawn_sky");
1774                         read_color(L, -1, &sky_params.sky_color.dawn_sky);
1775                         lua_pop(L, 1);
1776
1777                         lua_getfield(L, -1, "dawn_horizon");
1778                         read_color(L, -1, &sky_params.sky_color.dawn_horizon);
1779                         lua_pop(L, 1);
1780
1781                         lua_getfield(L, -1, "night_sky");
1782                         read_color(L, -1, &sky_params.sky_color.night_sky);
1783                         lua_pop(L, 1);
1784
1785                         lua_getfield(L, -1, "night_horizon");
1786                         read_color(L, -1, &sky_params.sky_color.night_horizon);
1787                         lua_pop(L, 1);
1788
1789                         lua_getfield(L, -1, "indoors");
1790                         read_color(L, -1, &sky_params.sky_color.indoors);
1791                         lua_pop(L, 1);
1792
1793                         // Prevent flickering clouds at dawn/dusk:
1794                         sky_params.fog_sun_tint = video::SColor(255, 255, 255, 255);
1795                         lua_getfield(L, -1, "fog_sun_tint");
1796                         read_color(L, -1, &sky_params.fog_sun_tint);
1797                         lua_pop(L, 1);
1798
1799                         sky_params.fog_moon_tint = video::SColor(255, 255, 255, 255);
1800                         lua_getfield(L, -1, "fog_moon_tint");
1801                         read_color(L, -1, &sky_params.fog_moon_tint);
1802                         lua_pop(L, 1);
1803
1804                         lua_getfield(L, -1, "fog_tint_type");
1805                         if (!lua_isnil(L, -1))
1806                                 sky_params.fog_tint_type = luaL_checkstring(L, -1);
1807                         lua_pop(L, 1);
1808
1809                         // Because we need to leave the "sky_color" table.
1810                         lua_pop(L, 1);
1811                 }
1812         } else {
1813                 // Handle old set_sky calls, and log deprecated:
1814                 log_deprecated(L, "Deprecated call to set_sky, please check lua_api.txt");
1815
1816                 // Fix sun, moon and stars showing when classic textured skyboxes are used
1817                 SunParams sun_params = player->getSunParams();
1818                 MoonParams moon_params = player->getMoonParams();
1819                 StarParams star_params = player->getStarParams();
1820
1821                 // Prevent erroneous background colors
1822                 sky_params.bgcolor = video::SColor(255, 255, 255, 255);
1823                 read_color(L, 2, &sky_params.bgcolor);
1824
1825                 sky_params.type = luaL_checkstring(L, 3);
1826
1827                 // Preserve old behaviour of the sun, moon and stars
1828                 // when using the old set_sky call.
1829                 if (sky_params.type == "regular") {
1830                         sun_params.visible = true;
1831                         sun_params.sunrise_visible = true;
1832                         moon_params.visible = true;
1833                         star_params.visible = true;
1834                 } else {
1835                         sun_params.visible = false;
1836                         sun_params.sunrise_visible = false;
1837                         moon_params.visible = false;
1838                         star_params.visible = false;
1839                 }
1840
1841                 sky_params.textures.clear();
1842                 if (lua_istable(L, 4)) {
1843                         lua_pushnil(L);
1844                         while (lua_next(L, 4) != 0) {
1845                         // Key at index -2, and value at index -1
1846                                 if (lua_isstring(L, -1))
1847                                         sky_params.textures.emplace_back(readParam<std::string>(L, -1));
1848                                 else
1849                                         sky_params.textures.emplace_back("");
1850                                 // Remove the value, keep the key for the next iteration
1851                                 lua_pop(L, 1);
1852                         }
1853                 }
1854                 if (sky_params.type == "skybox" && sky_params.textures.size() != 6)
1855                         throw LuaError("Skybox expects 6 textures.");
1856
1857                 sky_params.clouds = true;
1858                 if (lua_isboolean(L, 5))
1859                         sky_params.clouds = readParam<bool>(L, 5);
1860
1861                 getServer(L)->setSun(player, sun_params);
1862                 getServer(L)->setMoon(player, moon_params);
1863                 getServer(L)->setStars(player, star_params);
1864         }
1865         getServer(L)->setSky(player, sky_params);
1866         lua_pushboolean(L, true);
1867         return 1;
1868 }
1869
1870 // get_sky(self)
1871 int ObjectRef::l_get_sky(lua_State *L)
1872 {
1873         NO_MAP_LOCK_REQUIRED;
1874         ObjectRef *ref = checkobject(L, 1);
1875         RemotePlayer *player = getplayer(ref);
1876         if (player == nullptr)
1877                 return 0;
1878
1879         SkyboxParams skybox_params = player->getSkyParams();
1880
1881         push_ARGB8(L, skybox_params.bgcolor);
1882         lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
1883
1884         lua_newtable(L);
1885         s16 i = 1;
1886         for (const std::string &texture : skybox_params.textures) {
1887                 lua_pushlstring(L, texture.c_str(), texture.size());
1888                 lua_rawseti(L, -2, i++);
1889         }
1890         lua_pushboolean(L, skybox_params.clouds);
1891         return 4;
1892 }
1893
1894 // get_sky_color(self)
1895 int ObjectRef::l_get_sky_color(lua_State *L)
1896 {
1897         NO_MAP_LOCK_REQUIRED;
1898         ObjectRef *ref = checkobject(L, 1);
1899         RemotePlayer *player = getplayer(ref);
1900         if (player == nullptr)
1901                 return 0;
1902
1903         const SkyboxParams &skybox_params = player->getSkyParams();
1904
1905         lua_newtable(L);
1906         if (skybox_params.type == "regular") {
1907                 push_ARGB8(L, skybox_params.sky_color.day_sky);
1908                 lua_setfield(L, -2, "day_sky");
1909                 push_ARGB8(L, skybox_params.sky_color.day_horizon);
1910                 lua_setfield(L, -2, "day_horizon");
1911                 push_ARGB8(L, skybox_params.sky_color.dawn_sky);
1912                 lua_setfield(L, -2, "dawn_sky");
1913                 push_ARGB8(L, skybox_params.sky_color.dawn_horizon);
1914                 lua_setfield(L, -2, "dawn_horizon");
1915                 push_ARGB8(L, skybox_params.sky_color.night_sky);
1916                 lua_setfield(L, -2, "night_sky");
1917                 push_ARGB8(L, skybox_params.sky_color.night_horizon);
1918                 lua_setfield(L, -2, "night_horizon");
1919                 push_ARGB8(L, skybox_params.sky_color.indoors);
1920                 lua_setfield(L, -2, "indoors");
1921         }
1922         push_ARGB8(L, skybox_params.fog_sun_tint);
1923         lua_setfield(L, -2, "fog_sun_tint");
1924         push_ARGB8(L, skybox_params.fog_moon_tint);
1925         lua_setfield(L, -2, "fog_moon_tint");
1926         lua_pushstring(L, skybox_params.fog_tint_type.c_str());
1927         lua_setfield(L, -2, "fog_tint_type");
1928         return 1;
1929 }
1930
1931 // set_sun(self, sun_parameters)
1932 int ObjectRef::l_set_sun(lua_State *L)
1933 {
1934         NO_MAP_LOCK_REQUIRED;
1935         ObjectRef *ref = checkobject(L, 1);
1936         RemotePlayer *player = getplayer(ref);
1937         if (player == nullptr)
1938                 return 0;
1939
1940         luaL_checktype(L, 2, LUA_TTABLE);
1941         SunParams sun_params = player->getSunParams();
1942
1943         sun_params.visible = getboolfield_default(L, 2,
1944                         "visible", sun_params.visible);
1945         sun_params.texture = getstringfield_default(L, 2,
1946                         "texture", sun_params.texture);
1947         sun_params.tonemap = getstringfield_default(L, 2,
1948                         "tonemap", sun_params.tonemap);
1949         sun_params.sunrise = getstringfield_default(L, 2,
1950                         "sunrise", sun_params.sunrise);
1951         sun_params.sunrise_visible = getboolfield_default(L, 2,
1952                         "sunrise_visible", sun_params.sunrise_visible);
1953         sun_params.scale = getfloatfield_default(L, 2,
1954                         "scale", sun_params.scale);
1955
1956         getServer(L)->setSun(player, sun_params);
1957         lua_pushboolean(L, true);
1958         return 1;
1959 }
1960
1961 //get_sun(self)
1962 int ObjectRef::l_get_sun(lua_State *L)
1963 {
1964         NO_MAP_LOCK_REQUIRED;
1965         ObjectRef *ref = checkobject(L, 1);
1966         RemotePlayer *player = getplayer(ref);
1967         if (player == nullptr)
1968                 return 0;
1969
1970         const SunParams &sun_params = player->getSunParams();
1971
1972         lua_newtable(L);
1973         lua_pushboolean(L, sun_params.visible);
1974         lua_setfield(L, -2, "visible");
1975         lua_pushstring(L, sun_params.texture.c_str());
1976         lua_setfield(L, -2, "texture");
1977         lua_pushstring(L, sun_params.tonemap.c_str());
1978         lua_setfield(L, -2, "tonemap");
1979         lua_pushstring(L, sun_params.sunrise.c_str());
1980         lua_setfield(L, -2, "sunrise");
1981         lua_pushboolean(L, sun_params.sunrise_visible);
1982         lua_setfield(L, -2, "sunrise_visible");
1983         lua_pushnumber(L, sun_params.scale);
1984         lua_setfield(L, -2, "scale");
1985         return 1;
1986 }
1987
1988 // set_moon(self, moon_parameters)
1989 int ObjectRef::l_set_moon(lua_State *L)
1990 {
1991         NO_MAP_LOCK_REQUIRED;
1992         ObjectRef *ref = checkobject(L, 1);
1993         RemotePlayer *player = getplayer(ref);
1994         if (player == nullptr)
1995                 return 0;
1996
1997         luaL_checktype(L, 2, LUA_TTABLE);
1998         MoonParams moon_params = player->getMoonParams();
1999
2000         moon_params.visible = getboolfield_default(L, 2,
2001                 "visible", moon_params.visible);
2002         moon_params.texture = getstringfield_default(L, 2,
2003                 "texture", moon_params.texture);
2004         moon_params.tonemap = getstringfield_default(L, 2,
2005                 "tonemap", moon_params.tonemap);
2006         moon_params.scale = getfloatfield_default(L, 2,
2007                 "scale", moon_params.scale);
2008
2009         getServer(L)->setMoon(player, moon_params);
2010         lua_pushboolean(L, true);
2011         return 1;
2012 }
2013
2014 // get_moon(self)
2015 int ObjectRef::l_get_moon(lua_State *L)
2016 {
2017         NO_MAP_LOCK_REQUIRED;
2018         ObjectRef *ref = checkobject(L, 1);
2019         RemotePlayer *player = getplayer(ref);
2020         if (player == nullptr)
2021                 return 0;
2022
2023         const MoonParams &moon_params = player->getMoonParams();
2024
2025         lua_newtable(L);
2026         lua_pushboolean(L, moon_params.visible);
2027         lua_setfield(L, -2, "visible");
2028         lua_pushstring(L, moon_params.texture.c_str());
2029         lua_setfield(L, -2, "texture");
2030         lua_pushstring(L, moon_params.tonemap.c_str());
2031         lua_setfield(L, -2, "tonemap");
2032         lua_pushnumber(L, moon_params.scale);
2033         lua_setfield(L, -2, "scale");
2034         return 1;
2035 }
2036
2037 // set_stars(self, star_parameters)
2038 int ObjectRef::l_set_stars(lua_State *L)
2039 {
2040         NO_MAP_LOCK_REQUIRED;
2041         ObjectRef *ref = checkobject(L, 1);
2042         RemotePlayer *player = getplayer(ref);
2043         if (player == nullptr)
2044                 return 0;
2045
2046         luaL_checktype(L, 2, LUA_TTABLE);
2047         StarParams star_params = player->getStarParams();
2048
2049         star_params.visible = getboolfield_default(L, 2,
2050                 "visible", star_params.visible);
2051         star_params.count = getintfield_default(L, 2,
2052                 "count", star_params.count);
2053
2054         lua_getfield(L, 2, "star_color");
2055         if (!lua_isnil(L, -1))
2056                 read_color(L, -1, &star_params.starcolor);
2057         lua_pop(L, 1);
2058
2059         star_params.scale = getfloatfield_default(L, 2,
2060                 "scale", star_params.scale);
2061
2062         getServer(L)->setStars(player, star_params);
2063         lua_pushboolean(L, true);
2064         return 1;
2065 }
2066
2067 // get_stars(self)
2068 int ObjectRef::l_get_stars(lua_State *L)
2069 {
2070         NO_MAP_LOCK_REQUIRED;
2071         ObjectRef *ref = checkobject(L, 1);
2072         RemotePlayer *player = getplayer(ref);
2073         if (player == nullptr)
2074                 return 0;
2075
2076         const StarParams &star_params = player->getStarParams();
2077
2078         lua_newtable(L);
2079         lua_pushboolean(L, star_params.visible);
2080         lua_setfield(L, -2, "visible");
2081         lua_pushnumber(L, star_params.count);
2082         lua_setfield(L, -2, "count");
2083         push_ARGB8(L, star_params.starcolor);
2084         lua_setfield(L, -2, "star_color");
2085         lua_pushnumber(L, star_params.scale);
2086         lua_setfield(L, -2, "scale");
2087         return 1;
2088 }
2089
2090 // set_clouds(self, cloud_parameters)
2091 int ObjectRef::l_set_clouds(lua_State *L)
2092 {
2093         NO_MAP_LOCK_REQUIRED;
2094         ObjectRef *ref = checkobject(L, 1);
2095         RemotePlayer *player = getplayer(ref);
2096         if (player == nullptr)
2097                 return 0;
2098
2099         luaL_checktype(L, 2, LUA_TTABLE);
2100         CloudParams cloud_params = player->getCloudParams();
2101
2102         cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
2103
2104         lua_getfield(L, 2, "color");
2105         if (!lua_isnil(L, -1))
2106                 read_color(L, -1, &cloud_params.color_bright);
2107         lua_pop(L, 1);
2108         lua_getfield(L, 2, "ambient");
2109         if (!lua_isnil(L, -1))
2110                 read_color(L, -1, &cloud_params.color_ambient);
2111         lua_pop(L, 1);
2112
2113         cloud_params.height    = getfloatfield_default(L, 2, "height",    cloud_params.height   );
2114         cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
2115
2116         lua_getfield(L, 2, "speed");
2117         if (lua_istable(L, -1)) {
2118                 v2f new_speed;
2119                 new_speed.X = getfloatfield_default(L, -1, "x", 0);
2120                 new_speed.Y = getfloatfield_default(L, -1, "z", 0);
2121                 cloud_params.speed = new_speed;
2122         }
2123         lua_pop(L, 1);
2124
2125         getServer(L)->setClouds(player, cloud_params);
2126         lua_pushboolean(L, true);
2127         return 1;
2128 }
2129
2130 int ObjectRef::l_get_clouds(lua_State *L)
2131 {
2132         NO_MAP_LOCK_REQUIRED;
2133         ObjectRef *ref = checkobject(L, 1);
2134         RemotePlayer *player = getplayer(ref);
2135         if (player == nullptr)
2136                 return 0;
2137
2138         const CloudParams &cloud_params = player->getCloudParams();
2139
2140         lua_newtable(L);
2141         lua_pushnumber(L, cloud_params.density);
2142         lua_setfield(L, -2, "density");
2143         push_ARGB8(L, cloud_params.color_bright);
2144         lua_setfield(L, -2, "color");
2145         push_ARGB8(L, cloud_params.color_ambient);
2146         lua_setfield(L, -2, "ambient");
2147         lua_pushnumber(L, cloud_params.height);
2148         lua_setfield(L, -2, "height");
2149         lua_pushnumber(L, cloud_params.thickness);
2150         lua_setfield(L, -2, "thickness");
2151         lua_newtable(L);
2152         lua_pushnumber(L, cloud_params.speed.X);
2153         lua_setfield(L, -2, "x");
2154         lua_pushnumber(L, cloud_params.speed.Y);
2155         lua_setfield(L, -2, "y");
2156         lua_setfield(L, -2, "speed");
2157         return 1;
2158 }
2159
2160
2161 // override_day_night_ratio(self, ratio)
2162 int ObjectRef::l_override_day_night_ratio(lua_State *L)
2163 {
2164         NO_MAP_LOCK_REQUIRED;
2165         ObjectRef *ref = checkobject(L, 1);
2166         RemotePlayer *player = getplayer(ref);
2167         if (player == nullptr)
2168                 return 0;
2169
2170         bool do_override = false;
2171         float ratio = 0.0f;
2172
2173         if (!lua_isnil(L, 2)) {
2174                 do_override = true;
2175                 ratio = readParam<float>(L, 2);
2176                 luaL_argcheck(L, ratio >= 0.0f && ratio <= 1.0f, 1,
2177                         "value must be between 0 and 1");
2178         }
2179
2180         getServer(L)->overrideDayNightRatio(player, do_override, ratio);
2181         lua_pushboolean(L, true);
2182         return 1;
2183 }
2184
2185 // get_day_night_ratio(self)
2186 int ObjectRef::l_get_day_night_ratio(lua_State *L)
2187 {
2188         NO_MAP_LOCK_REQUIRED;
2189         ObjectRef *ref = checkobject(L, 1);
2190         RemotePlayer *player = getplayer(ref);
2191         if (player == nullptr)
2192                 return 0;
2193
2194         bool do_override;
2195         float ratio;
2196         player->getDayNightRatio(&do_override, &ratio);
2197
2198         if (do_override)
2199                 lua_pushnumber(L, ratio);
2200         else
2201                 lua_pushnil(L);
2202
2203         return 1;
2204 }
2205
2206 // set_minimap_modes(self, modes, selected_mode)
2207 int ObjectRef::l_set_minimap_modes(lua_State *L)
2208 {
2209         NO_MAP_LOCK_REQUIRED;
2210         ObjectRef *ref = checkobject(L, 1);
2211         RemotePlayer *player = getplayer(ref);
2212         if (player == nullptr)
2213                 return 0;
2214
2215         luaL_checktype(L, 2, LUA_TTABLE);
2216         std::vector<MinimapMode> modes;
2217         s16 selected_mode = readParam<s16>(L, 3);
2218
2219         lua_pushnil(L);
2220         while (lua_next(L, 2) != 0) {
2221                 /* key is at index -2, value is at index -1 */
2222                 if (lua_istable(L, -1)) {
2223                         bool ok = true;
2224                         MinimapMode mode;
2225                         std::string type = getstringfield_default(L, -1, "type", "");
2226                         if (type == "off")
2227                                 mode.type = MINIMAP_TYPE_OFF;
2228                         else if (type == "surface")
2229                                 mode.type = MINIMAP_TYPE_SURFACE;
2230                         else if (type == "radar")
2231                                 mode.type = MINIMAP_TYPE_RADAR;
2232                         else if (type == "texture") {
2233                                 mode.type = MINIMAP_TYPE_TEXTURE;
2234                                 mode.texture = getstringfield_default(L, -1, "texture", "");
2235                                 mode.scale = getintfield_default(L, -1, "scale", 1);
2236                         } else {
2237                                 warningstream << "Minimap mode of unknown type \"" << type.c_str()
2238                                         << "\" ignored.\n" << std::endl;
2239                                 ok = false;
2240                         }
2241
2242                         if (ok) {
2243                                 mode.label = getstringfield_default(L, -1, "label", "");
2244                                 // Size is limited to 512. Performance gets poor if size too large, and
2245                                 // segfaults have been experienced.
2246                                 mode.size = rangelim(getintfield_default(L, -1, "size", 0), 1, 512);
2247                                 modes.push_back(mode);
2248                         }
2249                 }
2250                 /* removes 'value'; keeps 'key' for next iteration */
2251                 lua_pop(L, 1);
2252         }
2253         lua_pop(L, 1); // Remove key
2254
2255         getServer(L)->SendMinimapModes(player->getPeerId(), modes, selected_mode);
2256         return 0;
2257 }
2258
2259 ObjectRef::ObjectRef(ServerActiveObject *object):
2260         m_object(object)
2261 {}
2262
2263 // Creates an ObjectRef and leaves it on top of stack
2264 // Not callable from Lua; all references are created on the C side.
2265 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
2266 {
2267         ObjectRef *obj = new ObjectRef(object);
2268         *(void **)(lua_newuserdata(L, sizeof(void *))) = obj;
2269         luaL_getmetatable(L, className);
2270         lua_setmetatable(L, -2);
2271 }
2272
2273 void ObjectRef::set_null(lua_State *L)
2274 {
2275         ObjectRef *obj = checkobject(L, -1);
2276         obj->m_object = nullptr;
2277 }
2278
2279 void ObjectRef::Register(lua_State *L)
2280 {
2281         lua_newtable(L);
2282         int methodtable = lua_gettop(L);
2283         luaL_newmetatable(L, className);
2284         int metatable = lua_gettop(L);
2285
2286         lua_pushliteral(L, "__metatable");
2287         lua_pushvalue(L, methodtable);
2288         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
2289
2290         lua_pushliteral(L, "__index");
2291         lua_pushvalue(L, methodtable);
2292         lua_settable(L, metatable);
2293
2294         lua_pushliteral(L, "__gc");
2295         lua_pushcfunction(L, gc_object);
2296         lua_settable(L, metatable);
2297
2298         lua_pop(L, 1);  // drop metatable
2299
2300         luaL_register(L, nullptr, methods);  // fill methodtable
2301         lua_pop(L, 1);  // drop methodtable
2302 }
2303
2304 const char ObjectRef::className[] = "ObjectRef";
2305 luaL_Reg ObjectRef::methods[] = {
2306         // ServerActiveObject
2307         luamethod(ObjectRef, remove),
2308         luamethod_aliased(ObjectRef, get_pos, getpos),
2309         luamethod_aliased(ObjectRef, set_pos, setpos),
2310         luamethod_aliased(ObjectRef, move_to, moveto),
2311         luamethod(ObjectRef, punch),
2312         luamethod(ObjectRef, right_click),
2313         luamethod(ObjectRef, set_hp),
2314         luamethod(ObjectRef, get_hp),
2315         luamethod(ObjectRef, get_inventory),
2316         luamethod(ObjectRef, get_wield_list),
2317         luamethod(ObjectRef, get_wield_index),
2318         luamethod(ObjectRef, get_wielded_item),
2319         luamethod(ObjectRef, set_wielded_item),
2320         luamethod(ObjectRef, set_armor_groups),
2321         luamethod(ObjectRef, get_armor_groups),
2322         luamethod(ObjectRef, set_animation),
2323         luamethod(ObjectRef, get_animation),
2324         luamethod(ObjectRef, set_animation_frame_speed),
2325         luamethod(ObjectRef, set_bone_position),
2326         luamethod(ObjectRef, get_bone_position),
2327         luamethod(ObjectRef, set_attach),
2328         luamethod(ObjectRef, get_attach),
2329         luamethod(ObjectRef, get_children),
2330         luamethod(ObjectRef, set_detach),
2331         luamethod(ObjectRef, set_properties),
2332         luamethod(ObjectRef, get_properties),
2333         luamethod(ObjectRef, set_nametag_attributes),
2334         luamethod(ObjectRef, get_nametag_attributes),
2335
2336         luamethod_aliased(ObjectRef, set_velocity, setvelocity),
2337         luamethod_aliased(ObjectRef, add_velocity, add_player_velocity),
2338         luamethod_aliased(ObjectRef, get_velocity, getvelocity),
2339         luamethod_dep(ObjectRef, get_velocity, get_player_velocity),
2340
2341         // LuaEntitySAO-only
2342         luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
2343         luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
2344         luamethod_aliased(ObjectRef, set_yaw, setyaw),
2345         luamethod_aliased(ObjectRef, get_yaw, getyaw),
2346         luamethod(ObjectRef, set_rotation),
2347         luamethod(ObjectRef, get_rotation),
2348         luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
2349         luamethod(ObjectRef, get_texture_mod),
2350         luamethod_aliased(ObjectRef, set_sprite, setsprite),
2351         luamethod(ObjectRef, get_entity_name),
2352         luamethod(ObjectRef, get_luaentity),
2353
2354         // Player-only
2355         luamethod(ObjectRef, is_player),
2356         luamethod(ObjectRef, get_player_name),
2357         luamethod(ObjectRef, get_look_dir),
2358         luamethod(ObjectRef, get_look_pitch),
2359         luamethod(ObjectRef, get_look_yaw),
2360         luamethod(ObjectRef, get_look_vertical),
2361         luamethod(ObjectRef, get_look_horizontal),
2362         luamethod(ObjectRef, set_look_horizontal),
2363         luamethod(ObjectRef, set_look_vertical),
2364         luamethod(ObjectRef, set_look_yaw),
2365         luamethod(ObjectRef, set_look_pitch),
2366         luamethod(ObjectRef, get_fov),
2367         luamethod(ObjectRef, set_fov),
2368         luamethod(ObjectRef, get_breath),
2369         luamethod(ObjectRef, set_breath),
2370         luamethod(ObjectRef, get_attribute),
2371         luamethod(ObjectRef, set_attribute),
2372         luamethod(ObjectRef, get_meta),
2373         luamethod(ObjectRef, set_inventory_formspec),
2374         luamethod(ObjectRef, get_inventory_formspec),
2375         luamethod(ObjectRef, set_formspec_prepend),
2376         luamethod(ObjectRef, get_formspec_prepend),
2377         luamethod(ObjectRef, get_player_control),
2378         luamethod(ObjectRef, get_player_control_bits),
2379         luamethod(ObjectRef, set_physics_override),
2380         luamethod(ObjectRef, get_physics_override),
2381         luamethod(ObjectRef, hud_add),
2382         luamethod(ObjectRef, hud_remove),
2383         luamethod(ObjectRef, hud_change),
2384         luamethod(ObjectRef, hud_get),
2385         luamethod(ObjectRef, hud_set_flags),
2386         luamethod(ObjectRef, hud_get_flags),
2387         luamethod(ObjectRef, hud_set_hotbar_itemcount),
2388         luamethod(ObjectRef, hud_get_hotbar_itemcount),
2389         luamethod(ObjectRef, hud_set_hotbar_image),
2390         luamethod(ObjectRef, hud_get_hotbar_image),
2391         luamethod(ObjectRef, hud_set_hotbar_selected_image),
2392         luamethod(ObjectRef, hud_get_hotbar_selected_image),
2393         luamethod(ObjectRef, set_sky),
2394         luamethod(ObjectRef, get_sky),
2395         luamethod(ObjectRef, get_sky_color),
2396         luamethod(ObjectRef, set_sun),
2397         luamethod(ObjectRef, get_sun),
2398         luamethod(ObjectRef, set_moon),
2399         luamethod(ObjectRef, get_moon),
2400         luamethod(ObjectRef, set_stars),
2401         luamethod(ObjectRef, get_stars),
2402         luamethod(ObjectRef, set_clouds),
2403         luamethod(ObjectRef, get_clouds),
2404         luamethod(ObjectRef, override_day_night_ratio),
2405         luamethod(ObjectRef, get_day_night_ratio),
2406         luamethod(ObjectRef, set_local_animation),
2407         luamethod(ObjectRef, get_local_animation),
2408         luamethod(ObjectRef, set_eye_offset),
2409         luamethod(ObjectRef, get_eye_offset),
2410         luamethod(ObjectRef, send_mapblock),
2411         luamethod(ObjectRef, set_minimap_modes),
2412         {0,0}
2413 };