]> git.lizzy.rs Git - minetest.git/blob - src/content_sao.cpp
Fix lava damage on player's upper body
[minetest.git] / src / content_sao.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-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 "content_sao.h"
21 #include "collision.h"
22 #include "environment.h"
23 #include "settings.h"
24 #include "main.h" // For g_profiler
25 #include "profiler.h"
26 #include "serialization.h" // For compressZlib
27 #include "tool.h" // For ToolCapabilities
28 #include "gamedef.h"
29 #include "player.h"
30 #include "scriptapi.h"
31 #include "genericobject.h"
32 #include "util/serialize.h"
33
34 std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
35
36 /*
37         DummyLoadSAO
38 */
39
40 class DummyLoadSAO : public ServerActiveObject
41 {
42 public:
43         DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type):
44                 ServerActiveObject(env, pos)
45         {
46                 ServerActiveObject::registerType(type, create);
47         }
48         // Pretend to be the test object (to fool the client)
49         u8 getType() const
50         { return ACTIVEOBJECT_TYPE_TEST; }
51         // And never save to disk
52         bool isStaticAllowed() const
53         { return false; }
54         
55         static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
56                         const std::string &data)
57         {
58                 return new DummyLoadSAO(env, pos, 0);
59         }
60
61         void step(float dtime, bool send_recommended)
62         {
63                 m_removed = true;
64                 infostream<<"DummyLoadSAO step"<<std::endl;
65         }
66
67         bool getCollisionBox(aabb3f *toset) {
68                 return false;
69         }
70
71 private:
72 };
73
74 // Prototype (registers item for deserialization)
75 DummyLoadSAO proto1_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_RAT);
76 DummyLoadSAO proto2_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_OERKKI1);
77 DummyLoadSAO proto3_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_FIREFLY);
78 DummyLoadSAO proto4_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_MOBV2);
79
80 /*
81         TestSAO
82 */
83
84 class TestSAO : public ServerActiveObject
85 {
86 public:
87         TestSAO(ServerEnvironment *env, v3f pos):
88                 ServerActiveObject(env, pos),
89                 m_timer1(0),
90                 m_age(0)
91         {
92                 ServerActiveObject::registerType(getType(), create);
93         }
94         u8 getType() const
95         { return ACTIVEOBJECT_TYPE_TEST; }
96         
97         static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
98                         const std::string &data)
99         {
100                 return new TestSAO(env, pos);
101         }
102
103         void step(float dtime, bool send_recommended)
104         {
105                 m_age += dtime;
106                 if(m_age > 10)
107                 {
108                         m_removed = true;
109                         return;
110                 }
111
112                 m_base_position.Y += dtime * BS * 2;
113                 if(m_base_position.Y > 8*BS)
114                         m_base_position.Y = 2*BS;
115
116                 if(send_recommended == false)
117                         return;
118
119                 m_timer1 -= dtime;
120                 if(m_timer1 < 0.0)
121                 {
122                         m_timer1 += 0.125;
123
124                         std::string data;
125
126                         data += itos(0); // 0 = position
127                         data += " ";
128                         data += itos(m_base_position.X);
129                         data += " ";
130                         data += itos(m_base_position.Y);
131                         data += " ";
132                         data += itos(m_base_position.Z);
133
134                         ActiveObjectMessage aom(getId(), false, data);
135                         m_messages_out.push_back(aom);
136                 }
137         }
138
139         bool getCollisionBox(aabb3f *toset) {
140                 return false;
141         }
142
143 private:
144         float m_timer1;
145         float m_age;
146 };
147
148 // Prototype (registers item for deserialization)
149 TestSAO proto_TestSAO(NULL, v3f(0,0,0));
150
151 /*
152         ItemSAO
153
154         DEPRECATED: New dropped items are implemented in Lua; see
155                     builtin/item_entity.lua.
156 */
157
158 class ItemSAO : public ServerActiveObject
159 {
160 public:
161         u8 getType() const
162         { return ACTIVEOBJECT_TYPE_ITEM; }
163         
164         float getMinimumSavedMovement()
165         { return 0.1*BS; }
166
167         static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
168                         const std::string &data)
169         {
170                 std::istringstream is(data, std::ios::binary);
171                 char buf[1];
172                 // read version
173                 is.read(buf, 1);
174                 u8 version = buf[0];
175                 // check if version is supported
176                 if(version != 0)
177                         return NULL;
178                 std::string itemstring = deSerializeString(is);
179                 infostream<<"create(): Creating item \""
180                                 <<itemstring<<"\""<<std::endl;
181                 return new ItemSAO(env, pos, itemstring);
182         }
183
184         ItemSAO(ServerEnvironment *env, v3f pos,
185                         const std::string itemstring):
186                 ServerActiveObject(env, pos),
187                 m_itemstring(itemstring),
188                 m_itemstring_changed(false),
189                 m_speed_f(0,0,0),
190                 m_last_sent_position(0,0,0)
191         {
192                 ServerActiveObject::registerType(getType(), create);
193         }
194
195         void step(float dtime, bool send_recommended)
196         {
197                 ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
198
199                 assert(m_env);
200
201                 const float interval = 0.2;
202                 if(m_move_interval.step(dtime, interval)==false)
203                         return;
204                 dtime = interval;
205                 
206                 core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
207                 collisionMoveResult moveresult;
208                 // Apply gravity
209                 m_speed_f += v3f(0, -dtime*9.81*BS, 0);
210                 // Maximum movement without glitches
211                 f32 pos_max_d = BS*0.25;
212                 // Limit speed
213                 if(m_speed_f.getLength()*dtime > pos_max_d)
214                         m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
215                 v3f pos_f = getBasePosition();
216                 v3f pos_f_old = pos_f;
217                 v3f accel_f = v3f(0,0,0);
218                 f32 stepheight = 0;
219                 moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
220                                 pos_max_d, box, stepheight, dtime,
221                                 pos_f, m_speed_f, accel_f);
222                 
223                 if(send_recommended == false)
224                         return;
225
226                 if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
227                 {
228                         setBasePosition(pos_f);
229                         m_last_sent_position = pos_f;
230
231                         std::ostringstream os(std::ios::binary);
232                         // command (0 = update position)
233                         writeU8(os, 0);
234                         // pos
235                         writeV3F1000(os, m_base_position);
236                         // create message and add to list
237                         ActiveObjectMessage aom(getId(), false, os.str());
238                         m_messages_out.push_back(aom);
239                 }
240                 if(m_itemstring_changed)
241                 {
242                         m_itemstring_changed = false;
243
244                         std::ostringstream os(std::ios::binary);
245                         // command (1 = update itemstring)
246                         writeU8(os, 1);
247                         // itemstring
248                         os<<serializeString(m_itemstring);
249                         // create message and add to list
250                         ActiveObjectMessage aom(getId(), false, os.str());
251                         m_messages_out.push_back(aom);
252                 }
253         }
254
255         std::string getClientInitializationData(u16 protocol_version)
256         {
257                 std::ostringstream os(std::ios::binary);
258                 // version
259                 writeU8(os, 0);
260                 // pos
261                 writeV3F1000(os, m_base_position);
262                 // itemstring
263                 os<<serializeString(m_itemstring);
264                 return os.str();
265         }
266
267         std::string getStaticData()
268         {
269                 infostream<<__FUNCTION_NAME<<std::endl;
270                 std::ostringstream os(std::ios::binary);
271                 // version
272                 writeU8(os, 0);
273                 // itemstring
274                 os<<serializeString(m_itemstring);
275                 return os.str();
276         }
277
278         ItemStack createItemStack()
279         {
280                 try{
281                         IItemDefManager *idef = m_env->getGameDef()->idef();
282                         ItemStack item;
283                         item.deSerialize(m_itemstring, idef);
284                         infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
285                                         <<"\" -> item=\""<<item.getItemString()<<"\""
286                                         <<std::endl;
287                         return item;
288                 }
289                 catch(SerializationError &e)
290                 {
291                         infostream<<__FUNCTION_NAME<<": serialization error: "
292                                         <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
293                         return ItemStack();
294                 }
295         }
296
297         int punch(v3f dir,
298                         const ToolCapabilities *toolcap,
299                         ServerActiveObject *puncher,
300                         float time_from_last_punch)
301         {
302                 // Take item into inventory
303                 ItemStack item = createItemStack();
304                 Inventory *inv = puncher->getInventory();
305                 if(inv != NULL)
306                 {
307                         std::string wieldlist = puncher->getWieldList();
308                         ItemStack leftover = inv->addItem(wieldlist, item);
309                         puncher->setInventoryModified();
310                         if(leftover.empty())
311                         {
312                                 m_removed = true;
313                         }
314                         else
315                         {
316                                 m_itemstring = leftover.getItemString();
317                                 m_itemstring_changed = true;
318                         }
319                 }
320                 
321                 return 0;
322         }
323
324         bool getCollisionBox(aabb3f *toset) {
325                 return false;
326         }
327
328
329 private:
330         std::string m_itemstring;
331         bool m_itemstring_changed;
332         v3f m_speed_f;
333         v3f m_last_sent_position;
334         IntervalLimiter m_move_interval;
335 };
336
337 // Prototype (registers item for deserialization)
338 ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
339
340 ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
341                 const std::string itemstring)
342 {
343         return new ItemSAO(env, pos, itemstring);
344 }
345
346 /*
347         LuaEntitySAO
348 */
349
350 // Prototype (registers item for deserialization)
351 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
352
353 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
354                 const std::string &name, const std::string &state):
355         ServerActiveObject(env, pos),
356         m_init_name(name),
357         m_init_state(state),
358         m_registered(false),
359         m_hp(-1),
360         m_velocity(0,0,0),
361         m_acceleration(0,0,0),
362         m_yaw(0),
363         m_properties_sent(true),
364         m_last_sent_yaw(0),
365         m_last_sent_position(0,0,0),
366         m_last_sent_velocity(0,0,0),
367         m_last_sent_position_timer(0),
368         m_last_sent_move_precision(0),
369         m_armor_groups_sent(false),
370         m_animation_speed(0),
371         m_animation_blend(0),
372         m_animation_sent(false),
373         m_bone_position_sent(false),
374         m_attachment_parent_id(0),
375         m_attachment_sent(false)
376 {
377         // Only register type if no environment supplied
378         if(env == NULL){
379                 ServerActiveObject::registerType(getType(), create);
380                 return;
381         }
382         
383         // Initialize something to armor groups
384         m_armor_groups["fleshy"] = 100;
385 }
386
387 LuaEntitySAO::~LuaEntitySAO()
388 {
389         if(m_registered){
390                 lua_State *L = m_env->getLua();
391                 scriptapi_luaentity_rm(L, m_id);
392         }
393 }
394
395 void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
396 {
397         ServerActiveObject::addedToEnvironment(dtime_s);
398         
399         // Create entity from name
400         lua_State *L = m_env->getLua();
401         m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
402         
403         if(m_registered){
404                 // Get properties
405                 scriptapi_luaentity_get_properties(L, m_id, &m_prop);
406                 // Initialize HP from properties
407                 m_hp = m_prop.hp_max;
408                 // Activate entity, supplying serialized state
409                 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str(), dtime_s);
410         }
411 }
412
413 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
414                 const std::string &data)
415 {
416         std::string name;
417         std::string state;
418         s16 hp = 1;
419         v3f velocity;
420         float yaw = 0;
421         if(data != ""){
422                 std::istringstream is(data, std::ios::binary);
423                 // read version
424                 u8 version = readU8(is);
425                 // check if version is supported
426                 if(version == 0){
427                         name = deSerializeString(is);
428                         state = deSerializeLongString(is);
429                 }
430                 else if(version == 1){
431                         name = deSerializeString(is);
432                         state = deSerializeLongString(is);
433                         hp = readS16(is);
434                         velocity = readV3F1000(is);
435                         yaw = readF1000(is);
436                 }
437         }
438         // create object
439         infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
440                         <<state<<"\")"<<std::endl;
441         LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
442         sao->m_hp = hp;
443         sao->m_velocity = velocity;
444         sao->m_yaw = yaw;
445         return sao;
446 }
447
448 bool LuaEntitySAO::isAttached()
449 {
450         if(!m_attachment_parent_id)
451                 return false;
452         // Check if the parent still exists
453         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
454         if(obj)
455                 return true;
456         return false;
457 }
458
459 void LuaEntitySAO::step(float dtime, bool send_recommended)
460 {
461         if(!m_properties_sent)
462         {
463                 m_properties_sent = true;
464                 std::string str = getPropertyPacket();
465                 // create message and add to list
466                 ActiveObjectMessage aom(getId(), true, str);
467                 m_messages_out.push_back(aom);
468         }
469
470         // If attached, check that our parent is still there. If it isn't, detach.
471         if(m_attachment_parent_id && !isAttached())
472         {
473                 m_attachment_parent_id = 0;
474                 m_attachment_bone = "";
475                 m_attachment_position = v3f(0,0,0);
476                 m_attachment_rotation = v3f(0,0,0);
477                 sendPosition(false, true);
478         }
479
480         m_last_sent_position_timer += dtime;
481
482         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
483         // If the object gets detached this comes into effect automatically from the last known origin
484         if(isAttached())
485         {
486                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
487                 m_base_position = pos;
488                 m_velocity = v3f(0,0,0);
489                 m_acceleration = v3f(0,0,0);
490         }
491         else
492         {
493                 if(m_prop.physical){
494                         core::aabbox3d<f32> box = m_prop.collisionbox;
495                         box.MinEdge *= BS;
496                         box.MaxEdge *= BS;
497                         collisionMoveResult moveresult;
498                         f32 pos_max_d = BS*0.25; // Distance per iteration
499                         f32 stepheight = 0; // Maximum climbable step height
500                         v3f p_pos = m_base_position;
501                         v3f p_velocity = m_velocity;
502                         v3f p_acceleration = m_acceleration;
503                         moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
504                                         pos_max_d, box, stepheight, dtime,
505                                         p_pos, p_velocity, p_acceleration,this);
506                         // Apply results
507                         m_base_position = p_pos;
508                         m_velocity = p_velocity;
509                         m_acceleration = p_acceleration;
510                 } else {
511                         m_base_position += dtime * m_velocity + 0.5 * dtime
512                                         * dtime * m_acceleration;
513                         m_velocity += dtime * m_acceleration;
514                 }
515         }
516
517         if(m_registered){
518                 lua_State *L = m_env->getLua();
519                 scriptapi_luaentity_step(L, m_id, dtime);
520         }
521
522         if(send_recommended == false)
523                 return;
524
525         if(!isAttached())
526         {
527                 // TODO: force send when acceleration changes enough?
528                 float minchange = 0.2*BS;
529                 if(m_last_sent_position_timer > 1.0){
530                         minchange = 0.01*BS;
531                 } else if(m_last_sent_position_timer > 0.2){
532                         minchange = 0.05*BS;
533                 }
534                 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
535                 move_d += m_last_sent_move_precision;
536                 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
537                 if(move_d > minchange || vel_d > minchange ||
538                                 fabs(m_yaw - m_last_sent_yaw) > 1.0){
539                         sendPosition(true, false);
540                 }
541         }
542
543         if(m_armor_groups_sent == false){
544                 m_armor_groups_sent = true;
545                 std::string str = gob_cmd_update_armor_groups(
546                                 m_armor_groups);
547                 // create message and add to list
548                 ActiveObjectMessage aom(getId(), true, str);
549                 m_messages_out.push_back(aom);
550         }
551
552         if(m_animation_sent == false){
553                 m_animation_sent = true;
554                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
555                 // create message and add to list
556                 ActiveObjectMessage aom(getId(), true, str);
557                 m_messages_out.push_back(aom);
558         }
559
560         if(m_bone_position_sent == false){
561                 m_bone_position_sent = true;
562                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
563                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
564                         // create message and add to list
565                         ActiveObjectMessage aom(getId(), true, str);
566                         m_messages_out.push_back(aom);
567                 }
568         }
569
570         if(m_attachment_sent == false){
571                 m_attachment_sent = true;
572                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
573                 // create message and add to list
574                 ActiveObjectMessage aom(getId(), true, str);
575                 m_messages_out.push_back(aom);
576         }
577 }
578
579 std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
580 {
581         std::ostringstream os(std::ios::binary);
582
583         if(protocol_version >= 14)
584         {
585                 writeU8(os, 1); // version
586                 os<<serializeString(""); // name
587                 writeU8(os, 0); // is_player
588                 writeS16(os, getId()); //id
589                 writeV3F1000(os, m_base_position);
590                 writeF1000(os, m_yaw);
591                 writeS16(os, m_hp);
592
593                 writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
594                 os<<serializeLongString(getPropertyPacket()); // message 1
595                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
596                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
597                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
598                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
599                 }
600                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
601         }
602         else
603         {
604                 writeU8(os, 0); // version
605                 os<<serializeString(""); // name
606                 writeU8(os, 0); // is_player
607                 writeV3F1000(os, m_base_position);
608                 writeF1000(os, m_yaw);
609                 writeS16(os, m_hp);
610                 writeU8(os, 2); // number of messages stuffed in here
611                 os<<serializeLongString(getPropertyPacket()); // message 1
612                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
613         }
614
615         // return result
616         return os.str();
617 }
618
619 std::string LuaEntitySAO::getStaticData()
620 {
621         verbosestream<<__FUNCTION_NAME<<std::endl;
622         std::ostringstream os(std::ios::binary);
623         // version
624         writeU8(os, 1);
625         // name
626         os<<serializeString(m_init_name);
627         // state
628         if(m_registered){
629                 lua_State *L = m_env->getLua();
630                 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
631                 os<<serializeLongString(state);
632         } else {
633                 os<<serializeLongString(m_init_state);
634         }
635         // hp
636         writeS16(os, m_hp);
637         // velocity
638         writeV3F1000(os, m_velocity);
639         // yaw
640         writeF1000(os, m_yaw);
641         return os.str();
642 }
643
644 int LuaEntitySAO::punch(v3f dir,
645                 const ToolCapabilities *toolcap,
646                 ServerActiveObject *puncher,
647                 float time_from_last_punch)
648 {
649         if(!m_registered){
650                 // Delete unknown LuaEntities when punched
651                 m_removed = true;
652                 return 0;
653         }
654
655         // It's best that attachments cannot be punched 
656         if(isAttached())
657                 return 0;
658         
659         ItemStack *punchitem = NULL;
660         ItemStack punchitem_static;
661         if(puncher){
662                 punchitem_static = puncher->getWieldedItem();
663                 punchitem = &punchitem_static;
664         }
665
666         PunchDamageResult result = getPunchDamage(
667                         m_armor_groups,
668                         toolcap,
669                         punchitem,
670                         time_from_last_punch);
671         
672         if(result.did_punch)
673         {
674                 setHP(getHP() - result.damage);
675                 
676
677                 std::string punchername = "nil";
678
679                 if ( puncher != 0 )
680                         punchername = puncher->getDescription();
681
682                 actionstream<<getDescription()<<" punched by "
683                                 <<punchername<<", damage "<<result.damage
684                                 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
685                 
686                 {
687                         std::string str = gob_cmd_punched(result.damage, getHP());
688                         // create message and add to list
689                         ActiveObjectMessage aom(getId(), true, str);
690                         m_messages_out.push_back(aom);
691                 }
692
693                 if(getHP() == 0)
694                         m_removed = true;
695         }
696
697         lua_State *L = m_env->getLua();
698         scriptapi_luaentity_punch(L, m_id, puncher,
699                         time_from_last_punch, toolcap, dir);
700
701         return result.wear;
702 }
703
704 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
705 {
706         if(!m_registered)
707                 return;
708         // It's best that attachments cannot be clicked
709         if(isAttached())
710                 return;
711         lua_State *L = m_env->getLua();
712         scriptapi_luaentity_rightclick(L, m_id, clicker);
713 }
714
715 void LuaEntitySAO::setPos(v3f pos)
716 {
717         if(isAttached())
718                 return;
719         m_base_position = pos;
720         sendPosition(false, true);
721 }
722
723 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
724 {
725         if(isAttached())
726                 return;
727         m_base_position = pos;
728         if(!continuous)
729                 sendPosition(true, true);
730 }
731
732 float LuaEntitySAO::getMinimumSavedMovement()
733 {
734         return 0.1 * BS;
735 }
736
737 std::string LuaEntitySAO::getDescription()
738 {
739         std::ostringstream os(std::ios::binary);
740         os<<"LuaEntitySAO at (";
741         os<<(m_base_position.X/BS)<<",";
742         os<<(m_base_position.Y/BS)<<",";
743         os<<(m_base_position.Z/BS);
744         os<<")";
745         return os.str();
746 }
747
748 void LuaEntitySAO::setHP(s16 hp)
749 {
750         if(hp < 0) hp = 0;
751         m_hp = hp;
752 }
753
754 s16 LuaEntitySAO::getHP() const
755 {
756         return m_hp;
757 }
758
759 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
760 {
761         m_armor_groups = armor_groups;
762         m_armor_groups_sent = false;
763 }
764
765 void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
766 {
767         m_animation_range = frame_range;
768         m_animation_speed = frame_speed;
769         m_animation_blend = frame_blend;
770         m_animation_sent = false;
771 }
772
773 void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation)
774 {
775         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
776         m_bone_position_sent = false;
777 }
778
779 void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
780 {
781         // Attachments need to be handled on both the server and client.
782         // If we just attach on the server, we can only copy the position of the parent. Attachments
783         // are still sent to clients at an interval so players might see them lagging, plus we can't
784         // read and attach to skeletal bones.
785         // If we just attach on the client, the server still sees the child at its original location.
786         // This breaks some things so we also give the server the most accurate representation
787         // even if players only see the client changes.
788
789         m_attachment_parent_id = parent_id;
790         m_attachment_bone = bone;
791         m_attachment_position = position;
792         m_attachment_rotation = rotation;
793         m_attachment_sent = false;
794 }
795
796 ObjectProperties* LuaEntitySAO::accessObjectProperties()
797 {
798         return &m_prop;
799 }
800
801 void LuaEntitySAO::notifyObjectPropertiesModified()
802 {
803         m_properties_sent = false;
804 }
805
806 void LuaEntitySAO::setVelocity(v3f velocity)
807 {
808         m_velocity = velocity;
809 }
810
811 v3f LuaEntitySAO::getVelocity()
812 {
813         return m_velocity;
814 }
815
816 void LuaEntitySAO::setAcceleration(v3f acceleration)
817 {
818         m_acceleration = acceleration;
819 }
820
821 v3f LuaEntitySAO::getAcceleration()
822 {
823         return m_acceleration;
824 }
825
826 void LuaEntitySAO::setYaw(float yaw)
827 {
828         m_yaw = yaw;
829 }
830
831 float LuaEntitySAO::getYaw()
832 {
833         return m_yaw;
834 }
835
836 void LuaEntitySAO::setTextureMod(const std::string &mod)
837 {
838         std::string str = gob_cmd_set_texture_mod(mod);
839         // create message and add to list
840         ActiveObjectMessage aom(getId(), true, str);
841         m_messages_out.push_back(aom);
842 }
843
844 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
845                 bool select_horiz_by_yawpitch)
846 {
847         std::string str = gob_cmd_set_sprite(
848                 p,
849                 num_frames,
850                 framelength,
851                 select_horiz_by_yawpitch
852         );
853         // create message and add to list
854         ActiveObjectMessage aom(getId(), true, str);
855         m_messages_out.push_back(aom);
856 }
857
858 std::string LuaEntitySAO::getName()
859 {
860         return m_init_name;
861 }
862
863 std::string LuaEntitySAO::getPropertyPacket()
864 {
865         return gob_cmd_set_properties(m_prop);
866 }
867
868 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
869 {
870         // If the object is attached client-side, don't waste bandwidth sending its position to clients
871         if(isAttached())
872                 return;
873         
874         m_last_sent_move_precision = m_base_position.getDistanceFrom(
875                         m_last_sent_position);
876         m_last_sent_position_timer = 0;
877         m_last_sent_yaw = m_yaw;
878         m_last_sent_position = m_base_position;
879         m_last_sent_velocity = m_velocity;
880         //m_last_sent_acceleration = m_acceleration;
881
882         float update_interval = m_env->getSendRecommendedInterval();
883
884         std::string str = gob_cmd_update_position(
885                 m_base_position,
886                 m_velocity,
887                 m_acceleration,
888                 m_yaw,
889                 do_interpolate,
890                 is_movement_end,
891                 update_interval
892         );
893         // create message and add to list
894         ActiveObjectMessage aom(getId(), false, str);
895         m_messages_out.push_back(aom);
896 }
897
898 bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
899         if (m_prop.physical)
900         {
901                 //update collision box
902                 toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
903                 toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
904
905                 toset->MinEdge += m_base_position;
906                 toset->MaxEdge += m_base_position;
907
908                 return true;
909         }
910
911         return false;
912 }
913
914 /*
915         PlayerSAO
916 */
917
918 // No prototype, PlayerSAO does not need to be deserialized
919
920 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
921                 const std::set<std::string> &privs, bool is_singleplayer):
922         ServerActiveObject(env_, v3f(0,0,0)),
923         m_player(player_),
924         m_peer_id(peer_id_),
925         m_inventory(NULL),
926         m_last_good_position(0,0,0),
927         m_last_good_position_age(0),
928         m_time_from_last_punch(0),
929         m_nocheat_dig_pos(32767, 32767, 32767),
930         m_nocheat_dig_time(0),
931         m_wield_index(0),
932         m_position_not_sent(false),
933         m_armor_groups_sent(false),
934         m_properties_sent(true),
935         m_privs(privs),
936         m_is_singleplayer(is_singleplayer),
937         m_animation_sent(false),
938         m_bone_position_sent(false),
939         m_attachment_sent(false),
940         // public
941         m_moved(false),
942         m_inventory_not_sent(false),
943         m_hp_not_sent(false),
944         m_wielded_item_not_sent(false),
945         m_physics_override_speed(1),
946         m_physics_override_jump(1),
947         m_physics_override_gravity(1),
948         m_physics_override_sent(false)
949 {
950         assert(m_player);
951         assert(m_peer_id != 0);
952         setBasePosition(m_player->getPosition());
953         m_inventory = &m_player->inventory;
954         m_armor_groups["fleshy"] = 100;
955
956         m_prop.hp_max = PLAYER_MAX_HP;
957         m_prop.physical = false;
958         m_prop.weight = 75;
959         m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
960         // start of default appearance, this should be overwritten by LUA
961         m_prop.visual = "upright_sprite";
962         m_prop.visual_size = v2f(1, 2);
963         m_prop.textures.clear();
964         m_prop.textures.push_back("player.png");
965         m_prop.textures.push_back("player_back.png");
966         m_prop.colors.clear();
967         m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
968         m_prop.spritediv = v2s16(1,1);
969         // end of default appearance
970         m_prop.is_visible = true;
971         m_prop.makes_footstep_sound = true;
972 }
973
974 PlayerSAO::~PlayerSAO()
975 {
976         if(m_inventory != &m_player->inventory)
977                 delete m_inventory;
978
979 }
980
981 std::string PlayerSAO::getDescription()
982 {
983         return std::string("player ") + m_player->getName();
984 }
985
986 // Called after id has been set and has been inserted in environment
987 void PlayerSAO::addedToEnvironment(u32 dtime_s)
988 {
989         ServerActiveObject::addedToEnvironment(dtime_s);
990         ServerActiveObject::setBasePosition(m_player->getPosition());
991         m_player->setPlayerSAO(this);
992         m_player->peer_id = m_peer_id;
993         m_last_good_position = m_player->getPosition();
994         m_last_good_position_age = 0.0;
995 }
996
997 // Called before removing from environment
998 void PlayerSAO::removingFromEnvironment()
999 {
1000         ServerActiveObject::removingFromEnvironment();
1001         if(m_player->getPlayerSAO() == this)
1002         {
1003                 m_player->setPlayerSAO(NULL);
1004                 m_player->peer_id = 0;
1005         }
1006 }
1007
1008 bool PlayerSAO::isStaticAllowed() const
1009 {
1010         return false;
1011 }
1012
1013 bool PlayerSAO::unlimitedTransferDistance() const
1014 {
1015         return g_settings->getBool("unlimited_player_transfer_distance");
1016 }
1017
1018 std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
1019 {
1020         std::ostringstream os(std::ios::binary);
1021
1022         if(protocol_version >= 15)
1023         {
1024                 writeU8(os, 1); // version
1025                 os<<serializeString(m_player->getName()); // name
1026                 writeU8(os, 1); // is_player
1027                 writeS16(os, getId()); //id
1028                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1029                 writeF1000(os, m_player->getYaw());
1030                 writeS16(os, getHP());
1031
1032                 writeU8(os, 5 + m_bone_position.size()); // number of messages stuffed in here
1033                 os<<serializeLongString(getPropertyPacket()); // message 1
1034                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1035                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
1036                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1037                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
1038                 }
1039                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
1040                 os<<serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity)); // 5
1041         }
1042         else
1043         {
1044                 writeU8(os, 0); // version
1045                 os<<serializeString(m_player->getName()); // name
1046                 writeU8(os, 1); // is_player
1047                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1048                 writeF1000(os, m_player->getYaw());
1049                 writeS16(os, getHP());
1050                 writeU8(os, 2); // number of messages stuffed in here
1051                 os<<serializeLongString(getPropertyPacket()); // message 1
1052                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1053         }
1054
1055         // return result
1056         return os.str();
1057 }
1058
1059 std::string PlayerSAO::getStaticData()
1060 {
1061         assert(0);
1062         return "";
1063 }
1064
1065 bool PlayerSAO::isAttached()
1066 {
1067         if(!m_attachment_parent_id)
1068                 return false;
1069         // Check if the parent still exists
1070         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
1071         if(obj)
1072                 return true;
1073         return false;
1074 }
1075
1076 void PlayerSAO::step(float dtime, bool send_recommended)
1077 {
1078         if(!m_properties_sent)
1079         {
1080                 m_properties_sent = true;
1081                 std::string str = getPropertyPacket();
1082                 // create message and add to list
1083                 ActiveObjectMessage aom(getId(), true, str);
1084                 m_messages_out.push_back(aom);
1085         }
1086
1087         // If attached, check that our parent is still there. If it isn't, detach.
1088         if(m_attachment_parent_id && !isAttached())
1089         {
1090                 m_attachment_parent_id = 0;
1091                 m_attachment_bone = "";
1092                 m_attachment_position = v3f(0,0,0);
1093                 m_attachment_rotation = v3f(0,0,0);
1094                 m_player->setPosition(m_last_good_position);
1095                 m_moved = true;
1096         }
1097
1098         m_time_from_last_punch += dtime;
1099         m_nocheat_dig_time += dtime;
1100
1101         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
1102         // If the object gets detached this comes into effect automatically from the last known origin
1103         if(isAttached())
1104         {
1105                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1106                 m_last_good_position = pos;
1107                 m_last_good_position_age = 0;
1108                 m_player->setPosition(pos);
1109         }
1110         else
1111         {
1112                 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
1113                 {
1114                         m_last_good_position = m_player->getPosition();
1115                         m_last_good_position_age = 0;
1116                 }
1117                 else
1118                 {
1119                         /*
1120                                 Check player movements
1121
1122                                 NOTE: Actually the server should handle player physics like the
1123                                 client does and compare player's position to what is calculated
1124                                 on our side. This is required when eg. players fly due to an
1125                                 explosion. Altough a node-based alternative might be possible
1126                                 too, and much more lightweight.
1127                         */
1128
1129                         float player_max_speed = 0;
1130                         float player_max_speed_up = 0;
1131                         if(m_privs.count("fast") != 0){
1132                                 // Fast speed
1133                                 player_max_speed = BS * 20;
1134                                 player_max_speed_up = BS * 20;
1135                         } else {
1136                                 // Normal speed
1137                                 player_max_speed = BS * 4.0;
1138                                 player_max_speed_up = BS * 4.0;
1139                         }
1140                         // Tolerance
1141                         player_max_speed *= 2.5;
1142                         player_max_speed_up *= 2.5;
1143
1144                         m_last_good_position_age += dtime;
1145                         if(m_last_good_position_age >= 1.0){
1146                                 float age = m_last_good_position_age;
1147                                 v3f diff = (m_player->getPosition() - m_last_good_position);
1148                                 float d_vert = diff.Y;
1149                                 diff.Y = 0;
1150                                 float d_horiz = diff.getLength();
1151                                 /*infostream<<m_player->getName()<<"'s horizontal speed is "
1152                                                 <<(d_horiz/age)<<std::endl;*/
1153                                 if(d_horiz <= age * player_max_speed &&
1154                                                 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1155                                         m_last_good_position = m_player->getPosition();
1156                                 } else {
1157                                         actionstream<<"Player "<<m_player->getName()
1158                                                         <<" moved too fast; resetting position"
1159                                                         <<std::endl;
1160                                         m_player->setPosition(m_last_good_position);
1161                                         m_moved = true;
1162                                 }
1163                                 m_last_good_position_age = 0;
1164                         }
1165                 }
1166         }
1167
1168         if(send_recommended == false)
1169                 return;
1170
1171         // If the object is attached client-side, don't waste bandwidth sending its position to clients
1172         if(m_position_not_sent && !isAttached())
1173         {
1174                 m_position_not_sent = false;
1175                 float update_interval = m_env->getSendRecommendedInterval();
1176                 v3f pos;
1177                 if(isAttached()) // Just in case we ever do send attachment position too
1178                         pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1179                 else
1180                         pos = m_player->getPosition() + v3f(0,BS*1,0);
1181                 std::string str = gob_cmd_update_position(
1182                         pos,
1183                         v3f(0,0,0),
1184                         v3f(0,0,0),
1185                         m_player->getYaw(),
1186                         true,
1187                         false,
1188                         update_interval
1189                 );
1190                 // create message and add to list
1191                 ActiveObjectMessage aom(getId(), false, str);
1192                 m_messages_out.push_back(aom);
1193         }
1194
1195         if(m_wielded_item_not_sent)
1196         {
1197                 m_wielded_item_not_sent = false;
1198                 // GenericCAO has no special way to show this
1199         }
1200
1201         if(m_armor_groups_sent == false){
1202                 m_armor_groups_sent = true;
1203                 std::string str = gob_cmd_update_armor_groups(
1204                                 m_armor_groups);
1205                 // create message and add to list
1206                 ActiveObjectMessage aom(getId(), true, str);
1207                 m_messages_out.push_back(aom);
1208         }
1209
1210         if(m_physics_override_sent == false){
1211                 m_physics_override_sent = true;
1212                 std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity);
1213                 // create message and add to list
1214                 ActiveObjectMessage aom(getId(), true, str);
1215                 m_messages_out.push_back(aom);
1216         }
1217
1218         if(m_animation_sent == false){
1219                 m_animation_sent = true;
1220                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
1221                 // create message and add to list
1222                 ActiveObjectMessage aom(getId(), true, str);
1223                 m_messages_out.push_back(aom);
1224         }
1225
1226         if(m_bone_position_sent == false){
1227                 m_bone_position_sent = true;
1228                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1229                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
1230                         // create message and add to list
1231                         ActiveObjectMessage aom(getId(), true, str);
1232                         m_messages_out.push_back(aom);
1233                 }
1234         }
1235
1236         if(m_attachment_sent == false){
1237                 m_attachment_sent = true;
1238                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
1239                 // create message and add to list
1240                 ActiveObjectMessage aom(getId(), true, str);
1241                 m_messages_out.push_back(aom);
1242         }
1243 }
1244
1245 void PlayerSAO::setBasePosition(const v3f &position)
1246 {
1247         // This needs to be ran for attachments too
1248         ServerActiveObject::setBasePosition(position);
1249         m_position_not_sent = true;
1250 }
1251
1252 void PlayerSAO::setPos(v3f pos)
1253 {
1254         if(isAttached())
1255                 return;
1256         m_player->setPosition(pos);
1257         // Movement caused by this command is always valid
1258         m_last_good_position = pos;
1259         m_last_good_position_age = 0;
1260         // Force position change on client
1261         m_moved = true;
1262 }
1263
1264 void PlayerSAO::moveTo(v3f pos, bool continuous)
1265 {
1266         if(isAttached())
1267                 return;
1268         m_player->setPosition(pos);
1269         // Movement caused by this command is always valid
1270         m_last_good_position = pos;
1271         m_last_good_position_age = 0;
1272         // Force position change on client
1273         m_moved = true;
1274 }
1275
1276 void PlayerSAO::setYaw(float yaw)
1277 {
1278         m_player->setYaw(yaw);
1279         // Force change on client
1280         m_moved = true;
1281 }
1282
1283 void PlayerSAO::setPitch(float pitch)
1284 {
1285         m_player->setPitch(pitch);
1286         // Force change on client
1287         m_moved = true;
1288 }
1289
1290 int PlayerSAO::punch(v3f dir,
1291         const ToolCapabilities *toolcap,
1292         ServerActiveObject *puncher,
1293         float time_from_last_punch)
1294 {
1295         // It's best that attachments cannot be punched 
1296         if(isAttached())
1297                 return 0;
1298
1299         if(!toolcap)
1300                 return 0;
1301
1302         // No effect if PvP disabled
1303         if(g_settings->getBool("enable_pvp") == false){
1304                 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1305                         std::string str = gob_cmd_punched(0, getHP());
1306                         // create message and add to list
1307                         ActiveObjectMessage aom(getId(), true, str);
1308                         m_messages_out.push_back(aom);
1309                         return 0;
1310                 }
1311         }
1312
1313         HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1314                         time_from_last_punch);
1315
1316         std::string punchername = "nil";
1317
1318         if ( puncher != 0 )
1319                 punchername = puncher->getDescription();
1320
1321         actionstream<<"Player "<<m_player->getName()<<" punched by "
1322                         <<punchername<<", damage "<<hitparams.hp
1323                         <<" HP"<<std::endl;
1324
1325         setHP(getHP() - hitparams.hp);
1326
1327         if(hitparams.hp != 0)
1328         {
1329                 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1330                 // create message and add to list
1331                 ActiveObjectMessage aom(getId(), true, str);
1332                 m_messages_out.push_back(aom);
1333         }
1334
1335         return hitparams.wear;
1336 }
1337
1338 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1339 {
1340 }
1341
1342 s16 PlayerSAO::getHP() const
1343 {
1344         return m_player->hp;
1345 }
1346
1347 void PlayerSAO::setHP(s16 hp)
1348 {
1349         s16 oldhp = m_player->hp;
1350
1351         if(hp < 0)
1352                 hp = 0;
1353         else if(hp > PLAYER_MAX_HP)
1354                 hp = PLAYER_MAX_HP;
1355
1356         if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1357         {
1358                 m_hp_not_sent = true; // fix wrong prediction on client
1359                 return;
1360         }
1361
1362         m_player->hp = hp;
1363
1364         if(hp != oldhp)
1365                 m_hp_not_sent = true;
1366
1367         // On death or reincarnation send an active object message
1368         if((hp == 0) != (oldhp == 0))
1369         {
1370                 // Will send new is_visible value based on (getHP()!=0)
1371                 m_properties_sent = false;
1372                 // Send new HP
1373                 std::string str = gob_cmd_punched(0, getHP());
1374                 ActiveObjectMessage aom(getId(), true, str);
1375                 m_messages_out.push_back(aom);
1376         }
1377 }
1378
1379 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1380 {
1381         m_armor_groups = armor_groups;
1382         m_armor_groups_sent = false;
1383 }
1384
1385 void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
1386 {
1387         // store these so they can be updated to clients
1388         m_animation_range = frame_range;
1389         m_animation_speed = frame_speed;
1390         m_animation_blend = frame_blend;
1391         m_animation_sent = false;
1392 }
1393
1394 void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
1395 {
1396         // store these so they can be updated to clients
1397         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1398         m_bone_position_sent = false;
1399 }
1400
1401 void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
1402 {
1403         // Attachments need to be handled on both the server and client.
1404         // If we just attach on the server, we can only copy the position of the parent. Attachments
1405         // are still sent to clients at an interval so players might see them lagging, plus we can't
1406         // read and attach to skeletal bones.
1407         // If we just attach on the client, the server still sees the child at its original location.
1408         // This breaks some things so we also give the server the most accurate representation
1409         // even if players only see the client changes.
1410
1411         m_attachment_parent_id = parent_id;
1412         m_attachment_bone = bone;
1413         m_attachment_position = position;
1414         m_attachment_rotation = rotation;
1415         m_attachment_sent = false;
1416 }
1417
1418 ObjectProperties* PlayerSAO::accessObjectProperties()
1419 {
1420         return &m_prop;
1421 }
1422
1423 void PlayerSAO::notifyObjectPropertiesModified()
1424 {
1425         m_properties_sent = false;
1426 }
1427
1428 Inventory* PlayerSAO::getInventory()
1429 {
1430         return m_inventory;
1431 }
1432 const Inventory* PlayerSAO::getInventory() const
1433 {
1434         return m_inventory;
1435 }
1436
1437 InventoryLocation PlayerSAO::getInventoryLocation() const
1438 {
1439         InventoryLocation loc;
1440         loc.setPlayer(m_player->getName());
1441         return loc;
1442 }
1443
1444 void PlayerSAO::setInventoryModified()
1445 {
1446         m_inventory_not_sent = true;
1447 }
1448
1449 std::string PlayerSAO::getWieldList() const
1450 {
1451         return "main";
1452 }
1453
1454 int PlayerSAO::getWieldIndex() const
1455 {
1456         return m_wield_index;
1457 }
1458
1459 void PlayerSAO::setWieldIndex(int i)
1460 {
1461         if(i != m_wield_index)
1462         {
1463                 m_wield_index = i;
1464                 m_wielded_item_not_sent = true;
1465         }
1466 }
1467
1468 void PlayerSAO::disconnected()
1469 {
1470         m_peer_id = 0;
1471         m_removed = true;
1472         if(m_player->getPlayerSAO() == this)
1473         {
1474                 m_player->setPlayerSAO(NULL);
1475                 m_player->peer_id = 0;
1476         }
1477 }
1478
1479 std::string PlayerSAO::getPropertyPacket()
1480 {
1481         m_prop.is_visible = (true);
1482         return gob_cmd_set_properties(m_prop);
1483 }
1484
1485 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1486         //update collision box
1487         *toset = m_player->getCollisionbox();
1488
1489         toset->MinEdge += m_base_position;
1490         toset->MaxEdge += m_base_position;
1491
1492         return true;
1493 }