]> git.lizzy.rs Git - minetest.git/blob - src/content_sao.cpp
Merge remote branch 'origin/master'
[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);
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                 actionstream<<getDescription()<<" punched by "
677                                 <<puncher->getDescription()<<", damage "<<result.damage
678                                 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
679                 
680                 {
681                         std::string str = gob_cmd_punched(result.damage, getHP());
682                         // create message and add to list
683                         ActiveObjectMessage aom(getId(), true, str);
684                         m_messages_out.push_back(aom);
685                 }
686
687                 if(getHP() == 0)
688                         m_removed = true;
689         }
690
691         lua_State *L = m_env->getLua();
692         scriptapi_luaentity_punch(L, m_id, puncher,
693                         time_from_last_punch, toolcap, dir);
694
695         return result.wear;
696 }
697
698 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
699 {
700         if(!m_registered)
701                 return;
702         // It's best that attachments cannot be clicked
703         if(isAttached())
704                 return;
705         lua_State *L = m_env->getLua();
706         scriptapi_luaentity_rightclick(L, 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         actionstream<<"Player "<<m_player->getName()<<" punched by "
1311                         <<puncher->getDescription()<<", damage "<<hitparams.hp
1312                         <<" HP"<<std::endl;
1313
1314         setHP(getHP() - hitparams.hp);
1315
1316         if(hitparams.hp != 0)
1317         {
1318                 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1319                 // create message and add to list
1320                 ActiveObjectMessage aom(getId(), true, str);
1321                 m_messages_out.push_back(aom);
1322         }
1323
1324         return hitparams.wear;
1325 }
1326
1327 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1328 {
1329 }
1330
1331 s16 PlayerSAO::getHP() const
1332 {
1333         return m_player->hp;
1334 }
1335
1336 void PlayerSAO::setHP(s16 hp)
1337 {
1338         s16 oldhp = m_player->hp;
1339
1340         if(hp < 0)
1341                 hp = 0;
1342         else if(hp > PLAYER_MAX_HP)
1343                 hp = PLAYER_MAX_HP;
1344
1345         if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1346         {
1347                 m_hp_not_sent = true; // fix wrong prediction on client
1348                 return;
1349         }
1350
1351         m_player->hp = hp;
1352
1353         if(hp != oldhp)
1354                 m_hp_not_sent = true;
1355
1356         // On death or reincarnation send an active object message
1357         if((hp == 0) != (oldhp == 0))
1358         {
1359                 // Will send new is_visible value based on (getHP()!=0)
1360                 m_properties_sent = false;
1361                 // Send new HP
1362                 std::string str = gob_cmd_punched(0, getHP());
1363                 ActiveObjectMessage aom(getId(), true, str);
1364                 m_messages_out.push_back(aom);
1365         }
1366 }
1367
1368 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1369 {
1370         m_armor_groups = armor_groups;
1371         m_armor_groups_sent = false;
1372 }
1373
1374 void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
1375 {
1376         // store these so they can be updated to clients
1377         m_animation_range = frame_range;
1378         m_animation_speed = frame_speed;
1379         m_animation_blend = frame_blend;
1380         m_animation_sent = false;
1381 }
1382
1383 void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
1384 {
1385         // store these so they can be updated to clients
1386         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1387         m_bone_position_sent = false;
1388 }
1389
1390 void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
1391 {
1392         // Attachments need to be handled on both the server and client.
1393         // If we just attach on the server, we can only copy the position of the parent. Attachments
1394         // are still sent to clients at an interval so players might see them lagging, plus we can't
1395         // read and attach to skeletal bones.
1396         // If we just attach on the client, the server still sees the child at its original location.
1397         // This breaks some things so we also give the server the most accurate representation
1398         // even if players only see the client changes.
1399
1400         m_attachment_parent_id = parent_id;
1401         m_attachment_bone = bone;
1402         m_attachment_position = position;
1403         m_attachment_rotation = rotation;
1404         m_attachment_sent = false;
1405 }
1406
1407 ObjectProperties* PlayerSAO::accessObjectProperties()
1408 {
1409         return &m_prop;
1410 }
1411
1412 void PlayerSAO::notifyObjectPropertiesModified()
1413 {
1414         m_properties_sent = false;
1415 }
1416
1417 Inventory* PlayerSAO::getInventory()
1418 {
1419         return m_inventory;
1420 }
1421 const Inventory* PlayerSAO::getInventory() const
1422 {
1423         return m_inventory;
1424 }
1425
1426 InventoryLocation PlayerSAO::getInventoryLocation() const
1427 {
1428         InventoryLocation loc;
1429         loc.setPlayer(m_player->getName());
1430         return loc;
1431 }
1432
1433 void PlayerSAO::setInventoryModified()
1434 {
1435         m_inventory_not_sent = true;
1436 }
1437
1438 std::string PlayerSAO::getWieldList() const
1439 {
1440         return "main";
1441 }
1442
1443 int PlayerSAO::getWieldIndex() const
1444 {
1445         return m_wield_index;
1446 }
1447
1448 void PlayerSAO::setWieldIndex(int i)
1449 {
1450         if(i != m_wield_index)
1451         {
1452                 m_wield_index = i;
1453                 m_wielded_item_not_sent = true;
1454         }
1455 }
1456
1457 void PlayerSAO::disconnected()
1458 {
1459         m_peer_id = 0;
1460         m_removed = true;
1461         if(m_player->getPlayerSAO() == this)
1462         {
1463                 m_player->setPlayerSAO(NULL);
1464                 m_player->peer_id = 0;
1465         }
1466 }
1467
1468 std::string PlayerSAO::getPropertyPacket()
1469 {
1470         m_prop.is_visible = (true);
1471         return gob_cmd_set_properties(m_prop);
1472 }
1473
1474 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1475         //player collision handling is already done clientside no need to do it twice
1476         return false;
1477 }