3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "content_sao.h"
21 #include "collision.h"
22 #include "environment.h"
24 #include "main.h" // For g_profiler
26 #include "serialization.h" // For compressZlib
27 #include "tool.h" // For ToolCapabilities
30 #include "scriptapi.h"
31 #include "genericobject.h"
32 #include "util/serialize.h"
34 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
40 class DummyLoadSAO : public ServerActiveObject
43 DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type):
44 ServerActiveObject(env, pos)
46 ServerActiveObject::registerType(type, create);
48 // Pretend to be the test object (to fool the client)
50 { return ACTIVEOBJECT_TYPE_TEST; }
51 // And never save to disk
52 bool isStaticAllowed() const
55 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
56 const std::string &data)
58 return new DummyLoadSAO(env, pos, 0);
61 void step(float dtime, bool send_recommended)
64 infostream<<"DummyLoadSAO step"<<std::endl;
70 // Prototype (registers item for deserialization)
71 DummyLoadSAO proto1_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_RAT);
72 DummyLoadSAO proto2_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_OERKKI1);
73 DummyLoadSAO proto3_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_FIREFLY);
74 DummyLoadSAO proto4_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_MOBV2);
80 class TestSAO : public ServerActiveObject
83 TestSAO(ServerEnvironment *env, v3f pos):
84 ServerActiveObject(env, pos),
88 ServerActiveObject::registerType(getType(), create);
91 { return ACTIVEOBJECT_TYPE_TEST; }
93 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
94 const std::string &data)
96 return new TestSAO(env, pos);
99 void step(float dtime, bool send_recommended)
108 m_base_position.Y += dtime * BS * 2;
109 if(m_base_position.Y > 8*BS)
110 m_base_position.Y = 2*BS;
112 if(send_recommended == false)
122 data += itos(0); // 0 = position
124 data += itos(m_base_position.X);
126 data += itos(m_base_position.Y);
128 data += itos(m_base_position.Z);
130 ActiveObjectMessage aom(getId(), false, data);
131 m_messages_out.push_back(aom);
140 // Prototype (registers item for deserialization)
141 TestSAO proto_TestSAO(NULL, v3f(0,0,0));
146 DEPRECATED: New dropped items are implemented in Lua; see
147 builtin/item_entity.lua.
150 class ItemSAO : public ServerActiveObject
154 { return ACTIVEOBJECT_TYPE_ITEM; }
156 float getMinimumSavedMovement()
159 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
160 const std::string &data)
162 std::istringstream is(data, std::ios::binary);
167 // check if version is supported
170 std::string itemstring = deSerializeString(is);
171 infostream<<"create(): Creating item \""
172 <<itemstring<<"\""<<std::endl;
173 return new ItemSAO(env, pos, itemstring);
176 ItemSAO(ServerEnvironment *env, v3f pos,
177 const std::string itemstring):
178 ServerActiveObject(env, pos),
179 m_itemstring(itemstring),
180 m_itemstring_changed(false),
182 m_last_sent_position(0,0,0)
184 ServerActiveObject::registerType(getType(), create);
187 void step(float dtime, bool send_recommended)
189 ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
193 const float interval = 0.2;
194 if(m_move_interval.step(dtime, interval)==false)
198 core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
199 collisionMoveResult moveresult;
201 m_speed_f += v3f(0, -dtime*9.81*BS, 0);
202 // Maximum movement without glitches
203 f32 pos_max_d = BS*0.25;
205 if(m_speed_f.getLength()*dtime > pos_max_d)
206 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
207 v3f pos_f = getBasePosition();
208 v3f pos_f_old = pos_f;
209 v3f accel_f = v3f(0,0,0);
211 IGameDef *gamedef = m_env->getGameDef();
212 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
213 pos_max_d, box, stepheight, dtime,
214 pos_f, m_speed_f, accel_f);
216 if(send_recommended == false)
219 if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
221 setBasePosition(pos_f);
222 m_last_sent_position = pos_f;
224 std::ostringstream os(std::ios::binary);
225 // command (0 = update position)
228 writeV3F1000(os, m_base_position);
229 // create message and add to list
230 ActiveObjectMessage aom(getId(), false, os.str());
231 m_messages_out.push_back(aom);
233 if(m_itemstring_changed)
235 m_itemstring_changed = false;
237 std::ostringstream os(std::ios::binary);
238 // command (1 = update itemstring)
241 os<<serializeString(m_itemstring);
242 // create message and add to list
243 ActiveObjectMessage aom(getId(), false, os.str());
244 m_messages_out.push_back(aom);
248 std::string getClientInitializationData()
250 std::ostringstream os(std::ios::binary);
254 writeV3F1000(os, m_base_position);
256 os<<serializeString(m_itemstring);
260 std::string getStaticData()
262 infostream<<__FUNCTION_NAME<<std::endl;
263 std::ostringstream os(std::ios::binary);
267 os<<serializeString(m_itemstring);
271 ItemStack createItemStack()
274 IItemDefManager *idef = m_env->getGameDef()->idef();
276 item.deSerialize(m_itemstring, idef);
277 infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
278 <<"\" -> item=\""<<item.getItemString()<<"\""
282 catch(SerializationError &e)
284 infostream<<__FUNCTION_NAME<<": serialization error: "
285 <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
291 const ToolCapabilities *toolcap,
292 ServerActiveObject *puncher,
293 float time_from_last_punch)
295 // Directly delete item in creative mode
296 if(g_settings->getBool("creative_mode") == true)
302 // Take item into inventory
303 ItemStack item = createItemStack();
304 Inventory *inv = puncher->getInventory();
307 std::string wieldlist = puncher->getWieldList();
308 ItemStack leftover = inv->addItem(wieldlist, item);
309 puncher->setInventoryModified();
316 m_itemstring = leftover.getItemString();
317 m_itemstring_changed = true;
326 std::string m_itemstring;
327 bool m_itemstring_changed;
329 v3f m_last_sent_position;
330 IntervalLimiter m_move_interval;
333 // Prototype (registers item for deserialization)
334 ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
336 ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
337 const std::string itemstring)
339 return new ItemSAO(env, pos, itemstring);
346 // Prototype (registers item for deserialization)
347 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
349 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
350 const std::string &name, const std::string &state):
351 ServerActiveObject(env, pos),
357 m_acceleration(0,0,0),
359 m_properties_sent(true),
361 m_last_sent_position(0,0,0),
362 m_last_sent_velocity(0,0,0),
363 m_last_sent_position_timer(0),
364 m_last_sent_move_precision(0),
365 m_armor_groups_sent(false)
367 // Only register type if no environment supplied
369 ServerActiveObject::registerType(getType(), create);
373 // Initialize something to armor groups
374 m_armor_groups["fleshy"] = 3;
375 m_armor_groups["snappy"] = 2;
378 LuaEntitySAO::~LuaEntitySAO()
381 lua_State *L = m_env->getLua();
382 scriptapi_luaentity_rm(L, m_id);
386 void LuaEntitySAO::addedToEnvironment()
388 ServerActiveObject::addedToEnvironment();
390 // Create entity from name
391 lua_State *L = m_env->getLua();
392 m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
396 scriptapi_luaentity_get_properties(L, m_id, &m_prop);
397 // Initialize HP from properties
398 m_hp = m_prop.hp_max;
399 // Activate entity, supplying serialized state
400 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
404 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
405 const std::string &data)
413 std::istringstream is(data, std::ios::binary);
415 u8 version = readU8(is);
416 // check if version is supported
418 name = deSerializeString(is);
419 state = deSerializeLongString(is);
421 else if(version == 1){
422 name = deSerializeString(is);
423 state = deSerializeLongString(is);
425 velocity = readV3F1000(is);
430 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
431 <<state<<"\")"<<std::endl;
432 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
434 sao->m_velocity = velocity;
439 void LuaEntitySAO::step(float dtime, bool send_recommended)
441 if(!m_properties_sent)
443 m_properties_sent = true;
444 std::string str = getPropertyPacket();
445 // create message and add to list
446 ActiveObjectMessage aom(getId(), true, str);
447 m_messages_out.push_back(aom);
450 m_last_sent_position_timer += dtime;
453 core::aabbox3d<f32> box = m_prop.collisionbox;
456 collisionMoveResult moveresult;
457 f32 pos_max_d = BS*0.25; // Distance per iteration
458 f32 stepheight = 0; // Maximum climbable step height
459 v3f p_pos = m_base_position;
460 v3f p_velocity = m_velocity;
461 v3f p_acceleration = m_acceleration;
462 IGameDef *gamedef = m_env->getGameDef();
463 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
464 pos_max_d, box, stepheight, dtime,
465 p_pos, p_velocity, p_acceleration);
467 m_base_position = p_pos;
468 m_velocity = p_velocity;
469 m_acceleration = p_acceleration;
471 m_base_position += dtime * m_velocity + 0.5 * dtime
472 * dtime * m_acceleration;
473 m_velocity += dtime * m_acceleration;
477 lua_State *L = m_env->getLua();
478 scriptapi_luaentity_step(L, m_id, dtime);
481 if(send_recommended == false)
484 // TODO: force send when acceleration changes enough?
485 float minchange = 0.2*BS;
486 if(m_last_sent_position_timer > 1.0){
488 } else if(m_last_sent_position_timer > 0.2){
491 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
492 move_d += m_last_sent_move_precision;
493 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
494 if(move_d > minchange || vel_d > minchange ||
495 fabs(m_yaw - m_last_sent_yaw) > 1.0){
496 sendPosition(true, false);
499 if(m_armor_groups_sent == false){
500 m_armor_groups_sent = true;
501 std::string str = gob_cmd_update_armor_groups(
503 // create message and add to list
504 ActiveObjectMessage aom(getId(), true, str);
505 m_messages_out.push_back(aom);
509 std::string LuaEntitySAO::getClientInitializationData()
511 std::ostringstream os(std::ios::binary);
512 writeU8(os, 0); // version
513 os<<serializeString(""); // name
514 writeU8(os, 0); // is_player
515 writeV3F1000(os, m_base_position);
516 writeF1000(os, m_yaw);
518 writeU8(os, 2); // number of messages stuffed in here
519 os<<serializeLongString(getPropertyPacket()); // message 1
520 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
525 std::string LuaEntitySAO::getStaticData()
527 verbosestream<<__FUNCTION_NAME<<std::endl;
528 std::ostringstream os(std::ios::binary);
532 os<<serializeString(m_init_name);
535 lua_State *L = m_env->getLua();
536 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
537 os<<serializeLongString(state);
539 os<<serializeLongString(m_init_state);
544 writeV3F1000(os, m_velocity);
546 writeF1000(os, m_yaw);
550 int LuaEntitySAO::punch(v3f dir,
551 const ToolCapabilities *toolcap,
552 ServerActiveObject *puncher,
553 float time_from_last_punch)
556 // Delete unknown LuaEntities when punched
561 ItemStack *punchitem = NULL;
562 ItemStack punchitem_static;
564 punchitem_static = puncher->getWieldedItem();
565 punchitem = &punchitem_static;
568 PunchDamageResult result = getPunchDamage(
572 time_from_last_punch);
576 setHP(getHP() - result.damage);
578 actionstream<<getDescription()<<" punched by "
579 <<puncher->getDescription()<<", damage "<<result.damage
580 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
583 std::string str = gob_cmd_punched(result.damage, getHP());
584 // create message and add to list
585 ActiveObjectMessage aom(getId(), true, str);
586 m_messages_out.push_back(aom);
593 lua_State *L = m_env->getLua();
594 scriptapi_luaentity_punch(L, m_id, puncher,
595 time_from_last_punch, toolcap, dir);
600 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
604 lua_State *L = m_env->getLua();
605 scriptapi_luaentity_rightclick(L, m_id, clicker);
608 void LuaEntitySAO::setPos(v3f pos)
610 m_base_position = pos;
611 sendPosition(false, true);
614 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
616 m_base_position = pos;
618 sendPosition(true, true);
621 float LuaEntitySAO::getMinimumSavedMovement()
626 std::string LuaEntitySAO::getDescription()
628 std::ostringstream os(std::ios::binary);
629 os<<"LuaEntitySAO at (";
630 os<<(m_base_position.X/BS)<<",";
631 os<<(m_base_position.Y/BS)<<",";
632 os<<(m_base_position.Z/BS);
637 void LuaEntitySAO::setHP(s16 hp)
643 s16 LuaEntitySAO::getHP() const
648 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
650 m_armor_groups = armor_groups;
651 m_armor_groups_sent = false;
654 ObjectProperties* LuaEntitySAO::accessObjectProperties()
659 void LuaEntitySAO::notifyObjectPropertiesModified()
661 m_properties_sent = false;
664 void LuaEntitySAO::setVelocity(v3f velocity)
666 m_velocity = velocity;
669 v3f LuaEntitySAO::getVelocity()
674 void LuaEntitySAO::setAcceleration(v3f acceleration)
676 m_acceleration = acceleration;
679 v3f LuaEntitySAO::getAcceleration()
681 return m_acceleration;
684 void LuaEntitySAO::setYaw(float yaw)
689 float LuaEntitySAO::getYaw()
694 void LuaEntitySAO::setTextureMod(const std::string &mod)
696 std::string str = gob_cmd_set_texture_mod(mod);
697 // create message and add to list
698 ActiveObjectMessage aom(getId(), true, str);
699 m_messages_out.push_back(aom);
702 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
703 bool select_horiz_by_yawpitch)
705 std::string str = gob_cmd_set_sprite(
709 select_horiz_by_yawpitch
711 // create message and add to list
712 ActiveObjectMessage aom(getId(), true, str);
713 m_messages_out.push_back(aom);
716 std::string LuaEntitySAO::getName()
721 std::string LuaEntitySAO::getPropertyPacket()
723 return gob_cmd_set_properties(m_prop);
726 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
728 m_last_sent_move_precision = m_base_position.getDistanceFrom(
729 m_last_sent_position);
730 m_last_sent_position_timer = 0;
731 m_last_sent_yaw = m_yaw;
732 m_last_sent_position = m_base_position;
733 m_last_sent_velocity = m_velocity;
734 //m_last_sent_acceleration = m_acceleration;
736 float update_interval = m_env->getSendRecommendedInterval();
738 std::string str = gob_cmd_update_position(
747 // create message and add to list
748 ActiveObjectMessage aom(getId(), false, str);
749 m_messages_out.push_back(aom);
756 // No prototype, PlayerSAO does not need to be deserialized
758 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
759 const std::set<std::string> &privs, bool is_singleplayer):
760 ServerActiveObject(env_, v3f(0,0,0)),
764 m_last_good_position(0,0,0),
765 m_last_good_position_age(0),
766 m_time_from_last_punch(0),
767 m_nocheat_dig_pos(32767, 32767, 32767),
768 m_nocheat_dig_time(0),
770 m_position_not_sent(false),
771 m_armor_groups_sent(false),
772 m_properties_sent(true),
774 m_is_singleplayer(is_singleplayer),
777 m_inventory_not_sent(false),
778 m_hp_not_sent(false),
779 m_wielded_item_not_sent(false)
782 assert(m_peer_id != 0);
783 setBasePosition(m_player->getPosition());
784 m_inventory = &m_player->inventory;
785 m_armor_groups["choppy"] = 2;
786 m_armor_groups["fleshy"] = 3;
788 m_prop.hp_max = PLAYER_MAX_HP;
789 m_prop.physical = false;
791 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
792 m_prop.visual = "upright_sprite";
793 m_prop.visual_size = v2f(1, 2);
794 m_prop.textures.clear();
795 m_prop.textures.push_back("player.png");
796 m_prop.textures.push_back("player_back.png");
797 m_prop.spritediv = v2s16(1,1);
798 m_prop.is_visible = (getHP() != 0);
799 m_prop.makes_footstep_sound = true;
802 PlayerSAO::~PlayerSAO()
804 if(m_inventory != &m_player->inventory)
809 std::string PlayerSAO::getDescription()
811 return std::string("player ") + m_player->getName();
814 // Called after id has been set and has been inserted in environment
815 void PlayerSAO::addedToEnvironment()
817 ServerActiveObject::addedToEnvironment();
818 ServerActiveObject::setBasePosition(m_player->getPosition());
819 m_player->setPlayerSAO(this);
820 m_player->peer_id = m_peer_id;
821 m_last_good_position = m_player->getPosition();
822 m_last_good_position_age = 0.0;
825 // Called before removing from environment
826 void PlayerSAO::removingFromEnvironment()
828 ServerActiveObject::removingFromEnvironment();
829 if(m_player->getPlayerSAO() == this)
831 m_player->setPlayerSAO(NULL);
832 m_player->peer_id = 0;
836 bool PlayerSAO::isStaticAllowed() const
841 bool PlayerSAO::unlimitedTransferDistance() const
843 return g_settings->getBool("unlimited_player_transfer_distance");
846 std::string PlayerSAO::getClientInitializationData()
848 std::ostringstream os(std::ios::binary);
849 writeU8(os, 0); // version
850 os<<serializeString(m_player->getName()); // name
851 writeU8(os, 1); // is_player
852 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
853 writeF1000(os, m_player->getYaw());
854 writeS16(os, getHP());
855 writeU8(os, 2); // number of messages stuffed in here
856 os<<serializeLongString(getPropertyPacket()); // message 1
857 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
861 std::string PlayerSAO::getStaticData()
867 void PlayerSAO::step(float dtime, bool send_recommended)
869 if(!m_properties_sent)
871 m_properties_sent = true;
872 std::string str = getPropertyPacket();
873 // create message and add to list
874 ActiveObjectMessage aom(getId(), true, str);
875 m_messages_out.push_back(aom);
878 m_time_from_last_punch += dtime;
879 m_nocheat_dig_time += dtime;
881 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
883 m_last_good_position = m_player->getPosition();
884 m_last_good_position_age = 0;
889 Check player movements
891 NOTE: Actually the server should handle player physics like the
892 client does and compare player's position to what is calculated
893 on our side. This is required when eg. players fly due to an
894 explosion. Altough a node-based alternative might be possible
895 too, and much more lightweight.
898 float player_max_speed = 0;
899 float player_max_speed_up = 0;
900 if(m_privs.count("fast") != 0){
902 player_max_speed = BS * 20;
903 player_max_speed_up = BS * 20;
906 player_max_speed = BS * 4.0;
907 player_max_speed_up = BS * 4.0;
910 player_max_speed *= 2.5;
911 player_max_speed_up *= 2.5;
913 m_last_good_position_age += dtime;
914 if(m_last_good_position_age >= 1.0){
915 float age = m_last_good_position_age;
916 v3f diff = (m_player->getPosition() - m_last_good_position);
917 float d_vert = diff.Y;
919 float d_horiz = diff.getLength();
920 /*infostream<<m_player->getName()<<"'s horizontal speed is "
921 <<(d_horiz/age)<<std::endl;*/
922 if(d_horiz <= age * player_max_speed &&
923 (d_vert < 0 || d_vert < age * player_max_speed_up)){
924 m_last_good_position = m_player->getPosition();
926 actionstream<<"Player "<<m_player->getName()
927 <<" moved too fast; resetting position"
929 m_player->setPosition(m_last_good_position);
932 m_last_good_position_age = 0;
936 if(send_recommended == false)
939 if(m_position_not_sent)
941 m_position_not_sent = false;
942 float update_interval = m_env->getSendRecommendedInterval();
943 std::string str = gob_cmd_update_position(
944 m_player->getPosition() + v3f(0,BS*1,0),
952 // create message and add to list
953 ActiveObjectMessage aom(getId(), false, str);
954 m_messages_out.push_back(aom);
957 if(m_wielded_item_not_sent)
959 m_wielded_item_not_sent = false;
960 // GenericCAO has no special way to show this
963 if(m_armor_groups_sent == false){
964 m_armor_groups_sent = true;
965 std::string str = gob_cmd_update_armor_groups(
967 // create message and add to list
968 ActiveObjectMessage aom(getId(), true, str);
969 m_messages_out.push_back(aom);
973 void PlayerSAO::setBasePosition(const v3f &position)
975 ServerActiveObject::setBasePosition(position);
976 m_position_not_sent = true;
979 void PlayerSAO::setPos(v3f pos)
981 m_player->setPosition(pos);
982 // Movement caused by this command is always valid
983 m_last_good_position = pos;
984 m_last_good_position_age = 0;
985 // Force position change on client
989 void PlayerSAO::moveTo(v3f pos, bool continuous)
991 m_player->setPosition(pos);
992 // Movement caused by this command is always valid
993 m_last_good_position = pos;
994 m_last_good_position_age = 0;
995 // Force position change on client
999 int PlayerSAO::punch(v3f dir,
1000 const ToolCapabilities *toolcap,
1001 ServerActiveObject *puncher,
1002 float time_from_last_punch)
1007 // No effect if PvP disabled
1008 if(g_settings->getBool("enable_pvp") == false){
1009 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1010 std::string str = gob_cmd_punched(0, getHP());
1011 // create message and add to list
1012 ActiveObjectMessage aom(getId(), true, str);
1013 m_messages_out.push_back(aom);
1018 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1019 time_from_last_punch);
1021 actionstream<<"Player "<<m_player->getName()<<" punched by "
1022 <<puncher->getDescription()<<", damage "<<hitparams.hp
1025 setHP(getHP() - hitparams.hp);
1027 if(hitparams.hp != 0)
1029 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1030 // create message and add to list
1031 ActiveObjectMessage aom(getId(), true, str);
1032 m_messages_out.push_back(aom);
1035 return hitparams.wear;
1038 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1042 s16 PlayerSAO::getHP() const
1044 return m_player->hp;
1047 void PlayerSAO::setHP(s16 hp)
1049 s16 oldhp = m_player->hp;
1053 else if(hp > PLAYER_MAX_HP)
1056 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1058 m_hp_not_sent = true; // fix wrong prediction on client
1065 m_hp_not_sent = true;
1067 // On death or reincarnation send an active object message
1068 if((hp == 0) != (oldhp == 0))
1070 // Will send new is_visible value based on (getHP()!=0)
1071 m_properties_sent = false;
1073 std::string str = gob_cmd_punched(0, getHP());
1074 ActiveObjectMessage aom(getId(), true, str);
1075 m_messages_out.push_back(aom);
1079 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1081 m_armor_groups = armor_groups;
1082 m_armor_groups_sent = false;
1085 ObjectProperties* PlayerSAO::accessObjectProperties()
1090 void PlayerSAO::notifyObjectPropertiesModified()
1092 m_properties_sent = false;
1095 Inventory* PlayerSAO::getInventory()
1099 const Inventory* PlayerSAO::getInventory() const
1104 InventoryLocation PlayerSAO::getInventoryLocation() const
1106 InventoryLocation loc;
1107 loc.setPlayer(m_player->getName());
1111 void PlayerSAO::setInventoryModified()
1113 m_inventory_not_sent = true;
1116 std::string PlayerSAO::getWieldList() const
1121 int PlayerSAO::getWieldIndex() const
1123 return m_wield_index;
1126 void PlayerSAO::setWieldIndex(int i)
1128 if(i != m_wield_index)
1131 m_wielded_item_not_sent = true;
1135 void PlayerSAO::disconnected()
1139 if(m_player->getPlayerSAO() == this)
1141 m_player->setPlayerSAO(NULL);
1142 m_player->peer_id = 0;
1146 void PlayerSAO::createCreativeInventory()
1148 if(m_inventory != &m_player->inventory)
1151 m_inventory = new Inventory(m_player->inventory);
1152 m_inventory->clearContents();
1153 scriptapi_get_creative_inventory(m_env->getLua(), this);
1156 std::string PlayerSAO::getPropertyPacket()
1158 m_prop.is_visible = (getHP() != 0);
1159 return gob_cmd_set_properties(m_prop);