]> git.lizzy.rs Git - minetest.git/blob - src/content_sao.cpp
Remove useless recalculation of bounding box (mapblock_mesh)
[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 "cpp_api/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                 ENV_TO_SA(m_env)->luaentity_Remove(m_id);
391         }
392 }
393
394 void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
395 {
396         ServerActiveObject::addedToEnvironment(dtime_s);
397         
398         // Create entity from name
399         m_registered = ENV_TO_SA(m_env)->luaentity_Add(m_id, m_init_name.c_str());
400         
401         if(m_registered){
402                 // Get properties
403                 ENV_TO_SA(m_env)->luaentity_GetProperties(m_id, &m_prop);
404                 // Initialize HP from properties
405                 m_hp = m_prop.hp_max;
406                 // Activate entity, supplying serialized state
407                 ENV_TO_SA(m_env)->luaentity_Activate(m_id, m_init_state.c_str(), dtime_s);
408         }
409 }
410
411 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
412                 const std::string &data)
413 {
414         std::string name;
415         std::string state;
416         s16 hp = 1;
417         v3f velocity;
418         float yaw = 0;
419         if(data != ""){
420                 std::istringstream is(data, std::ios::binary);
421                 // read version
422                 u8 version = readU8(is);
423                 // check if version is supported
424                 if(version == 0){
425                         name = deSerializeString(is);
426                         state = deSerializeLongString(is);
427                 }
428                 else if(version == 1){
429                         name = deSerializeString(is);
430                         state = deSerializeLongString(is);
431                         hp = readS16(is);
432                         velocity = readV3F1000(is);
433                         yaw = readF1000(is);
434                 }
435         }
436         // create object
437         infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
438                         <<state<<"\")"<<std::endl;
439         LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
440         sao->m_hp = hp;
441         sao->m_velocity = velocity;
442         sao->m_yaw = yaw;
443         return sao;
444 }
445
446 bool LuaEntitySAO::isAttached()
447 {
448         if(!m_attachment_parent_id)
449                 return false;
450         // Check if the parent still exists
451         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
452         if(obj)
453                 return true;
454         return false;
455 }
456
457 void LuaEntitySAO::step(float dtime, bool send_recommended)
458 {
459         if(!m_properties_sent)
460         {
461                 m_properties_sent = true;
462                 std::string str = getPropertyPacket();
463                 // create message and add to list
464                 ActiveObjectMessage aom(getId(), true, str);
465                 m_messages_out.push_back(aom);
466         }
467
468         // If attached, check that our parent is still there. If it isn't, detach.
469         if(m_attachment_parent_id && !isAttached())
470         {
471                 m_attachment_parent_id = 0;
472                 m_attachment_bone = "";
473                 m_attachment_position = v3f(0,0,0);
474                 m_attachment_rotation = v3f(0,0,0);
475                 sendPosition(false, true);
476         }
477
478         m_last_sent_position_timer += dtime;
479
480         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
481         // If the object gets detached this comes into effect automatically from the last known origin
482         if(isAttached())
483         {
484                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
485                 m_base_position = pos;
486                 m_velocity = v3f(0,0,0);
487                 m_acceleration = v3f(0,0,0);
488         }
489         else
490         {
491                 if(m_prop.physical){
492                         core::aabbox3d<f32> box = m_prop.collisionbox;
493                         box.MinEdge *= BS;
494                         box.MaxEdge *= BS;
495                         collisionMoveResult moveresult;
496                         f32 pos_max_d = BS*0.25; // Distance per iteration
497                         f32 stepheight = 0; // Maximum climbable step height
498                         v3f p_pos = m_base_position;
499                         v3f p_velocity = m_velocity;
500                         v3f p_acceleration = m_acceleration;
501                         moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
502                                         pos_max_d, box, stepheight, dtime,
503                                         p_pos, p_velocity, p_acceleration,this);
504                         // Apply results
505                         m_base_position = p_pos;
506                         m_velocity = p_velocity;
507                         m_acceleration = p_acceleration;
508                 } else {
509                         m_base_position += dtime * m_velocity + 0.5 * dtime
510                                         * dtime * m_acceleration;
511                         m_velocity += dtime * m_acceleration;
512                 }
513         }
514
515         if(m_registered){
516                 ENV_TO_SA(m_env)->luaentity_Step(m_id, dtime);
517         }
518
519         if(send_recommended == false)
520                 return;
521
522         if(!isAttached())
523         {
524                 // TODO: force send when acceleration changes enough?
525                 float minchange = 0.2*BS;
526                 if(m_last_sent_position_timer > 1.0){
527                         minchange = 0.01*BS;
528                 } else if(m_last_sent_position_timer > 0.2){
529                         minchange = 0.05*BS;
530                 }
531                 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
532                 move_d += m_last_sent_move_precision;
533                 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
534                 if(move_d > minchange || vel_d > minchange ||
535                                 fabs(m_yaw - m_last_sent_yaw) > 1.0){
536                         sendPosition(true, false);
537                 }
538         }
539
540         if(m_armor_groups_sent == false){
541                 m_armor_groups_sent = true;
542                 std::string str = gob_cmd_update_armor_groups(
543                                 m_armor_groups);
544                 // create message and add to list
545                 ActiveObjectMessage aom(getId(), true, str);
546                 m_messages_out.push_back(aom);
547         }
548
549         if(m_animation_sent == false){
550                 m_animation_sent = true;
551                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
552                 // create message and add to list
553                 ActiveObjectMessage aom(getId(), true, str);
554                 m_messages_out.push_back(aom);
555         }
556
557         if(m_bone_position_sent == false){
558                 m_bone_position_sent = true;
559                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
560                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
561                         // create message and add to list
562                         ActiveObjectMessage aom(getId(), true, str);
563                         m_messages_out.push_back(aom);
564                 }
565         }
566
567         if(m_attachment_sent == false){
568                 m_attachment_sent = true;
569                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
570                 // create message and add to list
571                 ActiveObjectMessage aom(getId(), true, str);
572                 m_messages_out.push_back(aom);
573         }
574 }
575
576 std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
577 {
578         std::ostringstream os(std::ios::binary);
579
580         if(protocol_version >= 14)
581         {
582                 writeU8(os, 1); // version
583                 os<<serializeString(""); // name
584                 writeU8(os, 0); // is_player
585                 writeS16(os, getId()); //id
586                 writeV3F1000(os, m_base_position);
587                 writeF1000(os, m_yaw);
588                 writeS16(os, m_hp);
589
590                 writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
591                 os<<serializeLongString(getPropertyPacket()); // message 1
592                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
593                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
594                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
595                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
596                 }
597                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
598         }
599         else
600         {
601                 writeU8(os, 0); // version
602                 os<<serializeString(""); // name
603                 writeU8(os, 0); // is_player
604                 writeV3F1000(os, m_base_position);
605                 writeF1000(os, m_yaw);
606                 writeS16(os, m_hp);
607                 writeU8(os, 2); // number of messages stuffed in here
608                 os<<serializeLongString(getPropertyPacket()); // message 1
609                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
610         }
611
612         // return result
613         return os.str();
614 }
615
616 std::string LuaEntitySAO::getStaticData()
617 {
618         verbosestream<<__FUNCTION_NAME<<std::endl;
619         std::ostringstream os(std::ios::binary);
620         // version
621         writeU8(os, 1);
622         // name
623         os<<serializeString(m_init_name);
624         // state
625         if(m_registered){
626                 std::string state = ENV_TO_SA(m_env)->luaentity_GetStaticdata(m_id);
627                 os<<serializeLongString(state);
628         } else {
629                 os<<serializeLongString(m_init_state);
630         }
631         // hp
632         writeS16(os, m_hp);
633         // velocity
634         writeV3F1000(os, m_velocity);
635         // yaw
636         writeF1000(os, m_yaw);
637         return os.str();
638 }
639
640 int LuaEntitySAO::punch(v3f dir,
641                 const ToolCapabilities *toolcap,
642                 ServerActiveObject *puncher,
643                 float time_from_last_punch)
644 {
645         if(!m_registered){
646                 // Delete unknown LuaEntities when punched
647                 m_removed = true;
648                 return 0;
649         }
650
651         // It's best that attachments cannot be punched 
652         if(isAttached())
653                 return 0;
654         
655         ItemStack *punchitem = NULL;
656         ItemStack punchitem_static;
657         if(puncher){
658                 punchitem_static = puncher->getWieldedItem();
659                 punchitem = &punchitem_static;
660         }
661
662         PunchDamageResult result = getPunchDamage(
663                         m_armor_groups,
664                         toolcap,
665                         punchitem,
666                         time_from_last_punch);
667         
668         if(result.did_punch)
669         {
670                 setHP(getHP() - result.damage);
671                 
672
673                 std::string punchername = "nil";
674
675                 if ( puncher != 0 )
676                         punchername = puncher->getDescription();
677
678                 actionstream<<getDescription()<<" punched by "
679                                 <<punchername<<", damage "<<result.damage
680                                 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
681                 
682                 {
683                         std::string str = gob_cmd_punched(result.damage, getHP());
684                         // create message and add to list
685                         ActiveObjectMessage aom(getId(), true, str);
686                         m_messages_out.push_back(aom);
687                 }
688
689                 if(getHP() == 0)
690                         m_removed = true;
691         }
692
693         ENV_TO_SA(m_env)->luaentity_Punch(m_id, puncher,
694                         time_from_last_punch, toolcap, dir);
695
696         return result.wear;
697 }
698
699 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
700 {
701         if(!m_registered)
702                 return;
703         // It's best that attachments cannot be clicked
704         if(isAttached())
705                 return;
706         ENV_TO_SA(m_env)->luaentity_Rightclick(m_id, clicker);
707 }
708
709 void LuaEntitySAO::setPos(v3f pos)
710 {
711         if(isAttached())
712                 return;
713         m_base_position = pos;
714         sendPosition(false, true);
715 }
716
717 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
718 {
719         if(isAttached())
720                 return;
721         m_base_position = pos;
722         if(!continuous)
723                 sendPosition(true, true);
724 }
725
726 float LuaEntitySAO::getMinimumSavedMovement()
727 {
728         return 0.1 * BS;
729 }
730
731 std::string LuaEntitySAO::getDescription()
732 {
733         std::ostringstream os(std::ios::binary);
734         os<<"LuaEntitySAO at (";
735         os<<(m_base_position.X/BS)<<",";
736         os<<(m_base_position.Y/BS)<<",";
737         os<<(m_base_position.Z/BS);
738         os<<")";
739         return os.str();
740 }
741
742 void LuaEntitySAO::setHP(s16 hp)
743 {
744         if(hp < 0) hp = 0;
745         m_hp = hp;
746 }
747
748 s16 LuaEntitySAO::getHP() const
749 {
750         return m_hp;
751 }
752
753 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
754 {
755         m_armor_groups = armor_groups;
756         m_armor_groups_sent = false;
757 }
758
759 void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
760 {
761         m_animation_range = frame_range;
762         m_animation_speed = frame_speed;
763         m_animation_blend = frame_blend;
764         m_animation_sent = false;
765 }
766
767 void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation)
768 {
769         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
770         m_bone_position_sent = false;
771 }
772
773 void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
774 {
775         // Attachments need to be handled on both the server and client.
776         // If we just attach on the server, we can only copy the position of the parent. Attachments
777         // are still sent to clients at an interval so players might see them lagging, plus we can't
778         // read and attach to skeletal bones.
779         // If we just attach on the client, the server still sees the child at its original location.
780         // This breaks some things so we also give the server the most accurate representation
781         // even if players only see the client changes.
782
783         m_attachment_parent_id = parent_id;
784         m_attachment_bone = bone;
785         m_attachment_position = position;
786         m_attachment_rotation = rotation;
787         m_attachment_sent = false;
788 }
789
790 ObjectProperties* LuaEntitySAO::accessObjectProperties()
791 {
792         return &m_prop;
793 }
794
795 void LuaEntitySAO::notifyObjectPropertiesModified()
796 {
797         m_properties_sent = false;
798 }
799
800 void LuaEntitySAO::setVelocity(v3f velocity)
801 {
802         m_velocity = velocity;
803 }
804
805 v3f LuaEntitySAO::getVelocity()
806 {
807         return m_velocity;
808 }
809
810 void LuaEntitySAO::setAcceleration(v3f acceleration)
811 {
812         m_acceleration = acceleration;
813 }
814
815 v3f LuaEntitySAO::getAcceleration()
816 {
817         return m_acceleration;
818 }
819
820 void LuaEntitySAO::setYaw(float yaw)
821 {
822         m_yaw = yaw;
823 }
824
825 float LuaEntitySAO::getYaw()
826 {
827         return m_yaw;
828 }
829
830 void LuaEntitySAO::setTextureMod(const std::string &mod)
831 {
832         std::string str = gob_cmd_set_texture_mod(mod);
833         // create message and add to list
834         ActiveObjectMessage aom(getId(), true, str);
835         m_messages_out.push_back(aom);
836 }
837
838 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
839                 bool select_horiz_by_yawpitch)
840 {
841         std::string str = gob_cmd_set_sprite(
842                 p,
843                 num_frames,
844                 framelength,
845                 select_horiz_by_yawpitch
846         );
847         // create message and add to list
848         ActiveObjectMessage aom(getId(), true, str);
849         m_messages_out.push_back(aom);
850 }
851
852 std::string LuaEntitySAO::getName()
853 {
854         return m_init_name;
855 }
856
857 std::string LuaEntitySAO::getPropertyPacket()
858 {
859         return gob_cmd_set_properties(m_prop);
860 }
861
862 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
863 {
864         // If the object is attached client-side, don't waste bandwidth sending its position to clients
865         if(isAttached())
866                 return;
867         
868         m_last_sent_move_precision = m_base_position.getDistanceFrom(
869                         m_last_sent_position);
870         m_last_sent_position_timer = 0;
871         m_last_sent_yaw = m_yaw;
872         m_last_sent_position = m_base_position;
873         m_last_sent_velocity = m_velocity;
874         //m_last_sent_acceleration = m_acceleration;
875
876         float update_interval = m_env->getSendRecommendedInterval();
877
878         std::string str = gob_cmd_update_position(
879                 m_base_position,
880                 m_velocity,
881                 m_acceleration,
882                 m_yaw,
883                 do_interpolate,
884                 is_movement_end,
885                 update_interval
886         );
887         // create message and add to list
888         ActiveObjectMessage aom(getId(), false, str);
889         m_messages_out.push_back(aom);
890 }
891
892 bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
893         if (m_prop.physical)
894         {
895                 //update collision box
896                 toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
897                 toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
898
899                 toset->MinEdge += m_base_position;
900                 toset->MaxEdge += m_base_position;
901
902                 return true;
903         }
904
905         return false;
906 }
907
908 /*
909         PlayerSAO
910 */
911
912 // No prototype, PlayerSAO does not need to be deserialized
913
914 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
915                 const std::set<std::string> &privs, bool is_singleplayer):
916         ServerActiveObject(env_, v3f(0,0,0)),
917         m_player(player_),
918         m_peer_id(peer_id_),
919         m_inventory(NULL),
920         m_last_good_position(0,0,0),
921         m_last_good_position_age(0),
922         m_time_from_last_punch(0),
923         m_nocheat_dig_pos(32767, 32767, 32767),
924         m_nocheat_dig_time(0),
925         m_wield_index(0),
926         m_position_not_sent(false),
927         m_armor_groups_sent(false),
928         m_properties_sent(true),
929         m_privs(privs),
930         m_is_singleplayer(is_singleplayer),
931         m_animation_sent(false),
932         m_bone_position_sent(false),
933         m_attachment_sent(false),
934         // public
935         m_moved(false),
936         m_inventory_not_sent(false),
937         m_hp_not_sent(false),
938         m_wielded_item_not_sent(false),
939         m_physics_override_speed(1),
940         m_physics_override_jump(1),
941         m_physics_override_gravity(1),
942         m_physics_override_sent(false)
943 {
944         assert(m_player);
945         assert(m_peer_id != 0);
946         setBasePosition(m_player->getPosition());
947         m_inventory = &m_player->inventory;
948         m_armor_groups["fleshy"] = 100;
949
950         m_prop.hp_max = PLAYER_MAX_HP;
951         m_prop.physical = false;
952         m_prop.weight = 75;
953         m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
954         // start of default appearance, this should be overwritten by LUA
955         m_prop.visual = "upright_sprite";
956         m_prop.visual_size = v2f(1, 2);
957         m_prop.textures.clear();
958         m_prop.textures.push_back("player.png");
959         m_prop.textures.push_back("player_back.png");
960         m_prop.colors.clear();
961         m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
962         m_prop.spritediv = v2s16(1,1);
963         // end of default appearance
964         m_prop.is_visible = true;
965         m_prop.makes_footstep_sound = true;
966 }
967
968 PlayerSAO::~PlayerSAO()
969 {
970         if(m_inventory != &m_player->inventory)
971                 delete m_inventory;
972
973 }
974
975 std::string PlayerSAO::getDescription()
976 {
977         return std::string("player ") + m_player->getName();
978 }
979
980 // Called after id has been set and has been inserted in environment
981 void PlayerSAO::addedToEnvironment(u32 dtime_s)
982 {
983         ServerActiveObject::addedToEnvironment(dtime_s);
984         ServerActiveObject::setBasePosition(m_player->getPosition());
985         m_player->setPlayerSAO(this);
986         m_player->peer_id = m_peer_id;
987         m_last_good_position = m_player->getPosition();
988         m_last_good_position_age = 0.0;
989 }
990
991 // Called before removing from environment
992 void PlayerSAO::removingFromEnvironment()
993 {
994         ServerActiveObject::removingFromEnvironment();
995         if(m_player->getPlayerSAO() == this)
996         {
997                 m_player->setPlayerSAO(NULL);
998                 m_player->peer_id = 0;
999         }
1000 }
1001
1002 bool PlayerSAO::isStaticAllowed() const
1003 {
1004         return false;
1005 }
1006
1007 bool PlayerSAO::unlimitedTransferDistance() const
1008 {
1009         return g_settings->getBool("unlimited_player_transfer_distance");
1010 }
1011
1012 std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
1013 {
1014         std::ostringstream os(std::ios::binary);
1015
1016         if(protocol_version >= 15)
1017         {
1018                 writeU8(os, 1); // version
1019                 os<<serializeString(m_player->getName()); // name
1020                 writeU8(os, 1); // is_player
1021                 writeS16(os, getId()); //id
1022                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1023                 writeF1000(os, m_player->getYaw());
1024                 writeS16(os, getHP());
1025
1026                 writeU8(os, 5 + m_bone_position.size()); // number of messages stuffed in here
1027                 os<<serializeLongString(getPropertyPacket()); // message 1
1028                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1029                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
1030                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1031                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
1032                 }
1033                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
1034                 os<<serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity)); // 5
1035         }
1036         else
1037         {
1038                 writeU8(os, 0); // version
1039                 os<<serializeString(m_player->getName()); // name
1040                 writeU8(os, 1); // is_player
1041                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1042                 writeF1000(os, m_player->getYaw());
1043                 writeS16(os, getHP());
1044                 writeU8(os, 2); // number of messages stuffed in here
1045                 os<<serializeLongString(getPropertyPacket()); // message 1
1046                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1047         }
1048
1049         // return result
1050         return os.str();
1051 }
1052
1053 std::string PlayerSAO::getStaticData()
1054 {
1055         assert(0);
1056         return "";
1057 }
1058
1059 bool PlayerSAO::isAttached()
1060 {
1061         if(!m_attachment_parent_id)
1062                 return false;
1063         // Check if the parent still exists
1064         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
1065         if(obj)
1066                 return true;
1067         return false;
1068 }
1069
1070 void PlayerSAO::step(float dtime, bool send_recommended)
1071 {
1072         if(!m_properties_sent)
1073         {
1074                 m_properties_sent = true;
1075                 std::string str = getPropertyPacket();
1076                 // create message and add to list
1077                 ActiveObjectMessage aom(getId(), true, str);
1078                 m_messages_out.push_back(aom);
1079         }
1080
1081         // If attached, check that our parent is still there. If it isn't, detach.
1082         if(m_attachment_parent_id && !isAttached())
1083         {
1084                 m_attachment_parent_id = 0;
1085                 m_attachment_bone = "";
1086                 m_attachment_position = v3f(0,0,0);
1087                 m_attachment_rotation = v3f(0,0,0);
1088                 m_player->setPosition(m_last_good_position);
1089                 m_moved = true;
1090         }
1091
1092         m_time_from_last_punch += dtime;
1093         m_nocheat_dig_time += dtime;
1094
1095         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
1096         // If the object gets detached this comes into effect automatically from the last known origin
1097         if(isAttached())
1098         {
1099                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1100                 m_last_good_position = pos;
1101                 m_last_good_position_age = 0;
1102                 m_player->setPosition(pos);
1103         }
1104         else
1105         {
1106                 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
1107                 {
1108                         m_last_good_position = m_player->getPosition();
1109                         m_last_good_position_age = 0;
1110                 }
1111                 else
1112                 {
1113                         /*
1114                                 Check player movements
1115
1116                                 NOTE: Actually the server should handle player physics like the
1117                                 client does and compare player's position to what is calculated
1118                                 on our side. This is required when eg. players fly due to an
1119                                 explosion. Altough a node-based alternative might be possible
1120                                 too, and much more lightweight.
1121                         */
1122
1123                         float player_max_speed = 0;
1124                         float player_max_speed_up = 0;
1125                         if(m_privs.count("fast") != 0){
1126                                 // Fast speed
1127                                 player_max_speed = BS * 20;
1128                                 player_max_speed_up = BS * 20;
1129                         } else {
1130                                 // Normal speed
1131                                 player_max_speed = BS * 4.0;
1132                                 player_max_speed_up = BS * 4.0;
1133                         }
1134                         // Tolerance
1135                         player_max_speed *= 2.5;
1136                         player_max_speed_up *= 2.5;
1137
1138                         m_last_good_position_age += dtime;
1139                         if(m_last_good_position_age >= 1.0){
1140                                 float age = m_last_good_position_age;
1141                                 v3f diff = (m_player->getPosition() - m_last_good_position);
1142                                 float d_vert = diff.Y;
1143                                 diff.Y = 0;
1144                                 float d_horiz = diff.getLength();
1145                                 /*infostream<<m_player->getName()<<"'s horizontal speed is "
1146                                                 <<(d_horiz/age)<<std::endl;*/
1147                                 if(d_horiz <= age * player_max_speed &&
1148                                                 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1149                                         m_last_good_position = m_player->getPosition();
1150                                 } else {
1151                                         actionstream<<"Player "<<m_player->getName()
1152                                                         <<" moved too fast; resetting position"
1153                                                         <<std::endl;
1154                                         m_player->setPosition(m_last_good_position);
1155                                         m_moved = true;
1156                                 }
1157                                 m_last_good_position_age = 0;
1158                         }
1159                 }
1160         }
1161
1162         if(send_recommended == false)
1163                 return;
1164
1165         // If the object is attached client-side, don't waste bandwidth sending its position to clients
1166         if(m_position_not_sent && !isAttached())
1167         {
1168                 m_position_not_sent = false;
1169                 float update_interval = m_env->getSendRecommendedInterval();
1170                 v3f pos;
1171                 if(isAttached()) // Just in case we ever do send attachment position too
1172                         pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1173                 else
1174                         pos = m_player->getPosition() + v3f(0,BS*1,0);
1175                 std::string str = gob_cmd_update_position(
1176                         pos,
1177                         v3f(0,0,0),
1178                         v3f(0,0,0),
1179                         m_player->getYaw(),
1180                         true,
1181                         false,
1182                         update_interval
1183                 );
1184                 // create message and add to list
1185                 ActiveObjectMessage aom(getId(), false, str);
1186                 m_messages_out.push_back(aom);
1187         }
1188
1189         if(m_wielded_item_not_sent)
1190         {
1191                 m_wielded_item_not_sent = false;
1192                 // GenericCAO has no special way to show this
1193         }
1194
1195         if(m_armor_groups_sent == false){
1196                 m_armor_groups_sent = true;
1197                 std::string str = gob_cmd_update_armor_groups(
1198                                 m_armor_groups);
1199                 // create message and add to list
1200                 ActiveObjectMessage aom(getId(), true, str);
1201                 m_messages_out.push_back(aom);
1202         }
1203
1204         if(m_physics_override_sent == false){
1205                 m_physics_override_sent = true;
1206                 std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity);
1207                 // create message and add to list
1208                 ActiveObjectMessage aom(getId(), true, str);
1209                 m_messages_out.push_back(aom);
1210         }
1211
1212         if(m_animation_sent == false){
1213                 m_animation_sent = true;
1214                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
1215                 // create message and add to list
1216                 ActiveObjectMessage aom(getId(), true, str);
1217                 m_messages_out.push_back(aom);
1218         }
1219
1220         if(m_bone_position_sent == false){
1221                 m_bone_position_sent = true;
1222                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1223                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
1224                         // create message and add to list
1225                         ActiveObjectMessage aom(getId(), true, str);
1226                         m_messages_out.push_back(aom);
1227                 }
1228         }
1229
1230         if(m_attachment_sent == false){
1231                 m_attachment_sent = true;
1232                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
1233                 // create message and add to list
1234                 ActiveObjectMessage aom(getId(), true, str);
1235                 m_messages_out.push_back(aom);
1236         }
1237 }
1238
1239 void PlayerSAO::setBasePosition(const v3f &position)
1240 {
1241         // This needs to be ran for attachments too
1242         ServerActiveObject::setBasePosition(position);
1243         m_position_not_sent = true;
1244 }
1245
1246 void PlayerSAO::setPos(v3f pos)
1247 {
1248         if(isAttached())
1249                 return;
1250         m_player->setPosition(pos);
1251         // Movement caused by this command is always valid
1252         m_last_good_position = pos;
1253         m_last_good_position_age = 0;
1254         // Force position change on client
1255         m_moved = true;
1256 }
1257
1258 void PlayerSAO::moveTo(v3f pos, bool continuous)
1259 {
1260         if(isAttached())
1261                 return;
1262         m_player->setPosition(pos);
1263         // Movement caused by this command is always valid
1264         m_last_good_position = pos;
1265         m_last_good_position_age = 0;
1266         // Force position change on client
1267         m_moved = true;
1268 }
1269
1270 void PlayerSAO::setYaw(float yaw)
1271 {
1272         m_player->setYaw(yaw);
1273         // Force change on client
1274         m_moved = true;
1275 }
1276
1277 void PlayerSAO::setPitch(float pitch)
1278 {
1279         m_player->setPitch(pitch);
1280         // Force change on client
1281         m_moved = true;
1282 }
1283
1284 int PlayerSAO::punch(v3f dir,
1285         const ToolCapabilities *toolcap,
1286         ServerActiveObject *puncher,
1287         float time_from_last_punch)
1288 {
1289         // It's best that attachments cannot be punched 
1290         if(isAttached())
1291                 return 0;
1292
1293         if(!toolcap)
1294                 return 0;
1295
1296         // No effect if PvP disabled
1297         if(g_settings->getBool("enable_pvp") == false){
1298                 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1299                         std::string str = gob_cmd_punched(0, getHP());
1300                         // create message and add to list
1301                         ActiveObjectMessage aom(getId(), true, str);
1302                         m_messages_out.push_back(aom);
1303                         return 0;
1304                 }
1305         }
1306
1307         HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1308                         time_from_last_punch);
1309
1310         std::string punchername = "nil";
1311
1312         if ( puncher != 0 )
1313                 punchername = puncher->getDescription();
1314
1315         actionstream<<"Player "<<m_player->getName()<<" punched by "
1316                         <<punchername<<", damage "<<hitparams.hp
1317                         <<" HP"<<std::endl;
1318
1319         setHP(getHP() - hitparams.hp);
1320
1321         if(hitparams.hp != 0)
1322         {
1323                 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1324                 // create message and add to list
1325                 ActiveObjectMessage aom(getId(), true, str);
1326                 m_messages_out.push_back(aom);
1327         }
1328
1329         return hitparams.wear;
1330 }
1331
1332 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1333 {
1334 }
1335
1336 s16 PlayerSAO::getHP() const
1337 {
1338         return m_player->hp;
1339 }
1340
1341 void PlayerSAO::setHP(s16 hp)
1342 {
1343         s16 oldhp = m_player->hp;
1344
1345         if(hp < 0)
1346                 hp = 0;
1347         else if(hp > PLAYER_MAX_HP)
1348                 hp = PLAYER_MAX_HP;
1349
1350         if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1351         {
1352                 m_hp_not_sent = true; // fix wrong prediction on client
1353                 return;
1354         }
1355
1356         m_player->hp = hp;
1357
1358         if(hp != oldhp)
1359                 m_hp_not_sent = true;
1360
1361         // On death or reincarnation send an active object message
1362         if((hp == 0) != (oldhp == 0))
1363         {
1364                 // Will send new is_visible value based on (getHP()!=0)
1365                 m_properties_sent = false;
1366                 // Send new HP
1367                 std::string str = gob_cmd_punched(0, getHP());
1368                 ActiveObjectMessage aom(getId(), true, str);
1369                 m_messages_out.push_back(aom);
1370         }
1371 }
1372
1373 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1374 {
1375         m_armor_groups = armor_groups;
1376         m_armor_groups_sent = false;
1377 }
1378
1379 void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
1380 {
1381         // store these so they can be updated to clients
1382         m_animation_range = frame_range;
1383         m_animation_speed = frame_speed;
1384         m_animation_blend = frame_blend;
1385         m_animation_sent = false;
1386 }
1387
1388 void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
1389 {
1390         // store these so they can be updated to clients
1391         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1392         m_bone_position_sent = false;
1393 }
1394
1395 void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
1396 {
1397         // Attachments need to be handled on both the server and client.
1398         // If we just attach on the server, we can only copy the position of the parent. Attachments
1399         // are still sent to clients at an interval so players might see them lagging, plus we can't
1400         // read and attach to skeletal bones.
1401         // If we just attach on the client, the server still sees the child at its original location.
1402         // This breaks some things so we also give the server the most accurate representation
1403         // even if players only see the client changes.
1404
1405         m_attachment_parent_id = parent_id;
1406         m_attachment_bone = bone;
1407         m_attachment_position = position;
1408         m_attachment_rotation = rotation;
1409         m_attachment_sent = false;
1410 }
1411
1412 ObjectProperties* PlayerSAO::accessObjectProperties()
1413 {
1414         return &m_prop;
1415 }
1416
1417 void PlayerSAO::notifyObjectPropertiesModified()
1418 {
1419         m_properties_sent = false;
1420 }
1421
1422 Inventory* PlayerSAO::getInventory()
1423 {
1424         return m_inventory;
1425 }
1426 const Inventory* PlayerSAO::getInventory() const
1427 {
1428         return m_inventory;
1429 }
1430
1431 InventoryLocation PlayerSAO::getInventoryLocation() const
1432 {
1433         InventoryLocation loc;
1434         loc.setPlayer(m_player->getName());
1435         return loc;
1436 }
1437
1438 void PlayerSAO::setInventoryModified()
1439 {
1440         m_inventory_not_sent = true;
1441 }
1442
1443 std::string PlayerSAO::getWieldList() const
1444 {
1445         return "main";
1446 }
1447
1448 int PlayerSAO::getWieldIndex() const
1449 {
1450         return m_wield_index;
1451 }
1452
1453 void PlayerSAO::setWieldIndex(int i)
1454 {
1455         if(i != m_wield_index)
1456         {
1457                 m_wield_index = i;
1458                 m_wielded_item_not_sent = true;
1459         }
1460 }
1461
1462 void PlayerSAO::disconnected()
1463 {
1464         m_peer_id = 0;
1465         m_removed = true;
1466         if(m_player->getPlayerSAO() == this)
1467         {
1468                 m_player->setPlayerSAO(NULL);
1469                 m_player->peer_id = 0;
1470         }
1471 }
1472
1473 std::string PlayerSAO::getPropertyPacket()
1474 {
1475         m_prop.is_visible = (true);
1476         return gob_cmd_set_properties(m_prop);
1477 }
1478
1479 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1480         //update collision box
1481         *toset = m_player->getCollisionbox();
1482
1483         toset->MinEdge += m_base_position;
1484         toset->MaxEdge += m_base_position;
1485
1486         return true;
1487 }