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