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"
33 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
39 class DummyLoadSAO : public ServerActiveObject
42 DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type):
43 ServerActiveObject(env, pos)
45 ServerActiveObject::registerType(type, create);
47 // Pretend to be the test object (to fool the client)
49 { return ACTIVEOBJECT_TYPE_TEST; }
50 // And never save to disk
51 bool isStaticAllowed() const
54 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
55 const std::string &data)
57 return new DummyLoadSAO(env, pos, 0);
60 void step(float dtime, bool send_recommended)
63 infostream<<"DummyLoadSAO step"<<std::endl;
69 // Prototype (registers item for deserialization)
70 DummyLoadSAO proto1_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_RAT);
71 DummyLoadSAO proto2_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_OERKKI1);
72 DummyLoadSAO proto3_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_FIREFLY);
73 DummyLoadSAO proto4_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_MOBV2);
79 class TestSAO : public ServerActiveObject
82 TestSAO(ServerEnvironment *env, v3f pos):
83 ServerActiveObject(env, pos),
87 ServerActiveObject::registerType(getType(), create);
90 { return ACTIVEOBJECT_TYPE_TEST; }
92 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
93 const std::string &data)
95 return new TestSAO(env, pos);
98 void step(float dtime, bool send_recommended)
107 m_base_position.Y += dtime * BS * 2;
108 if(m_base_position.Y > 8*BS)
109 m_base_position.Y = 2*BS;
111 if(send_recommended == false)
121 data += itos(0); // 0 = position
123 data += itos(m_base_position.X);
125 data += itos(m_base_position.Y);
127 data += itos(m_base_position.Z);
129 ActiveObjectMessage aom(getId(), false, data);
130 m_messages_out.push_back(aom);
139 // Prototype (registers item for deserialization)
140 TestSAO proto_TestSAO(NULL, v3f(0,0,0));
145 DEPRECATED: New dropped items are implemented in Lua; see
146 builtin/item_entity.lua.
149 class ItemSAO : public ServerActiveObject
153 { return ACTIVEOBJECT_TYPE_ITEM; }
155 float getMinimumSavedMovement()
158 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
159 const std::string &data)
161 std::istringstream is(data, std::ios::binary);
166 // check if version is supported
169 std::string itemstring = deSerializeString(is);
170 infostream<<"create(): Creating item \""
171 <<itemstring<<"\""<<std::endl;
172 return new ItemSAO(env, pos, itemstring);
175 ItemSAO(ServerEnvironment *env, v3f pos,
176 const std::string itemstring):
177 ServerActiveObject(env, pos),
178 m_itemstring(itemstring),
179 m_itemstring_changed(false),
181 m_last_sent_position(0,0,0)
183 ServerActiveObject::registerType(getType(), create);
186 void step(float dtime, bool send_recommended)
188 ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
192 const float interval = 0.2;
193 if(m_move_interval.step(dtime, interval)==false)
197 core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
198 collisionMoveResult moveresult;
200 m_speed_f += v3f(0, -dtime*9.81*BS, 0);
201 // Maximum movement without glitches
202 f32 pos_max_d = BS*0.25;
204 if(m_speed_f.getLength()*dtime > pos_max_d)
205 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
206 v3f pos_f = getBasePosition();
207 v3f pos_f_old = pos_f;
208 IGameDef *gamedef = m_env->getGameDef();
209 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
210 pos_max_d, box, dtime, pos_f, m_speed_f);
212 if(send_recommended == false)
215 if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
217 setBasePosition(pos_f);
218 m_last_sent_position = pos_f;
220 std::ostringstream os(std::ios::binary);
221 // command (0 = update position)
224 writeV3F1000(os, m_base_position);
225 // create message and add to list
226 ActiveObjectMessage aom(getId(), false, os.str());
227 m_messages_out.push_back(aom);
229 if(m_itemstring_changed)
231 m_itemstring_changed = false;
233 std::ostringstream os(std::ios::binary);
234 // command (1 = update itemstring)
237 os<<serializeString(m_itemstring);
238 // create message and add to list
239 ActiveObjectMessage aom(getId(), false, os.str());
240 m_messages_out.push_back(aom);
244 std::string getClientInitializationData()
246 std::ostringstream os(std::ios::binary);
250 writeV3F1000(os, m_base_position);
252 os<<serializeString(m_itemstring);
256 std::string getStaticData()
258 infostream<<__FUNCTION_NAME<<std::endl;
259 std::ostringstream os(std::ios::binary);
263 os<<serializeString(m_itemstring);
267 ItemStack createItemStack()
270 IItemDefManager *idef = m_env->getGameDef()->idef();
272 item.deSerialize(m_itemstring, idef);
273 infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
274 <<"\" -> item=\""<<item.getItemString()<<"\""
278 catch(SerializationError &e)
280 infostream<<__FUNCTION_NAME<<": serialization error: "
281 <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
287 const ToolCapabilities *toolcap,
288 ServerActiveObject *puncher,
289 float time_from_last_punch)
291 // Directly delete item in creative mode
292 if(g_settings->getBool("creative_mode") == true)
298 // Take item into inventory
299 ItemStack item = createItemStack();
300 Inventory *inv = puncher->getInventory();
303 std::string wieldlist = puncher->getWieldList();
304 ItemStack leftover = inv->addItem(wieldlist, item);
305 puncher->setInventoryModified();
312 m_itemstring = leftover.getItemString();
313 m_itemstring_changed = true;
322 std::string m_itemstring;
323 bool m_itemstring_changed;
325 v3f m_last_sent_position;
326 IntervalLimiter m_move_interval;
329 // Prototype (registers item for deserialization)
330 ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
332 ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
333 const std::string itemstring)
335 return new ItemSAO(env, pos, itemstring);
342 // Prototype (registers item for deserialization)
343 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
345 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
346 const std::string &name, const std::string &state):
347 ServerActiveObject(env, pos),
353 m_acceleration(0,0,0),
355 m_properties_sent(true),
357 m_last_sent_position(0,0,0),
358 m_last_sent_velocity(0,0,0),
359 m_last_sent_position_timer(0),
360 m_last_sent_move_precision(0),
361 m_armor_groups_sent(false)
363 // Only register type if no environment supplied
365 ServerActiveObject::registerType(getType(), create);
369 // Initialize something to armor groups
370 m_armor_groups["fleshy"] = 3;
371 m_armor_groups["snappy"] = 2;
374 LuaEntitySAO::~LuaEntitySAO()
377 lua_State *L = m_env->getLua();
378 scriptapi_luaentity_rm(L, m_id);
382 void LuaEntitySAO::addedToEnvironment()
384 ServerActiveObject::addedToEnvironment();
386 // Create entity from name
387 lua_State *L = m_env->getLua();
388 m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
392 scriptapi_luaentity_get_properties(L, m_id, &m_prop);
393 // Initialize HP from properties
394 m_hp = m_prop.hp_max;
395 // Activate entity, supplying serialized state
396 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
400 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
401 const std::string &data)
409 std::istringstream is(data, std::ios::binary);
411 u8 version = readU8(is);
412 // check if version is supported
414 name = deSerializeString(is);
415 state = deSerializeLongString(is);
417 else if(version == 1){
418 name = deSerializeString(is);
419 state = deSerializeLongString(is);
421 velocity = readV3F1000(is);
426 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
427 <<state<<"\")"<<std::endl;
428 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
430 sao->m_velocity = velocity;
435 void LuaEntitySAO::step(float dtime, bool send_recommended)
437 if(!m_properties_sent)
439 m_properties_sent = true;
440 std::string str = getPropertyPacket();
441 // create message and add to list
442 ActiveObjectMessage aom(getId(), true, str);
443 m_messages_out.push_back(aom);
446 m_last_sent_position_timer += dtime;
449 core::aabbox3d<f32> box = m_prop.collisionbox;
452 collisionMoveResult moveresult;
453 f32 pos_max_d = BS*0.25; // Distance per iteration
454 v3f p_pos = getBasePosition();
455 v3f p_velocity = m_velocity;
456 IGameDef *gamedef = m_env->getGameDef();
457 moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
458 pos_max_d, box, dtime, p_pos, p_velocity);
460 setBasePosition(p_pos);
461 m_velocity = p_velocity;
463 m_velocity += dtime * m_acceleration;
465 m_base_position += dtime * m_velocity + 0.5 * dtime
466 * dtime * m_acceleration;
467 m_velocity += dtime * m_acceleration;
471 lua_State *L = m_env->getLua();
472 scriptapi_luaentity_step(L, m_id, dtime);
475 if(send_recommended == false)
478 // TODO: force send when acceleration changes enough?
479 float minchange = 0.2*BS;
480 if(m_last_sent_position_timer > 1.0){
482 } else if(m_last_sent_position_timer > 0.2){
485 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
486 move_d += m_last_sent_move_precision;
487 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
488 if(move_d > minchange || vel_d > minchange ||
489 fabs(m_yaw - m_last_sent_yaw) > 1.0){
490 sendPosition(true, false);
493 if(m_armor_groups_sent == false){
494 m_armor_groups_sent = true;
495 std::string str = gob_cmd_update_armor_groups(
497 // create message and add to list
498 ActiveObjectMessage aom(getId(), true, str);
499 m_messages_out.push_back(aom);
503 std::string LuaEntitySAO::getClientInitializationData()
505 std::ostringstream os(std::ios::binary);
506 writeU8(os, 0); // version
507 os<<serializeString(""); // name
508 writeU8(os, 0); // is_player
509 writeV3F1000(os, m_base_position);
510 writeF1000(os, m_yaw);
512 writeU8(os, 2); // number of messages stuffed in here
513 os<<serializeLongString(getPropertyPacket()); // message 1
514 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
519 std::string LuaEntitySAO::getStaticData()
521 verbosestream<<__FUNCTION_NAME<<std::endl;
522 std::ostringstream os(std::ios::binary);
526 os<<serializeString(m_init_name);
529 lua_State *L = m_env->getLua();
530 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
531 os<<serializeLongString(state);
533 os<<serializeLongString(m_init_state);
538 writeV3F1000(os, m_velocity);
540 writeF1000(os, m_yaw);
544 int LuaEntitySAO::punch(v3f dir,
545 const ToolCapabilities *toolcap,
546 ServerActiveObject *puncher,
547 float time_from_last_punch)
550 // Delete unknown LuaEntities when punched
555 ItemStack *punchitem = NULL;
556 ItemStack punchitem_static;
558 punchitem_static = puncher->getWieldedItem();
559 punchitem = &punchitem_static;
562 PunchDamageResult result = getPunchDamage(
566 time_from_last_punch);
570 setHP(getHP() - result.damage);
572 actionstream<<getDescription()<<" punched by "
573 <<puncher->getDescription()<<", damage "<<result.damage
574 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
577 std::string str = gob_cmd_punched(result.damage, getHP());
578 // create message and add to list
579 ActiveObjectMessage aom(getId(), true, str);
580 m_messages_out.push_back(aom);
587 lua_State *L = m_env->getLua();
588 scriptapi_luaentity_punch(L, m_id, puncher,
589 time_from_last_punch, toolcap, dir);
594 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
598 lua_State *L = m_env->getLua();
599 scriptapi_luaentity_rightclick(L, m_id, clicker);
602 void LuaEntitySAO::setPos(v3f pos)
604 m_base_position = pos;
605 sendPosition(false, true);
608 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
610 m_base_position = pos;
612 sendPosition(true, true);
615 float LuaEntitySAO::getMinimumSavedMovement()
620 std::string LuaEntitySAO::getDescription()
622 std::ostringstream os(std::ios::binary);
623 os<<"LuaEntitySAO at (";
624 os<<(m_base_position.X/BS)<<",";
625 os<<(m_base_position.Y/BS)<<",";
626 os<<(m_base_position.Z/BS);
631 void LuaEntitySAO::setHP(s16 hp)
637 s16 LuaEntitySAO::getHP() const
642 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
644 m_armor_groups = armor_groups;
645 m_armor_groups_sent = false;
648 ObjectProperties* LuaEntitySAO::accessObjectProperties()
653 void LuaEntitySAO::notifyObjectPropertiesModified()
655 m_properties_sent = false;
658 void LuaEntitySAO::setVelocity(v3f velocity)
660 m_velocity = velocity;
663 v3f LuaEntitySAO::getVelocity()
668 void LuaEntitySAO::setAcceleration(v3f acceleration)
670 m_acceleration = acceleration;
673 v3f LuaEntitySAO::getAcceleration()
675 return m_acceleration;
678 void LuaEntitySAO::setYaw(float yaw)
683 float LuaEntitySAO::getYaw()
688 void LuaEntitySAO::setTextureMod(const std::string &mod)
690 std::string str = gob_cmd_set_texture_mod(mod);
691 // create message and add to list
692 ActiveObjectMessage aom(getId(), true, str);
693 m_messages_out.push_back(aom);
696 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
697 bool select_horiz_by_yawpitch)
699 std::string str = gob_cmd_set_sprite(
703 select_horiz_by_yawpitch
705 // create message and add to list
706 ActiveObjectMessage aom(getId(), true, str);
707 m_messages_out.push_back(aom);
710 std::string LuaEntitySAO::getName()
715 std::string LuaEntitySAO::getPropertyPacket()
717 return gob_cmd_set_properties(m_prop);
720 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
722 m_last_sent_move_precision = m_base_position.getDistanceFrom(
723 m_last_sent_position);
724 m_last_sent_position_timer = 0;
725 m_last_sent_yaw = m_yaw;
726 m_last_sent_position = m_base_position;
727 m_last_sent_velocity = m_velocity;
728 //m_last_sent_acceleration = m_acceleration;
730 float update_interval = m_env->getSendRecommendedInterval();
732 std::string str = gob_cmd_update_position(
741 // create message and add to list
742 ActiveObjectMessage aom(getId(), false, str);
743 m_messages_out.push_back(aom);
750 // No prototype, PlayerSAO does not need to be deserialized
752 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
753 const std::set<std::string> &privs, bool is_singleplayer):
754 ServerActiveObject(env_, v3f(0,0,0)),
758 m_last_good_position(0,0,0),
759 m_last_good_position_age(0),
760 m_time_from_last_punch(0),
762 m_position_not_sent(false),
763 m_armor_groups_sent(false),
764 m_properties_sent(true),
766 m_is_singleplayer(is_singleplayer),
769 m_inventory_not_sent(false),
770 m_hp_not_sent(false),
771 m_wielded_item_not_sent(false)
774 assert(m_peer_id != 0);
775 setBasePosition(m_player->getPosition());
776 m_inventory = &m_player->inventory;
777 m_armor_groups["choppy"] = 2;
778 m_armor_groups["fleshy"] = 3;
780 m_prop.hp_max = PLAYER_MAX_HP;
781 m_prop.physical = false;
783 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
784 m_prop.visual = "upright_sprite";
785 m_prop.visual_size = v2f(1, 2);
786 m_prop.textures.clear();
787 m_prop.textures.push_back("player.png");
788 m_prop.textures.push_back("player_back.png");
789 m_prop.spritediv = v2s16(1,1);
790 m_prop.is_visible = (getHP() != 0);
791 m_prop.makes_footstep_sound = true;
794 PlayerSAO::~PlayerSAO()
796 if(m_inventory != &m_player->inventory)
801 std::string PlayerSAO::getDescription()
803 return std::string("player ") + m_player->getName();
806 // Called after id has been set and has been inserted in environment
807 void PlayerSAO::addedToEnvironment()
809 ServerActiveObject::addedToEnvironment();
810 ServerActiveObject::setBasePosition(m_player->getPosition());
811 m_player->setPlayerSAO(this);
812 m_player->peer_id = m_peer_id;
813 m_last_good_position = m_player->getPosition();
814 m_last_good_position_age = 0.0;
817 // Called before removing from environment
818 void PlayerSAO::removingFromEnvironment()
820 ServerActiveObject::removingFromEnvironment();
821 if(m_player->getPlayerSAO() == this)
823 m_player->setPlayerSAO(NULL);
824 m_player->peer_id = 0;
828 bool PlayerSAO::isStaticAllowed() const
833 bool PlayerSAO::unlimitedTransferDistance() const
835 return g_settings->getBool("unlimited_player_transfer_distance");
838 std::string PlayerSAO::getClientInitializationData()
840 std::ostringstream os(std::ios::binary);
841 writeU8(os, 0); // version
842 os<<serializeString(m_player->getName()); // name
843 writeU8(os, 1); // is_player
844 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
845 writeF1000(os, m_player->getYaw());
846 writeS16(os, getHP());
847 writeU8(os, 2); // number of messages stuffed in here
848 os<<serializeLongString(getPropertyPacket()); // message 1
849 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
853 std::string PlayerSAO::getStaticData()
859 void PlayerSAO::step(float dtime, bool send_recommended)
861 if(!m_properties_sent)
863 m_properties_sent = true;
864 std::string str = getPropertyPacket();
865 // create message and add to list
866 ActiveObjectMessage aom(getId(), true, str);
867 m_messages_out.push_back(aom);
870 m_time_from_last_punch += dtime;
872 if(m_is_singleplayer)
874 m_last_good_position = m_player->getPosition();
875 m_last_good_position_age = 0;
880 Check player movements
882 NOTE: Actually the server should handle player physics like the
883 client does and compare player's position to what is calculated
884 on our side. This is required when eg. players fly due to an
888 float player_max_speed = 0;
889 float player_max_speed_up = 0;
890 if(m_privs.count("fast") != 0){
892 player_max_speed = BS * 20;
893 player_max_speed_up = BS * 20;
896 player_max_speed = BS * 4.0;
897 player_max_speed_up = BS * 4.0;
900 player_max_speed *= 2.5;
901 player_max_speed_up *= 2.5;
903 m_last_good_position_age += dtime;
904 if(m_last_good_position_age >= 1.0){
905 float age = m_last_good_position_age;
906 v3f diff = (m_player->getPosition() - m_last_good_position);
907 float d_vert = diff.Y;
909 float d_horiz = diff.getLength();
910 /*infostream<<m_player->getName()<<"'s horizontal speed is "
911 <<(d_horiz/age)<<std::endl;*/
912 if(d_horiz <= age * player_max_speed &&
913 (d_vert < 0 || d_vert < age * player_max_speed_up)){
914 m_last_good_position = m_player->getPosition();
916 actionstream<<"Player "<<m_player->getName()
917 <<" moved too fast; resetting position"
919 m_player->setPosition(m_last_good_position);
922 m_last_good_position_age = 0;
926 if(send_recommended == false)
929 if(m_position_not_sent)
931 m_position_not_sent = false;
932 float update_interval = m_env->getSendRecommendedInterval();
933 std::string str = gob_cmd_update_position(
934 m_player->getPosition() + v3f(0,BS*1,0),
942 // create message and add to list
943 ActiveObjectMessage aom(getId(), false, str);
944 m_messages_out.push_back(aom);
947 if(m_wielded_item_not_sent)
949 m_wielded_item_not_sent = false;
950 // GenericCAO has no special way to show this
953 if(m_armor_groups_sent == false){
954 m_armor_groups_sent = true;
955 std::string str = gob_cmd_update_armor_groups(
957 // create message and add to list
958 ActiveObjectMessage aom(getId(), true, str);
959 m_messages_out.push_back(aom);
963 void PlayerSAO::setBasePosition(const v3f &position)
965 ServerActiveObject::setBasePosition(position);
966 m_position_not_sent = true;
969 void PlayerSAO::setPos(v3f pos)
971 m_player->setPosition(pos);
972 // Movement caused by this command is always valid
973 m_last_good_position = pos;
974 m_last_good_position_age = 0;
975 // Force position change on client
979 void PlayerSAO::moveTo(v3f pos, bool continuous)
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 int PlayerSAO::punch(v3f dir,
990 const ToolCapabilities *toolcap,
991 ServerActiveObject *puncher,
992 float time_from_last_punch)
997 // No effect if PvP disabled
998 if(g_settings->getBool("enable_pvp") == false){
999 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1000 std::string str = gob_cmd_punched(0, getHP());
1001 // create message and add to list
1002 ActiveObjectMessage aom(getId(), true, str);
1003 m_messages_out.push_back(aom);
1008 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1009 time_from_last_punch);
1011 actionstream<<"Player "<<m_player->getName()<<" punched by "
1012 <<puncher->getDescription()<<", damage "<<hitparams.hp
1015 setHP(getHP() - hitparams.hp);
1017 if(hitparams.hp != 0)
1019 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1020 // create message and add to list
1021 ActiveObjectMessage aom(getId(), true, str);
1022 m_messages_out.push_back(aom);
1025 return hitparams.wear;
1028 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1032 s16 PlayerSAO::getHP() const
1034 return m_player->hp;
1037 void PlayerSAO::setHP(s16 hp)
1039 s16 oldhp = m_player->hp;
1043 else if(hp > PLAYER_MAX_HP)
1046 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1048 m_hp_not_sent = true; // fix wrong prediction on client
1055 m_hp_not_sent = true;
1057 // On death or reincarnation send an active object message
1058 if((hp == 0) != (oldhp == 0))
1060 // Will send new is_visible value based on (getHP()!=0)
1061 m_properties_sent = false;
1063 std::string str = gob_cmd_punched(0, getHP());
1064 ActiveObjectMessage aom(getId(), true, str);
1065 m_messages_out.push_back(aom);
1069 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1071 m_armor_groups = armor_groups;
1072 m_armor_groups_sent = false;
1075 ObjectProperties* PlayerSAO::accessObjectProperties()
1080 void PlayerSAO::notifyObjectPropertiesModified()
1082 m_properties_sent = false;
1085 Inventory* PlayerSAO::getInventory()
1089 const Inventory* PlayerSAO::getInventory() const
1094 InventoryLocation PlayerSAO::getInventoryLocation() const
1096 InventoryLocation loc;
1097 loc.setPlayer(m_player->getName());
1101 void PlayerSAO::setInventoryModified()
1103 m_inventory_not_sent = true;
1106 std::string PlayerSAO::getWieldList() const
1111 int PlayerSAO::getWieldIndex() const
1113 return m_wield_index;
1116 void PlayerSAO::setWieldIndex(int i)
1118 if(i != m_wield_index)
1121 m_wielded_item_not_sent = true;
1125 void PlayerSAO::disconnected()
1129 if(m_player->getPlayerSAO() == this)
1131 m_player->setPlayerSAO(NULL);
1132 m_player->peer_id = 0;
1136 void PlayerSAO::createCreativeInventory()
1138 if(m_inventory != &m_player->inventory)
1141 m_inventory = new Inventory(m_player->inventory);
1142 m_inventory->clearContents();
1143 scriptapi_get_creative_inventory(m_env->getLua(), this);
1146 std::string PlayerSAO::getPropertyPacket()
1148 m_prop.is_visible = (getHP() != 0);
1149 return gob_cmd_set_properties(m_prop);