]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_sao.cpp
ae08b4260385fb9b4f253b7ff81fc2dd9482094f
[dragonfireclient.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 {
940         assert(m_player);
941         assert(m_peer_id != 0);
942         setBasePosition(m_player->getPosition());
943         m_inventory = &m_player->inventory;
944         m_armor_groups["fleshy"] = 100;
945
946         m_prop.hp_max = PLAYER_MAX_HP;
947         m_prop.physical = false;
948         m_prop.weight = 75;
949         m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
950         // start of default appearance, this should be overwritten by LUA
951         m_prop.visual = "upright_sprite";
952         m_prop.visual_size = v2f(1, 2);
953         m_prop.textures.clear();
954         m_prop.textures.push_back("player.png");
955         m_prop.textures.push_back("player_back.png");
956         m_prop.colors.clear();
957         m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
958         m_prop.spritediv = v2s16(1,1);
959         // end of default appearance
960         m_prop.is_visible = true;
961         m_prop.makes_footstep_sound = true;
962 }
963
964 PlayerSAO::~PlayerSAO()
965 {
966         if(m_inventory != &m_player->inventory)
967                 delete m_inventory;
968
969 }
970
971 std::string PlayerSAO::getDescription()
972 {
973         return std::string("player ") + m_player->getName();
974 }
975
976 // Called after id has been set and has been inserted in environment
977 void PlayerSAO::addedToEnvironment(u32 dtime_s)
978 {
979         ServerActiveObject::addedToEnvironment(dtime_s);
980         ServerActiveObject::setBasePosition(m_player->getPosition());
981         m_player->setPlayerSAO(this);
982         m_player->peer_id = m_peer_id;
983         m_last_good_position = m_player->getPosition();
984         m_last_good_position_age = 0.0;
985 }
986
987 // Called before removing from environment
988 void PlayerSAO::removingFromEnvironment()
989 {
990         ServerActiveObject::removingFromEnvironment();
991         if(m_player->getPlayerSAO() == this)
992         {
993                 m_player->setPlayerSAO(NULL);
994                 m_player->peer_id = 0;
995         }
996 }
997
998 bool PlayerSAO::isStaticAllowed() const
999 {
1000         return false;
1001 }
1002
1003 bool PlayerSAO::unlimitedTransferDistance() const
1004 {
1005         return g_settings->getBool("unlimited_player_transfer_distance");
1006 }
1007
1008 std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
1009 {
1010         std::ostringstream os(std::ios::binary);
1011
1012         if(protocol_version >= 15)
1013         {
1014                 writeU8(os, 1); // version
1015                 os<<serializeString(m_player->getName()); // name
1016                 writeU8(os, 1); // is_player
1017                 writeS16(os, getId()); //id
1018                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1019                 writeF1000(os, m_player->getYaw());
1020                 writeS16(os, getHP());
1021
1022                 writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
1023                 os<<serializeLongString(getPropertyPacket()); // message 1
1024                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1025                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
1026                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1027                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
1028                 }
1029                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
1030         }
1031         else
1032         {
1033                 writeU8(os, 0); // version
1034                 os<<serializeString(m_player->getName()); // name
1035                 writeU8(os, 1); // is_player
1036                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1037                 writeF1000(os, m_player->getYaw());
1038                 writeS16(os, getHP());
1039                 writeU8(os, 2); // number of messages stuffed in here
1040                 os<<serializeLongString(getPropertyPacket()); // message 1
1041                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1042         }
1043
1044         // return result
1045         return os.str();
1046 }
1047
1048 std::string PlayerSAO::getStaticData()
1049 {
1050         assert(0);
1051         return "";
1052 }
1053
1054 bool PlayerSAO::isAttached()
1055 {
1056         if(!m_attachment_parent_id)
1057                 return false;
1058         // Check if the parent still exists
1059         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
1060         if(obj)
1061                 return true;
1062         return false;
1063 }
1064
1065 void PlayerSAO::step(float dtime, bool send_recommended)
1066 {
1067         if(!m_properties_sent)
1068         {
1069                 m_properties_sent = true;
1070                 std::string str = getPropertyPacket();
1071                 // create message and add to list
1072                 ActiveObjectMessage aom(getId(), true, str);
1073                 m_messages_out.push_back(aom);
1074         }
1075
1076         // If attached, check that our parent is still there. If it isn't, detach.
1077         if(m_attachment_parent_id && !isAttached())
1078         {
1079                 m_attachment_parent_id = 0;
1080                 m_attachment_bone = "";
1081                 m_attachment_position = v3f(0,0,0);
1082                 m_attachment_rotation = v3f(0,0,0);
1083                 m_player->setPosition(m_last_good_position);
1084                 m_moved = true;
1085         }
1086
1087         m_time_from_last_punch += dtime;
1088         m_nocheat_dig_time += dtime;
1089
1090         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
1091         // If the object gets detached this comes into effect automatically from the last known origin
1092         if(isAttached())
1093         {
1094                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1095                 m_last_good_position = pos;
1096                 m_last_good_position_age = 0;
1097                 m_player->setPosition(pos);
1098         }
1099         else
1100         {
1101                 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
1102                 {
1103                         m_last_good_position = m_player->getPosition();
1104                         m_last_good_position_age = 0;
1105                 }
1106                 else
1107                 {
1108                         /*
1109                                 Check player movements
1110
1111                                 NOTE: Actually the server should handle player physics like the
1112                                 client does and compare player's position to what is calculated
1113                                 on our side. This is required when eg. players fly due to an
1114                                 explosion. Altough a node-based alternative might be possible
1115                                 too, and much more lightweight.
1116                         */
1117
1118                         float player_max_speed = 0;
1119                         float player_max_speed_up = 0;
1120                         if(m_privs.count("fast") != 0){
1121                                 // Fast speed
1122                                 player_max_speed = BS * 20;
1123                                 player_max_speed_up = BS * 20;
1124                         } else {
1125                                 // Normal speed
1126                                 player_max_speed = BS * 4.0;
1127                                 player_max_speed_up = BS * 4.0;
1128                         }
1129                         // Tolerance
1130                         player_max_speed *= 2.5;
1131                         player_max_speed_up *= 2.5;
1132
1133                         m_last_good_position_age += dtime;
1134                         if(m_last_good_position_age >= 1.0){
1135                                 float age = m_last_good_position_age;
1136                                 v3f diff = (m_player->getPosition() - m_last_good_position);
1137                                 float d_vert = diff.Y;
1138                                 diff.Y = 0;
1139                                 float d_horiz = diff.getLength();
1140                                 /*infostream<<m_player->getName()<<"'s horizontal speed is "
1141                                                 <<(d_horiz/age)<<std::endl;*/
1142                                 if(d_horiz <= age * player_max_speed &&
1143                                                 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1144                                         m_last_good_position = m_player->getPosition();
1145                                 } else {
1146                                         actionstream<<"Player "<<m_player->getName()
1147                                                         <<" moved too fast; resetting position"
1148                                                         <<std::endl;
1149                                         m_player->setPosition(m_last_good_position);
1150                                         m_moved = true;
1151                                 }
1152                                 m_last_good_position_age = 0;
1153                         }
1154                 }
1155         }
1156
1157         if(send_recommended == false)
1158                 return;
1159
1160         // If the object is attached client-side, don't waste bandwidth sending its position to clients
1161         if(m_position_not_sent && !isAttached())
1162         {
1163                 m_position_not_sent = false;
1164                 float update_interval = m_env->getSendRecommendedInterval();
1165                 v3f pos;
1166                 if(isAttached()) // Just in case we ever do send attachment position too
1167                         pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1168                 else
1169                         pos = m_player->getPosition() + v3f(0,BS*1,0);
1170                 std::string str = gob_cmd_update_position(
1171                         pos,
1172                         v3f(0,0,0),
1173                         v3f(0,0,0),
1174                         m_player->getYaw(),
1175                         true,
1176                         false,
1177                         update_interval
1178                 );
1179                 // create message and add to list
1180                 ActiveObjectMessage aom(getId(), false, str);
1181                 m_messages_out.push_back(aom);
1182         }
1183
1184         if(m_wielded_item_not_sent)
1185         {
1186                 m_wielded_item_not_sent = false;
1187                 // GenericCAO has no special way to show this
1188         }
1189
1190         if(m_armor_groups_sent == false){
1191                 m_armor_groups_sent = true;
1192                 std::string str = gob_cmd_update_armor_groups(
1193                                 m_armor_groups);
1194                 // create message and add to list
1195                 ActiveObjectMessage aom(getId(), true, str);
1196                 m_messages_out.push_back(aom);
1197         }
1198
1199         if(m_animation_sent == false){
1200                 m_animation_sent = true;
1201                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
1202                 // create message and add to list
1203                 ActiveObjectMessage aom(getId(), true, str);
1204                 m_messages_out.push_back(aom);
1205         }
1206
1207         if(m_bone_position_sent == false){
1208                 m_bone_position_sent = true;
1209                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1210                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
1211                         // create message and add to list
1212                         ActiveObjectMessage aom(getId(), true, str);
1213                         m_messages_out.push_back(aom);
1214                 }
1215         }
1216
1217         if(m_attachment_sent == false){
1218                 m_attachment_sent = true;
1219                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
1220                 // create message and add to list
1221                 ActiveObjectMessage aom(getId(), true, str);
1222                 m_messages_out.push_back(aom);
1223         }
1224 }
1225
1226 void PlayerSAO::setBasePosition(const v3f &position)
1227 {
1228         // This needs to be ran for attachments too
1229         ServerActiveObject::setBasePosition(position);
1230         m_position_not_sent = true;
1231 }
1232
1233 void PlayerSAO::setPos(v3f pos)
1234 {
1235         if(isAttached())
1236                 return;
1237         m_player->setPosition(pos);
1238         // Movement caused by this command is always valid
1239         m_last_good_position = pos;
1240         m_last_good_position_age = 0;
1241         // Force position change on client
1242         m_moved = true;
1243 }
1244
1245 void PlayerSAO::moveTo(v3f pos, bool continuous)
1246 {
1247         if(isAttached())
1248                 return;
1249         m_player->setPosition(pos);
1250         // Movement caused by this command is always valid
1251         m_last_good_position = pos;
1252         m_last_good_position_age = 0;
1253         // Force position change on client
1254         m_moved = true;
1255 }
1256
1257 void PlayerSAO::setYaw(float yaw)
1258 {
1259         m_player->setYaw(yaw);
1260         // Force change on client
1261         m_moved = true;
1262 }
1263
1264 void PlayerSAO::setPitch(float pitch)
1265 {
1266         m_player->setPitch(pitch);
1267         // Force change on client
1268         m_moved = true;
1269 }
1270
1271 int PlayerSAO::punch(v3f dir,
1272         const ToolCapabilities *toolcap,
1273         ServerActiveObject *puncher,
1274         float time_from_last_punch)
1275 {
1276         // It's best that attachments cannot be punched 
1277         if(isAttached())
1278                 return 0;
1279
1280         if(!toolcap)
1281                 return 0;
1282
1283         // No effect if PvP disabled
1284         if(g_settings->getBool("enable_pvp") == false){
1285                 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1286                         std::string str = gob_cmd_punched(0, getHP());
1287                         // create message and add to list
1288                         ActiveObjectMessage aom(getId(), true, str);
1289                         m_messages_out.push_back(aom);
1290                         return 0;
1291                 }
1292         }
1293
1294         HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1295                         time_from_last_punch);
1296
1297         actionstream<<"Player "<<m_player->getName()<<" punched by "
1298                         <<puncher->getDescription()<<", damage "<<hitparams.hp
1299                         <<" HP"<<std::endl;
1300
1301         setHP(getHP() - hitparams.hp);
1302
1303         if(hitparams.hp != 0)
1304         {
1305                 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1306                 // create message and add to list
1307                 ActiveObjectMessage aom(getId(), true, str);
1308                 m_messages_out.push_back(aom);
1309         }
1310
1311         return hitparams.wear;
1312 }
1313
1314 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1315 {
1316 }
1317
1318 s16 PlayerSAO::getHP() const
1319 {
1320         return m_player->hp;
1321 }
1322
1323 void PlayerSAO::setHP(s16 hp)
1324 {
1325         s16 oldhp = m_player->hp;
1326
1327         if(hp < 0)
1328                 hp = 0;
1329         else if(hp > PLAYER_MAX_HP)
1330                 hp = PLAYER_MAX_HP;
1331
1332         if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1333         {
1334                 m_hp_not_sent = true; // fix wrong prediction on client
1335                 return;
1336         }
1337
1338         m_player->hp = hp;
1339
1340         if(hp != oldhp)
1341                 m_hp_not_sent = true;
1342
1343         // On death or reincarnation send an active object message
1344         if((hp == 0) != (oldhp == 0))
1345         {
1346                 // Will send new is_visible value based on (getHP()!=0)
1347                 m_properties_sent = false;
1348                 // Send new HP
1349                 std::string str = gob_cmd_punched(0, getHP());
1350                 ActiveObjectMessage aom(getId(), true, str);
1351                 m_messages_out.push_back(aom);
1352         }
1353 }
1354
1355 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1356 {
1357         m_armor_groups = armor_groups;
1358         m_armor_groups_sent = false;
1359 }
1360
1361 void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
1362 {
1363         // store these so they can be updated to clients
1364         m_animation_range = frame_range;
1365         m_animation_speed = frame_speed;
1366         m_animation_blend = frame_blend;
1367         m_animation_sent = false;
1368 }
1369
1370 void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
1371 {
1372         // store these so they can be updated to clients
1373         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1374         m_bone_position_sent = false;
1375 }
1376
1377 void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
1378 {
1379         // Attachments need to be handled on both the server and client.
1380         // If we just attach on the server, we can only copy the position of the parent. Attachments
1381         // are still sent to clients at an interval so players might see them lagging, plus we can't
1382         // read and attach to skeletal bones.
1383         // If we just attach on the client, the server still sees the child at its original location.
1384         // This breaks some things so we also give the server the most accurate representation
1385         // even if players only see the client changes.
1386
1387         m_attachment_parent_id = parent_id;
1388         m_attachment_bone = bone;
1389         m_attachment_position = position;
1390         m_attachment_rotation = rotation;
1391         m_attachment_sent = false;
1392 }
1393
1394 ObjectProperties* PlayerSAO::accessObjectProperties()
1395 {
1396         return &m_prop;
1397 }
1398
1399 void PlayerSAO::notifyObjectPropertiesModified()
1400 {
1401         m_properties_sent = false;
1402 }
1403
1404 Inventory* PlayerSAO::getInventory()
1405 {
1406         return m_inventory;
1407 }
1408 const Inventory* PlayerSAO::getInventory() const
1409 {
1410         return m_inventory;
1411 }
1412
1413 InventoryLocation PlayerSAO::getInventoryLocation() const
1414 {
1415         InventoryLocation loc;
1416         loc.setPlayer(m_player->getName());
1417         return loc;
1418 }
1419
1420 void PlayerSAO::setInventoryModified()
1421 {
1422         m_inventory_not_sent = true;
1423 }
1424
1425 std::string PlayerSAO::getWieldList() const
1426 {
1427         return "main";
1428 }
1429
1430 int PlayerSAO::getWieldIndex() const
1431 {
1432         return m_wield_index;
1433 }
1434
1435 void PlayerSAO::setWieldIndex(int i)
1436 {
1437         if(i != m_wield_index)
1438         {
1439                 m_wield_index = i;
1440                 m_wielded_item_not_sent = true;
1441         }
1442 }
1443
1444 void PlayerSAO::disconnected()
1445 {
1446         m_peer_id = 0;
1447         m_removed = true;
1448         if(m_player->getPlayerSAO() == this)
1449         {
1450                 m_player->setPlayerSAO(NULL);
1451                 m_player->peer_id = 0;
1452         }
1453 }
1454
1455 std::string PlayerSAO::getPropertyPacket()
1456 {
1457         m_prop.is_visible = (true);
1458         return gob_cmd_set_properties(m_prop);
1459 }
1460
1461 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1462         //player collision handling is already done clientside no need to do it twice
1463         return false;
1464 }