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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU 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));
146 class ItemSAO : public ServerActiveObject
150 { return ACTIVEOBJECT_TYPE_ITEM; }
152 float getMinimumSavedMovement()
155 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
156 const std::string &data)
158 std::istringstream is(data, std::ios::binary);
163 // check if version is supported
166 std::string itemstring = deSerializeString(is);
167 infostream<<"create(): Creating item \""
168 <<itemstring<<"\""<<std::endl;
169 return new ItemSAO(env, pos, itemstring);
172 ItemSAO(ServerEnvironment *env, v3f pos,
173 const std::string itemstring):
174 ServerActiveObject(env, pos),
175 m_itemstring(itemstring),
176 m_itemstring_changed(false),
178 m_last_sent_position(0,0,0)
180 ServerActiveObject::registerType(getType(), create);
183 void step(float dtime, bool send_recommended)
185 ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
189 const float interval = 0.2;
190 if(m_move_interval.step(dtime, interval)==false)
194 core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
195 collisionMoveResult moveresult;
197 m_speed_f += v3f(0, -dtime*9.81*BS, 0);
198 // Maximum movement without glitches
199 f32 pos_max_d = BS*0.25;
201 if(m_speed_f.getLength()*dtime > pos_max_d)
202 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
203 v3f pos_f = getBasePosition();
204 v3f pos_f_old = pos_f;
205 IGameDef *gamedef = m_env->getGameDef();
206 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
207 pos_max_d, box, dtime, pos_f, m_speed_f);
209 if(send_recommended == false)
212 if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
214 setBasePosition(pos_f);
215 m_last_sent_position = pos_f;
217 std::ostringstream os(std::ios::binary);
218 // command (0 = update position)
221 writeV3F1000(os, m_base_position);
222 // create message and add to list
223 ActiveObjectMessage aom(getId(), false, os.str());
224 m_messages_out.push_back(aom);
226 if(m_itemstring_changed)
228 m_itemstring_changed = false;
230 std::ostringstream os(std::ios::binary);
231 // command (1 = update itemstring)
234 os<<serializeString(m_itemstring);
235 // create message and add to list
236 ActiveObjectMessage aom(getId(), false, os.str());
237 m_messages_out.push_back(aom);
241 std::string getClientInitializationData()
243 std::ostringstream os(std::ios::binary);
247 writeV3F1000(os, m_base_position);
249 os<<serializeString(m_itemstring);
253 std::string getStaticData()
255 infostream<<__FUNCTION_NAME<<std::endl;
256 std::ostringstream os(std::ios::binary);
260 os<<serializeString(m_itemstring);
264 ItemStack createItemStack()
267 IItemDefManager *idef = m_env->getGameDef()->idef();
269 item.deSerialize(m_itemstring, idef);
270 infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
271 <<"\" -> item=\""<<item.getItemString()<<"\""
275 catch(SerializationError &e)
277 infostream<<__FUNCTION_NAME<<": serialization error: "
278 <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
284 const ToolCapabilities *toolcap,
285 ServerActiveObject *puncher,
286 float time_from_last_punch)
288 // Directly delete item in creative mode
289 if(g_settings->getBool("creative_mode") == true)
295 // Take item into inventory
296 ItemStack item = createItemStack();
297 Inventory *inv = puncher->getInventory();
300 std::string wieldlist = puncher->getWieldList();
301 ItemStack leftover = inv->addItem(wieldlist, item);
302 puncher->setInventoryModified();
309 m_itemstring = leftover.getItemString();
310 m_itemstring_changed = true;
319 std::string m_itemstring;
320 bool m_itemstring_changed;
322 v3f m_last_sent_position;
323 IntervalLimiter m_move_interval;
326 // Prototype (registers item for deserialization)
327 ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
329 ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
330 const std::string itemstring)
332 return new ItemSAO(env, pos, itemstring);
339 // Prototype (registers item for deserialization)
340 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
342 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
343 const std::string &name, const std::string &state):
344 ServerActiveObject(env, pos),
350 m_acceleration(0,0,0),
352 m_properties_sent(true),
354 m_last_sent_position(0,0,0),
355 m_last_sent_velocity(0,0,0),
356 m_last_sent_position_timer(0),
357 m_last_sent_move_precision(0),
358 m_armor_groups_sent(false)
360 // Only register type if no environment supplied
362 ServerActiveObject::registerType(getType(), create);
366 // Initialize something to armor groups
367 m_armor_groups["fleshy"] = 3;
368 m_armor_groups["snappy"] = 2;
371 LuaEntitySAO::~LuaEntitySAO()
374 lua_State *L = m_env->getLua();
375 scriptapi_luaentity_rm(L, m_id);
379 void LuaEntitySAO::addedToEnvironment()
381 ServerActiveObject::addedToEnvironment();
383 // Create entity from name
384 lua_State *L = m_env->getLua();
385 m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
389 scriptapi_luaentity_get_properties(L, m_id, &m_prop);
390 // Initialize HP from properties
391 m_hp = m_prop.hp_max;
394 // Activate entity, supplying serialized state
395 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
398 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
399 const std::string &data)
407 std::istringstream is(data, std::ios::binary);
409 u8 version = readU8(is);
410 // check if version is supported
412 name = deSerializeString(is);
413 state = deSerializeLongString(is);
415 else if(version == 1){
416 name = deSerializeString(is);
417 state = deSerializeLongString(is);
419 velocity = readV3F1000(is);
424 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
425 <<state<<"\")"<<std::endl;
426 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
428 sao->m_velocity = velocity;
433 void LuaEntitySAO::step(float dtime, bool send_recommended)
435 if(!m_properties_sent)
437 m_properties_sent = true;
438 std::string str = getPropertyPacket();
439 // create message and add to list
440 ActiveObjectMessage aom(getId(), true, str);
441 m_messages_out.push_back(aom);
444 m_last_sent_position_timer += dtime;
447 core::aabbox3d<f32> box = m_prop.collisionbox;
450 collisionMoveResult moveresult;
451 f32 pos_max_d = BS*0.25; // Distance per iteration
452 v3f p_pos = getBasePosition();
453 v3f p_velocity = m_velocity;
454 IGameDef *gamedef = m_env->getGameDef();
455 moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
456 pos_max_d, box, dtime, p_pos, p_velocity);
458 setBasePosition(p_pos);
459 m_velocity = p_velocity;
461 m_velocity += dtime * m_acceleration;
463 m_base_position += dtime * m_velocity + 0.5 * dtime
464 * dtime * m_acceleration;
465 m_velocity += dtime * m_acceleration;
469 lua_State *L = m_env->getLua();
470 scriptapi_luaentity_step(L, m_id, dtime);
473 if(send_recommended == false)
476 // TODO: force send when acceleration changes enough?
477 float minchange = 0.2*BS;
478 if(m_last_sent_position_timer > 1.0){
480 } else if(m_last_sent_position_timer > 0.2){
483 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
484 move_d += m_last_sent_move_precision;
485 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
486 if(move_d > minchange || vel_d > minchange ||
487 fabs(m_yaw - m_last_sent_yaw) > 1.0){
488 sendPosition(true, false);
491 if(m_armor_groups_sent == false){
492 m_armor_groups_sent = true;
493 std::string str = gob_cmd_update_armor_groups(
495 // create message and add to list
496 ActiveObjectMessage aom(getId(), true, str);
497 m_messages_out.push_back(aom);
501 std::string LuaEntitySAO::getClientInitializationData()
503 std::ostringstream os(std::ios::binary);
504 writeU8(os, 0); // version
505 os<<serializeString(""); // name
506 writeU8(os, 0); // is_player
507 writeV3F1000(os, m_base_position);
508 writeF1000(os, m_yaw);
510 writeU8(os, 2); // number of messages stuffed in here
511 os<<serializeLongString(getPropertyPacket()); // message 1
512 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
517 std::string LuaEntitySAO::getStaticData()
519 verbosestream<<__FUNCTION_NAME<<std::endl;
520 std::ostringstream os(std::ios::binary);
524 os<<serializeString(m_init_name);
527 lua_State *L = m_env->getLua();
528 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
529 os<<serializeLongString(state);
531 os<<serializeLongString(m_init_state);
536 writeV3F1000(os, m_velocity);
538 writeF1000(os, m_yaw);
542 int LuaEntitySAO::punch(v3f dir,
543 const ToolCapabilities *toolcap,
544 ServerActiveObject *puncher,
545 float time_from_last_punch)
548 // Delete unknown LuaEntities when punched
553 ItemStack *punchitem = NULL;
554 ItemStack punchitem_static;
556 punchitem_static = puncher->getWieldedItem();
557 punchitem = &punchitem_static;
560 PunchDamageResult result = getPunchDamage(
564 time_from_last_punch);
568 setHP(getHP() - result.damage);
570 actionstream<<getDescription()<<" punched by "
571 <<puncher->getDescription()<<", damage "<<result.damage
572 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
575 std::string str = gob_cmd_punched(result.damage, getHP());
576 // create message and add to list
577 ActiveObjectMessage aom(getId(), true, str);
578 m_messages_out.push_back(aom);
585 lua_State *L = m_env->getLua();
586 scriptapi_luaentity_punch(L, m_id, puncher,
587 time_from_last_punch, toolcap, dir);
592 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
596 lua_State *L = m_env->getLua();
597 scriptapi_luaentity_rightclick(L, m_id, clicker);
600 void LuaEntitySAO::setPos(v3f pos)
602 m_base_position = pos;
603 sendPosition(false, true);
606 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
608 m_base_position = pos;
610 sendPosition(true, true);
613 float LuaEntitySAO::getMinimumSavedMovement()
618 std::string LuaEntitySAO::getDescription()
620 std::ostringstream os(std::ios::binary);
621 os<<"LuaEntitySAO at (";
622 os<<(m_base_position.X/BS)<<",";
623 os<<(m_base_position.Y/BS)<<",";
624 os<<(m_base_position.Z/BS);
629 void LuaEntitySAO::setHP(s16 hp)
635 s16 LuaEntitySAO::getHP() const
640 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
642 m_armor_groups = armor_groups;
643 m_armor_groups_sent = false;
646 ObjectProperties* LuaEntitySAO::accessObjectProperties()
651 void LuaEntitySAO::notifyObjectPropertiesModified()
653 m_properties_sent = false;
656 void LuaEntitySAO::setVelocity(v3f velocity)
658 m_velocity = velocity;
661 v3f LuaEntitySAO::getVelocity()
666 void LuaEntitySAO::setAcceleration(v3f acceleration)
668 m_acceleration = acceleration;
671 v3f LuaEntitySAO::getAcceleration()
673 return m_acceleration;
676 void LuaEntitySAO::setYaw(float yaw)
681 float LuaEntitySAO::getYaw()
686 void LuaEntitySAO::setTextureMod(const std::string &mod)
688 std::string str = gob_cmd_set_texture_mod(mod);
689 // create message and add to list
690 ActiveObjectMessage aom(getId(), true, str);
691 m_messages_out.push_back(aom);
694 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
695 bool select_horiz_by_yawpitch)
697 std::string str = gob_cmd_set_sprite(
701 select_horiz_by_yawpitch
703 // create message and add to list
704 ActiveObjectMessage aom(getId(), true, str);
705 m_messages_out.push_back(aom);
708 std::string LuaEntitySAO::getName()
713 std::string LuaEntitySAO::getPropertyPacket()
715 return gob_cmd_set_properties(m_prop);
718 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
720 m_last_sent_move_precision = m_base_position.getDistanceFrom(
721 m_last_sent_position);
722 m_last_sent_position_timer = 0;
723 m_last_sent_yaw = m_yaw;
724 m_last_sent_position = m_base_position;
725 m_last_sent_velocity = m_velocity;
726 //m_last_sent_acceleration = m_acceleration;
728 float update_interval = m_env->getSendRecommendedInterval();
730 std::string str = gob_cmd_update_position(
739 // create message and add to list
740 ActiveObjectMessage aom(getId(), false, str);
741 m_messages_out.push_back(aom);
748 // No prototype, PlayerSAO does not need to be deserialized
750 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
751 const std::set<std::string> &privs, bool is_singleplayer):
752 ServerActiveObject(env_, v3f(0,0,0)),
756 m_last_good_position(0,0,0),
757 m_last_good_position_age(0),
758 m_time_from_last_punch(0),
760 m_position_not_sent(false),
761 m_armor_groups_sent(false),
762 m_properties_sent(true),
764 m_is_singleplayer(is_singleplayer),
767 m_inventory_not_sent(false),
768 m_hp_not_sent(false),
769 m_wielded_item_not_sent(false)
772 assert(m_peer_id != 0);
773 setBasePosition(m_player->getPosition());
774 m_inventory = &m_player->inventory;
775 m_armor_groups["choppy"] = 2;
776 m_armor_groups["fleshy"] = 3;
778 m_prop.hp_max = PLAYER_MAX_HP;
779 m_prop.physical = false;
781 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
782 m_prop.visual = "upright_sprite";
783 m_prop.visual_size = v2f(1, 2);
784 m_prop.textures.clear();
785 m_prop.textures.push_back("player.png");
786 m_prop.textures.push_back("player_back.png");
787 m_prop.spritediv = v2s16(1,1);
788 m_prop.is_visible = (getHP() != 0);
789 m_prop.makes_footstep_sound = true;
792 PlayerSAO::~PlayerSAO()
794 if(m_inventory != &m_player->inventory)
799 std::string PlayerSAO::getDescription()
801 return std::string("player ") + m_player->getName();
804 // Called after id has been set and has been inserted in environment
805 void PlayerSAO::addedToEnvironment()
807 ServerActiveObject::addedToEnvironment();
808 ServerActiveObject::setBasePosition(m_player->getPosition());
809 m_player->setPlayerSAO(this);
810 m_player->peer_id = m_peer_id;
811 m_last_good_position = m_player->getPosition();
812 m_last_good_position_age = 0.0;
815 // Called before removing from environment
816 void PlayerSAO::removingFromEnvironment()
818 ServerActiveObject::removingFromEnvironment();
819 if(m_player->getPlayerSAO() == this)
821 m_player->setPlayerSAO(NULL);
822 m_player->peer_id = 0;
826 bool PlayerSAO::isStaticAllowed() const
831 bool PlayerSAO::unlimitedTransferDistance() const
833 return g_settings->getBool("unlimited_player_transfer_distance");
836 std::string PlayerSAO::getClientInitializationData()
838 std::ostringstream os(std::ios::binary);
839 writeU8(os, 0); // version
840 os<<serializeString(m_player->getName()); // name
841 writeU8(os, 1); // is_player
842 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
843 writeF1000(os, m_player->getYaw());
844 writeS16(os, getHP());
845 writeU8(os, 2); // number of messages stuffed in here
846 os<<serializeLongString(getPropertyPacket()); // message 1
847 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
851 std::string PlayerSAO::getStaticData()
857 void PlayerSAO::step(float dtime, bool send_recommended)
859 if(!m_properties_sent)
861 m_properties_sent = true;
862 std::string str = getPropertyPacket();
863 // create message and add to list
864 ActiveObjectMessage aom(getId(), true, str);
865 m_messages_out.push_back(aom);
868 m_time_from_last_punch += dtime;
870 if(m_is_singleplayer)
872 m_last_good_position = m_player->getPosition();
873 m_last_good_position_age = 0;
878 Check player movements
880 NOTE: Actually the server should handle player physics like the
881 client does and compare player's position to what is calculated
882 on our side. This is required when eg. players fly due to an
886 float player_max_speed = 0;
887 float player_max_speed_up = 0;
888 if(m_privs.count("fast") != 0){
890 player_max_speed = BS * 20;
891 player_max_speed_up = BS * 20;
894 player_max_speed = BS * 4.0;
895 player_max_speed_up = BS * 4.0;
898 player_max_speed *= 2.5;
899 player_max_speed_up *= 2.5;
901 m_last_good_position_age += dtime;
902 if(m_last_good_position_age >= 1.0){
903 float age = m_last_good_position_age;
904 v3f diff = (m_player->getPosition() - m_last_good_position);
905 float d_vert = diff.Y;
907 float d_horiz = diff.getLength();
908 /*infostream<<m_player->getName()<<"'s horizontal speed is "
909 <<(d_horiz/age)<<std::endl;*/
910 if(d_horiz <= age * player_max_speed &&
911 (d_vert < 0 || d_vert < age * player_max_speed_up)){
912 m_last_good_position = m_player->getPosition();
914 actionstream<<"Player "<<m_player->getName()
915 <<" moved too fast; resetting position"
917 m_player->setPosition(m_last_good_position);
920 m_last_good_position_age = 0;
924 if(send_recommended == false)
927 if(m_position_not_sent)
929 m_position_not_sent = false;
930 float update_interval = m_env->getSendRecommendedInterval();
931 std::string str = gob_cmd_update_position(
932 m_player->getPosition() + v3f(0,BS*1,0),
940 // create message and add to list
941 ActiveObjectMessage aom(getId(), false, str);
942 m_messages_out.push_back(aom);
945 if(m_wielded_item_not_sent)
947 m_wielded_item_not_sent = false;
948 // GenericCAO has no special way to show this
951 if(m_armor_groups_sent == false){
952 m_armor_groups_sent = true;
953 std::string str = gob_cmd_update_armor_groups(
955 // create message and add to list
956 ActiveObjectMessage aom(getId(), true, str);
957 m_messages_out.push_back(aom);
961 void PlayerSAO::setBasePosition(const v3f &position)
963 ServerActiveObject::setBasePosition(position);
964 m_position_not_sent = true;
967 void PlayerSAO::setPos(v3f pos)
969 m_player->setPosition(pos);
970 // Movement caused by this command is always valid
971 m_last_good_position = pos;
972 m_last_good_position_age = 0;
973 // Force position change on client
977 void PlayerSAO::moveTo(v3f pos, bool continuous)
979 m_player->setPosition(pos);
980 // Movement caused by this command is always valid
981 m_last_good_position = pos;
982 m_last_good_position_age = 0;
983 // Force position change on client
987 int PlayerSAO::punch(v3f dir,
988 const ToolCapabilities *toolcap,
989 ServerActiveObject *puncher,
990 float time_from_last_punch)
995 // No effect if PvP disabled
996 if(g_settings->getBool("enable_pvp") == false){
997 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
998 std::string str = gob_cmd_punched(0, getHP());
999 // create message and add to list
1000 ActiveObjectMessage aom(getId(), true, str);
1001 m_messages_out.push_back(aom);
1006 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1007 time_from_last_punch);
1009 actionstream<<"Player "<<m_player->getName()<<" punched by "
1010 <<puncher->getDescription()<<", damage "<<hitparams.hp
1013 setHP(getHP() - hitparams.hp);
1015 if(hitparams.hp != 0)
1017 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1018 // create message and add to list
1019 ActiveObjectMessage aom(getId(), true, str);
1020 m_messages_out.push_back(aom);
1023 return hitparams.wear;
1026 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1030 s16 PlayerSAO::getHP() const
1032 return m_player->hp;
1035 void PlayerSAO::setHP(s16 hp)
1037 s16 oldhp = m_player->hp;
1041 else if(hp > PLAYER_MAX_HP)
1044 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1046 m_hp_not_sent = true; // fix wrong prediction on client
1053 m_hp_not_sent = true;
1055 // On death or reincarnation send an active object message
1056 if((hp == 0) != (oldhp == 0))
1058 // Will send new is_visible value based on (getHP()!=0)
1059 m_properties_sent = false;
1061 std::string str = gob_cmd_punched(0, getHP());
1062 ActiveObjectMessage aom(getId(), true, str);
1063 m_messages_out.push_back(aom);
1067 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1069 m_armor_groups = armor_groups;
1070 m_armor_groups_sent = false;
1073 ObjectProperties* PlayerSAO::accessObjectProperties()
1078 void PlayerSAO::notifyObjectPropertiesModified()
1080 m_properties_sent = false;
1083 Inventory* PlayerSAO::getInventory()
1087 const Inventory* PlayerSAO::getInventory() const
1092 InventoryLocation PlayerSAO::getInventoryLocation() const
1094 InventoryLocation loc;
1095 loc.setPlayer(m_player->getName());
1099 void PlayerSAO::setInventoryModified()
1101 m_inventory_not_sent = true;
1104 std::string PlayerSAO::getWieldList() const
1109 int PlayerSAO::getWieldIndex() const
1111 return m_wield_index;
1114 void PlayerSAO::setWieldIndex(int i)
1116 if(i != m_wield_index)
1119 m_wielded_item_not_sent = true;
1123 void PlayerSAO::disconnected()
1127 if(m_player->getPlayerSAO() == this)
1129 m_player->setPlayerSAO(NULL);
1130 m_player->peer_id = 0;
1134 void PlayerSAO::createCreativeInventory()
1136 if(m_inventory != &m_player->inventory)
1139 m_inventory = new Inventory(m_player->inventory);
1140 m_inventory->clearContents();
1141 scriptapi_get_creative_inventory(m_env->getLua(), this);
1144 std::string PlayerSAO::getPropertyPacket()
1146 m_prop.is_visible = (getHP() != 0);
1147 return gob_cmd_set_properties(m_prop);