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