]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_sao.cpp
Log unhandled exceptions in connectionthreads to errorstream
[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                                 (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                 m_env->savePlayer(m_player->getName());
1031                 m_env->removePlayer(m_player->getName());
1032         }
1033 }
1034
1035 bool PlayerSAO::isStaticAllowed() const
1036 {
1037         return false;
1038 }
1039
1040 bool PlayerSAO::unlimitedTransferDistance() const
1041 {
1042         return g_settings->getBool("unlimited_player_transfer_distance");
1043 }
1044
1045 std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
1046 {
1047         std::ostringstream os(std::ios::binary);
1048
1049         if(protocol_version >= 15)
1050         {
1051                 writeU8(os, 1); // version
1052                 os<<serializeString(m_player->getName()); // name
1053                 writeU8(os, 1); // is_player
1054                 writeS16(os, getId()); //id
1055                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1056                 writeF1000(os, m_player->getYaw());
1057                 writeS16(os, getHP());
1058
1059                 writeU8(os, 5 + m_bone_position.size()); // number of messages stuffed in here
1060                 os<<serializeLongString(getPropertyPacket()); // message 1
1061                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1062                 os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
1063                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1064                         os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
1065                 }
1066                 os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
1067                 os<<serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed,
1068                                 m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
1069                                 m_physics_override_sneak_glitch)); // 5
1070         }
1071         else
1072         {
1073                 writeU8(os, 0); // version
1074                 os<<serializeString(m_player->getName()); // name
1075                 writeU8(os, 1); // is_player
1076                 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
1077                 writeF1000(os, m_player->getYaw());
1078                 writeS16(os, getHP());
1079                 writeU8(os, 2); // number of messages stuffed in here
1080                 os<<serializeLongString(getPropertyPacket()); // message 1
1081                 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
1082         }
1083
1084         // return result
1085         return os.str();
1086 }
1087
1088 std::string PlayerSAO::getStaticData()
1089 {
1090         assert(0);
1091         return "";
1092 }
1093
1094 bool PlayerSAO::isAttached()
1095 {
1096         if(!m_attachment_parent_id)
1097                 return false;
1098         // Check if the parent still exists
1099         ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
1100         if(obj)
1101                 return true;
1102         return false;
1103 }
1104
1105 void PlayerSAO::step(float dtime, bool send_recommended)
1106 {
1107         if(!m_properties_sent)
1108         {
1109                 m_properties_sent = true;
1110                 std::string str = getPropertyPacket();
1111                 // create message and add to list
1112                 ActiveObjectMessage aom(getId(), true, str);
1113                 m_messages_out.push_back(aom);
1114         }
1115
1116         // If attached, check that our parent is still there. If it isn't, detach.
1117         if(m_attachment_parent_id && !isAttached())
1118         {
1119                 m_attachment_parent_id = 0;
1120                 m_attachment_bone = "";
1121                 m_attachment_position = v3f(0,0,0);
1122                 m_attachment_rotation = v3f(0,0,0);
1123                 m_player->setPosition(m_last_good_position);
1124                 m_moved = true;
1125         }
1126
1127         //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;
1128
1129         // Set lag pool maximums based on estimated lag
1130         const float LAG_POOL_MIN = 5.0;
1131         float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
1132         if(lag_pool_max < LAG_POOL_MIN)
1133                 lag_pool_max = LAG_POOL_MIN;
1134         m_dig_pool.setMax(lag_pool_max);
1135         m_move_pool.setMax(lag_pool_max);
1136
1137         // Increment cheat prevention timers
1138         m_dig_pool.add(dtime);
1139         m_move_pool.add(dtime);
1140         m_time_from_last_punch += dtime;
1141         m_nocheat_dig_time += dtime;
1142
1143         // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
1144         // If the object gets detached this comes into effect automatically from the last known origin
1145         if(isAttached())
1146         {
1147                 v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1148                 m_last_good_position = pos;
1149                 m_player->setPosition(pos);
1150         }
1151
1152         if(send_recommended == false)
1153                 return;
1154
1155         // If the object is attached client-side, don't waste bandwidth sending its position to clients
1156         if(m_position_not_sent && !isAttached())
1157         {
1158                 m_position_not_sent = false;
1159                 float update_interval = m_env->getSendRecommendedInterval();
1160                 v3f pos;
1161                 if(isAttached()) // Just in case we ever do send attachment position too
1162                         pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
1163                 else
1164                         pos = m_player->getPosition() + v3f(0,BS*1,0);
1165                 std::string str = gob_cmd_update_position(
1166                         pos,
1167                         v3f(0,0,0),
1168                         v3f(0,0,0),
1169                         m_player->getYaw(),
1170                         true,
1171                         false,
1172                         update_interval
1173                 );
1174                 // create message and add to list
1175                 ActiveObjectMessage aom(getId(), false, str);
1176                 m_messages_out.push_back(aom);
1177         }
1178
1179         if(m_wielded_item_not_sent)
1180         {
1181                 m_wielded_item_not_sent = false;
1182                 // GenericCAO has no special way to show this
1183         }
1184
1185         if(m_armor_groups_sent == false){
1186                 m_armor_groups_sent = true;
1187                 std::string str = gob_cmd_update_armor_groups(
1188                                 m_armor_groups);
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_physics_override_sent == false){
1195                 m_physics_override_sent = true;
1196                 std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
1197                                 m_physics_override_jump, m_physics_override_gravity,
1198                                 m_physics_override_sneak, m_physics_override_sneak_glitch);
1199                 // create message and add to list
1200                 ActiveObjectMessage aom(getId(), true, str);
1201                 m_messages_out.push_back(aom);
1202         }
1203
1204         if(m_animation_sent == false){
1205                 m_animation_sent = true;
1206                 std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
1207                 // create message and add to list
1208                 ActiveObjectMessage aom(getId(), true, str);
1209                 m_messages_out.push_back(aom);
1210         }
1211
1212         if(m_bone_position_sent == false){
1213                 m_bone_position_sent = true;
1214                 for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
1215                         std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
1216                         // create message and add to list
1217                         ActiveObjectMessage aom(getId(), true, str);
1218                         m_messages_out.push_back(aom);
1219                 }
1220         }
1221
1222         if(m_attachment_sent == false){
1223                 m_attachment_sent = true;
1224                 std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
1225                 // create message and add to list
1226                 ActiveObjectMessage aom(getId(), true, str);
1227                 m_messages_out.push_back(aom);
1228         }
1229 }
1230
1231 void PlayerSAO::setBasePosition(const v3f &position)
1232 {
1233         // This needs to be ran for attachments too
1234         ServerActiveObject::setBasePosition(position);
1235         m_position_not_sent = true;
1236 }
1237
1238 void PlayerSAO::setPos(v3f pos)
1239 {
1240         if(isAttached())
1241                 return;
1242         m_player->setPosition(pos);
1243         // Movement caused by this command is always valid
1244         m_last_good_position = pos;
1245         // Force position change on client
1246         m_moved = true;
1247 }
1248
1249 void PlayerSAO::moveTo(v3f pos, bool continuous)
1250 {
1251         if(isAttached())
1252                 return;
1253         m_player->setPosition(pos);
1254         // Movement caused by this command is always valid
1255         m_last_good_position = pos;
1256         // Force position change on client
1257         m_moved = true;
1258 }
1259
1260 void PlayerSAO::setYaw(float yaw)
1261 {
1262         m_player->setYaw(yaw);
1263         // Force change on client
1264         m_moved = true;
1265 }
1266
1267 void PlayerSAO::setPitch(float pitch)
1268 {
1269         m_player->setPitch(pitch);
1270         // Force change on client
1271         m_moved = true;
1272 }
1273
1274 int PlayerSAO::punch(v3f dir,
1275         const ToolCapabilities *toolcap,
1276         ServerActiveObject *puncher,
1277         float time_from_last_punch)
1278 {
1279         // It's best that attachments cannot be punched 
1280         if(isAttached())
1281                 return 0;
1282
1283         if(!toolcap)
1284                 return 0;
1285
1286         // No effect if PvP disabled
1287         if(g_settings->getBool("enable_pvp") == false){
1288                 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1289                         std::string str = gob_cmd_punched(0, getHP());
1290                         // create message and add to list
1291                         ActiveObjectMessage aom(getId(), true, str);
1292                         m_messages_out.push_back(aom);
1293                         return 0;
1294                 }
1295         }
1296
1297         HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1298                         time_from_last_punch);
1299
1300         std::string punchername = "nil";
1301
1302         if ( puncher != 0 )
1303                 punchername = puncher->getDescription();
1304
1305         actionstream<<"Player "<<m_player->getName()<<" punched by "
1306                         <<punchername<<", damage "<<hitparams.hp
1307                         <<" HP"<<std::endl;
1308
1309         setHP(getHP() - hitparams.hp);
1310
1311         return hitparams.wear;
1312 }
1313
1314 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1315 {
1316 }
1317
1318 s16 PlayerSAO::getHP() const
1319 {
1320         return m_player->hp;
1321 }
1322
1323 s16 PlayerSAO::readDamage()
1324 {
1325         s16 damage = m_damage;
1326         m_damage = 0;
1327         return damage;
1328 }
1329
1330 void PlayerSAO::setHP(s16 hp)
1331 {
1332         s16 oldhp = m_player->hp;
1333
1334         if(hp < 0)
1335                 hp = 0;
1336         else if(hp > PLAYER_MAX_HP)
1337                 hp = PLAYER_MAX_HP;
1338
1339         if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1340         {
1341                 m_hp_not_sent = true; // fix wrong prediction on client
1342                 return;
1343         }
1344
1345         m_player->hp = hp;
1346
1347         if(hp != oldhp) {
1348                 m_hp_not_sent = true;
1349                 if(oldhp > hp)
1350                         m_damage += oldhp - hp;
1351         }
1352
1353         // Update properties on death
1354         if((hp == 0) != (oldhp == 0))
1355                 m_properties_sent = false;
1356 }
1357
1358 u16 PlayerSAO::getBreath() const
1359 {
1360         return m_player->getBreath();
1361 }
1362
1363 void PlayerSAO::setBreath(u16 breath)
1364 {
1365         m_player->setBreath(breath);
1366 }
1367
1368 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1369 {
1370         m_armor_groups = armor_groups;
1371         m_armor_groups_sent = false;
1372 }
1373
1374 void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
1375 {
1376         // store these so they can be updated to clients
1377         m_animation_range = frame_range;
1378         m_animation_speed = frame_speed;
1379         m_animation_blend = frame_blend;
1380         m_animation_sent = false;
1381 }
1382
1383 void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
1384 {
1385         // store these so they can be updated to clients
1386         m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1387         m_bone_position_sent = false;
1388 }
1389
1390 void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
1391 {
1392         // Attachments need to be handled on both the server and client.
1393         // If we just attach on the server, we can only copy the position of the parent. Attachments
1394         // are still sent to clients at an interval so players might see them lagging, plus we can't
1395         // read and attach to skeletal bones.
1396         // If we just attach on the client, the server still sees the child at its original location.
1397         // This breaks some things so we also give the server the most accurate representation
1398         // even if players only see the client changes.
1399
1400         m_attachment_parent_id = parent_id;
1401         m_attachment_bone = bone;
1402         m_attachment_position = position;
1403         m_attachment_rotation = rotation;
1404         m_attachment_sent = false;
1405 }
1406
1407 ObjectProperties* PlayerSAO::accessObjectProperties()
1408 {
1409         return &m_prop;
1410 }
1411
1412 void PlayerSAO::notifyObjectPropertiesModified()
1413 {
1414         m_properties_sent = false;
1415 }
1416
1417 Inventory* PlayerSAO::getInventory()
1418 {
1419         return m_inventory;
1420 }
1421 const Inventory* PlayerSAO::getInventory() const
1422 {
1423         return m_inventory;
1424 }
1425
1426 InventoryLocation PlayerSAO::getInventoryLocation() const
1427 {
1428         InventoryLocation loc;
1429         loc.setPlayer(m_player->getName());
1430         return loc;
1431 }
1432
1433 void PlayerSAO::setInventoryModified()
1434 {
1435         m_inventory_not_sent = true;
1436 }
1437
1438 std::string PlayerSAO::getWieldList() const
1439 {
1440         return "main";
1441 }
1442
1443 int PlayerSAO::getWieldIndex() const
1444 {
1445         return m_wield_index;
1446 }
1447
1448 void PlayerSAO::setWieldIndex(int i)
1449 {
1450         if(i != m_wield_index)
1451         {
1452                 m_wield_index = i;
1453                 m_wielded_item_not_sent = true;
1454         }
1455 }
1456
1457 void PlayerSAO::disconnected()
1458 {
1459         m_peer_id = 0;
1460         m_removed = true;
1461         if(m_player->getPlayerSAO() == this)
1462         {
1463                 m_player->setPlayerSAO(NULL);
1464                 m_player->peer_id = 0;
1465         }
1466 }
1467
1468 std::string PlayerSAO::getPropertyPacket()
1469 {
1470         m_prop.is_visible = (true);
1471         return gob_cmd_set_properties(m_prop);
1472 }
1473
1474 bool PlayerSAO::checkMovementCheat()
1475 {
1476         bool cheated = false;
1477         if(isAttached() || m_is_singleplayer ||
1478                         g_settings->getBool("disable_anticheat"))
1479         {
1480                 m_last_good_position = m_player->getPosition();
1481         }
1482         else
1483         {
1484                 /*
1485                         Check player movements
1486
1487                         NOTE: Actually the server should handle player physics like the
1488                         client does and compare player's position to what is calculated
1489                         on our side. This is required when eg. players fly due to an
1490                         explosion. Altough a node-based alternative might be possible
1491                         too, and much more lightweight.
1492                 */
1493
1494                 float player_max_speed = 0;
1495                 float player_max_speed_up = 0;
1496                 if(m_privs.count("fast") != 0){
1497                         // Fast speed
1498                         player_max_speed = m_player->movement_speed_fast;
1499                         player_max_speed_up = m_player->movement_speed_fast;
1500                 } else {
1501                         // Normal speed
1502                         player_max_speed = m_player->movement_speed_walk;
1503                         player_max_speed_up = m_player->movement_speed_walk;
1504                 }
1505                 // Tolerance. With the lag pool we shouldn't need it.
1506                 //player_max_speed *= 2.5;
1507                 //player_max_speed_up *= 2.5;
1508
1509                 v3f diff = (m_player->getPosition() - m_last_good_position);
1510                 float d_vert = diff.Y;
1511                 diff.Y = 0;
1512                 float d_horiz = diff.getLength();
1513                 float required_time = d_horiz/player_max_speed;
1514                 if(d_vert > 0 && d_vert/player_max_speed > required_time)
1515                         required_time = d_vert/player_max_speed;
1516                 if(m_move_pool.grab(required_time)){
1517                         m_last_good_position = m_player->getPosition();
1518                 } else {
1519                         actionstream<<"Player "<<m_player->getName()
1520                                         <<" moved too fast; resetting position"
1521                                         <<std::endl;
1522                         m_player->setPosition(m_last_good_position);
1523                         m_moved = true;
1524                         cheated = true;
1525                 }
1526         }
1527         return cheated;
1528 }
1529
1530 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1531         //update collision box
1532         *toset = m_player->getCollisionbox();
1533
1534         toset->MinEdge += m_base_position;
1535         toset->MaxEdge += m_base_position;
1536
1537         return true;
1538 }
1539
1540 bool PlayerSAO::collideWithObjects(){
1541         return true;
1542 }
1543