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