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