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;
392 // Activate entity, supplying serialized state
393 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
397 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
398 const std::string &data)
406 std::istringstream is(data, std::ios::binary);
408 u8 version = readU8(is);
409 // check if version is supported
411 name = deSerializeString(is);
412 state = deSerializeLongString(is);
414 else if(version == 1){
415 name = deSerializeString(is);
416 state = deSerializeLongString(is);
418 velocity = readV3F1000(is);
423 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
424 <<state<<"\")"<<std::endl;
425 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
427 sao->m_velocity = velocity;
432 void LuaEntitySAO::step(float dtime, bool send_recommended)
434 if(!m_properties_sent)
436 m_properties_sent = true;
437 std::string str = getPropertyPacket();
438 // create message and add to list
439 ActiveObjectMessage aom(getId(), true, str);
440 m_messages_out.push_back(aom);
443 m_last_sent_position_timer += dtime;
446 core::aabbox3d<f32> box = m_prop.collisionbox;
449 collisionMoveResult moveresult;
450 f32 pos_max_d = BS*0.25; // Distance per iteration
451 v3f p_pos = getBasePosition();
452 v3f p_velocity = m_velocity;
453 IGameDef *gamedef = m_env->getGameDef();
454 moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
455 pos_max_d, box, dtime, p_pos, p_velocity);
457 setBasePosition(p_pos);
458 m_velocity = p_velocity;
460 m_velocity += dtime * m_acceleration;
462 m_base_position += dtime * m_velocity + 0.5 * dtime
463 * dtime * m_acceleration;
464 m_velocity += dtime * m_acceleration;
468 lua_State *L = m_env->getLua();
469 scriptapi_luaentity_step(L, m_id, dtime);
472 if(send_recommended == false)
475 // TODO: force send when acceleration changes enough?
476 float minchange = 0.2*BS;
477 if(m_last_sent_position_timer > 1.0){
479 } else if(m_last_sent_position_timer > 0.2){
482 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
483 move_d += m_last_sent_move_precision;
484 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
485 if(move_d > minchange || vel_d > minchange ||
486 fabs(m_yaw - m_last_sent_yaw) > 1.0){
487 sendPosition(true, false);
490 if(m_armor_groups_sent == false){
491 m_armor_groups_sent = true;
492 std::string str = gob_cmd_update_armor_groups(
494 // create message and add to list
495 ActiveObjectMessage aom(getId(), true, str);
496 m_messages_out.push_back(aom);
500 std::string LuaEntitySAO::getClientInitializationData()
502 std::ostringstream os(std::ios::binary);
503 writeU8(os, 0); // version
504 os<<serializeString(""); // name
505 writeU8(os, 0); // is_player
506 writeV3F1000(os, m_base_position);
507 writeF1000(os, m_yaw);
509 writeU8(os, 2); // number of messages stuffed in here
510 os<<serializeLongString(getPropertyPacket()); // message 1
511 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
516 std::string LuaEntitySAO::getStaticData()
518 verbosestream<<__FUNCTION_NAME<<std::endl;
519 std::ostringstream os(std::ios::binary);
523 os<<serializeString(m_init_name);
526 lua_State *L = m_env->getLua();
527 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
528 os<<serializeLongString(state);
530 os<<serializeLongString(m_init_state);
535 writeV3F1000(os, m_velocity);
537 writeF1000(os, m_yaw);
541 int LuaEntitySAO::punch(v3f dir,
542 const ToolCapabilities *toolcap,
543 ServerActiveObject *puncher,
544 float time_from_last_punch)
547 // Delete unknown LuaEntities when punched
552 ItemStack *punchitem = NULL;
553 ItemStack punchitem_static;
555 punchitem_static = puncher->getWieldedItem();
556 punchitem = &punchitem_static;
559 PunchDamageResult result = getPunchDamage(
563 time_from_last_punch);
567 setHP(getHP() - result.damage);
569 actionstream<<getDescription()<<" punched by "
570 <<puncher->getDescription()<<", damage "<<result.damage
571 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
574 std::string str = gob_cmd_punched(result.damage, getHP());
575 // create message and add to list
576 ActiveObjectMessage aom(getId(), true, str);
577 m_messages_out.push_back(aom);
584 lua_State *L = m_env->getLua();
585 scriptapi_luaentity_punch(L, m_id, puncher,
586 time_from_last_punch, toolcap, dir);
591 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
595 lua_State *L = m_env->getLua();
596 scriptapi_luaentity_rightclick(L, m_id, clicker);
599 void LuaEntitySAO::setPos(v3f pos)
601 m_base_position = pos;
602 sendPosition(false, true);
605 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
607 m_base_position = pos;
609 sendPosition(true, true);
612 float LuaEntitySAO::getMinimumSavedMovement()
617 std::string LuaEntitySAO::getDescription()
619 std::ostringstream os(std::ios::binary);
620 os<<"LuaEntitySAO at (";
621 os<<(m_base_position.X/BS)<<",";
622 os<<(m_base_position.Y/BS)<<",";
623 os<<(m_base_position.Z/BS);
628 void LuaEntitySAO::setHP(s16 hp)
634 s16 LuaEntitySAO::getHP() const
639 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
641 m_armor_groups = armor_groups;
642 m_armor_groups_sent = false;
645 ObjectProperties* LuaEntitySAO::accessObjectProperties()
650 void LuaEntitySAO::notifyObjectPropertiesModified()
652 m_properties_sent = false;
655 void LuaEntitySAO::setVelocity(v3f velocity)
657 m_velocity = velocity;
660 v3f LuaEntitySAO::getVelocity()
665 void LuaEntitySAO::setAcceleration(v3f acceleration)
667 m_acceleration = acceleration;
670 v3f LuaEntitySAO::getAcceleration()
672 return m_acceleration;
675 void LuaEntitySAO::setYaw(float yaw)
680 float LuaEntitySAO::getYaw()
685 void LuaEntitySAO::setTextureMod(const std::string &mod)
687 std::string str = gob_cmd_set_texture_mod(mod);
688 // create message and add to list
689 ActiveObjectMessage aom(getId(), true, str);
690 m_messages_out.push_back(aom);
693 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
694 bool select_horiz_by_yawpitch)
696 std::string str = gob_cmd_set_sprite(
700 select_horiz_by_yawpitch
702 // create message and add to list
703 ActiveObjectMessage aom(getId(), true, str);
704 m_messages_out.push_back(aom);
707 std::string LuaEntitySAO::getName()
712 std::string LuaEntitySAO::getPropertyPacket()
714 return gob_cmd_set_properties(m_prop);
717 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
719 m_last_sent_move_precision = m_base_position.getDistanceFrom(
720 m_last_sent_position);
721 m_last_sent_position_timer = 0;
722 m_last_sent_yaw = m_yaw;
723 m_last_sent_position = m_base_position;
724 m_last_sent_velocity = m_velocity;
725 //m_last_sent_acceleration = m_acceleration;
727 float update_interval = m_env->getSendRecommendedInterval();
729 std::string str = gob_cmd_update_position(
738 // create message and add to list
739 ActiveObjectMessage aom(getId(), false, str);
740 m_messages_out.push_back(aom);
747 // No prototype, PlayerSAO does not need to be deserialized
749 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
750 const std::set<std::string> &privs, bool is_singleplayer):
751 ServerActiveObject(env_, v3f(0,0,0)),
755 m_last_good_position(0,0,0),
756 m_last_good_position_age(0),
757 m_time_from_last_punch(0),
759 m_position_not_sent(false),
760 m_armor_groups_sent(false),
761 m_properties_sent(true),
763 m_is_singleplayer(is_singleplayer),
766 m_inventory_not_sent(false),
767 m_hp_not_sent(false),
768 m_wielded_item_not_sent(false)
771 assert(m_peer_id != 0);
772 setBasePosition(m_player->getPosition());
773 m_inventory = &m_player->inventory;
774 m_armor_groups["choppy"] = 2;
775 m_armor_groups["fleshy"] = 3;
777 m_prop.hp_max = PLAYER_MAX_HP;
778 m_prop.physical = false;
780 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
781 m_prop.visual = "upright_sprite";
782 m_prop.visual_size = v2f(1, 2);
783 m_prop.textures.clear();
784 m_prop.textures.push_back("player.png");
785 m_prop.textures.push_back("player_back.png");
786 m_prop.spritediv = v2s16(1,1);
787 m_prop.is_visible = (getHP() != 0);
788 m_prop.makes_footstep_sound = true;
791 PlayerSAO::~PlayerSAO()
793 if(m_inventory != &m_player->inventory)
798 std::string PlayerSAO::getDescription()
800 return std::string("player ") + m_player->getName();
803 // Called after id has been set and has been inserted in environment
804 void PlayerSAO::addedToEnvironment()
806 ServerActiveObject::addedToEnvironment();
807 ServerActiveObject::setBasePosition(m_player->getPosition());
808 m_player->setPlayerSAO(this);
809 m_player->peer_id = m_peer_id;
810 m_last_good_position = m_player->getPosition();
811 m_last_good_position_age = 0.0;
814 // Called before removing from environment
815 void PlayerSAO::removingFromEnvironment()
817 ServerActiveObject::removingFromEnvironment();
818 if(m_player->getPlayerSAO() == this)
820 m_player->setPlayerSAO(NULL);
821 m_player->peer_id = 0;
825 bool PlayerSAO::isStaticAllowed() const
830 bool PlayerSAO::unlimitedTransferDistance() const
832 return g_settings->getBool("unlimited_player_transfer_distance");
835 std::string PlayerSAO::getClientInitializationData()
837 std::ostringstream os(std::ios::binary);
838 writeU8(os, 0); // version
839 os<<serializeString(m_player->getName()); // name
840 writeU8(os, 1); // is_player
841 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
842 writeF1000(os, m_player->getYaw());
843 writeS16(os, getHP());
844 writeU8(os, 2); // number of messages stuffed in here
845 os<<serializeLongString(getPropertyPacket()); // message 1
846 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
850 std::string PlayerSAO::getStaticData()
856 void PlayerSAO::step(float dtime, bool send_recommended)
858 if(!m_properties_sent)
860 m_properties_sent = true;
861 std::string str = getPropertyPacket();
862 // create message and add to list
863 ActiveObjectMessage aom(getId(), true, str);
864 m_messages_out.push_back(aom);
867 m_time_from_last_punch += dtime;
869 if(m_is_singleplayer)
871 m_last_good_position = m_player->getPosition();
872 m_last_good_position_age = 0;
877 Check player movements
879 NOTE: Actually the server should handle player physics like the
880 client does and compare player's position to what is calculated
881 on our side. This is required when eg. players fly due to an
885 float player_max_speed = 0;
886 float player_max_speed_up = 0;
887 if(m_privs.count("fast") != 0){
889 player_max_speed = BS * 20;
890 player_max_speed_up = BS * 20;
893 player_max_speed = BS * 4.0;
894 player_max_speed_up = BS * 4.0;
897 player_max_speed *= 2.5;
898 player_max_speed_up *= 2.5;
900 m_last_good_position_age += dtime;
901 if(m_last_good_position_age >= 1.0){
902 float age = m_last_good_position_age;
903 v3f diff = (m_player->getPosition() - m_last_good_position);
904 float d_vert = diff.Y;
906 float d_horiz = diff.getLength();
907 /*infostream<<m_player->getName()<<"'s horizontal speed is "
908 <<(d_horiz/age)<<std::endl;*/
909 if(d_horiz <= age * player_max_speed &&
910 (d_vert < 0 || d_vert < age * player_max_speed_up)){
911 m_last_good_position = m_player->getPosition();
913 actionstream<<"Player "<<m_player->getName()
914 <<" moved too fast; resetting position"
916 m_player->setPosition(m_last_good_position);
919 m_last_good_position_age = 0;
923 if(send_recommended == false)
926 if(m_position_not_sent)
928 m_position_not_sent = false;
929 float update_interval = m_env->getSendRecommendedInterval();
930 std::string str = gob_cmd_update_position(
931 m_player->getPosition() + v3f(0,BS*1,0),
939 // create message and add to list
940 ActiveObjectMessage aom(getId(), false, str);
941 m_messages_out.push_back(aom);
944 if(m_wielded_item_not_sent)
946 m_wielded_item_not_sent = false;
947 // GenericCAO has no special way to show this
950 if(m_armor_groups_sent == false){
951 m_armor_groups_sent = true;
952 std::string str = gob_cmd_update_armor_groups(
954 // create message and add to list
955 ActiveObjectMessage aom(getId(), true, str);
956 m_messages_out.push_back(aom);
960 void PlayerSAO::setBasePosition(const v3f &position)
962 ServerActiveObject::setBasePosition(position);
963 m_position_not_sent = true;
966 void PlayerSAO::setPos(v3f pos)
968 m_player->setPosition(pos);
969 // Movement caused by this command is always valid
970 m_last_good_position = pos;
971 m_last_good_position_age = 0;
972 // Force position change on client
976 void PlayerSAO::moveTo(v3f pos, bool continuous)
978 m_player->setPosition(pos);
979 // Movement caused by this command is always valid
980 m_last_good_position = pos;
981 m_last_good_position_age = 0;
982 // Force position change on client
986 int PlayerSAO::punch(v3f dir,
987 const ToolCapabilities *toolcap,
988 ServerActiveObject *puncher,
989 float time_from_last_punch)
994 // No effect if PvP disabled
995 if(g_settings->getBool("enable_pvp") == false){
996 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
997 std::string str = gob_cmd_punched(0, getHP());
998 // create message and add to list
999 ActiveObjectMessage aom(getId(), true, str);
1000 m_messages_out.push_back(aom);
1005 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1006 time_from_last_punch);
1008 actionstream<<"Player "<<m_player->getName()<<" punched by "
1009 <<puncher->getDescription()<<", damage "<<hitparams.hp
1012 setHP(getHP() - hitparams.hp);
1014 if(hitparams.hp != 0)
1016 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1017 // create message and add to list
1018 ActiveObjectMessage aom(getId(), true, str);
1019 m_messages_out.push_back(aom);
1022 return hitparams.wear;
1025 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1029 s16 PlayerSAO::getHP() const
1031 return m_player->hp;
1034 void PlayerSAO::setHP(s16 hp)
1036 s16 oldhp = m_player->hp;
1040 else if(hp > PLAYER_MAX_HP)
1043 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1045 m_hp_not_sent = true; // fix wrong prediction on client
1052 m_hp_not_sent = true;
1054 // On death or reincarnation send an active object message
1055 if((hp == 0) != (oldhp == 0))
1057 // Will send new is_visible value based on (getHP()!=0)
1058 m_properties_sent = false;
1060 std::string str = gob_cmd_punched(0, getHP());
1061 ActiveObjectMessage aom(getId(), true, str);
1062 m_messages_out.push_back(aom);
1066 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1068 m_armor_groups = armor_groups;
1069 m_armor_groups_sent = false;
1072 ObjectProperties* PlayerSAO::accessObjectProperties()
1077 void PlayerSAO::notifyObjectPropertiesModified()
1079 m_properties_sent = false;
1082 Inventory* PlayerSAO::getInventory()
1086 const Inventory* PlayerSAO::getInventory() const
1091 InventoryLocation PlayerSAO::getInventoryLocation() const
1093 InventoryLocation loc;
1094 loc.setPlayer(m_player->getName());
1098 void PlayerSAO::setInventoryModified()
1100 m_inventory_not_sent = true;
1103 std::string PlayerSAO::getWieldList() const
1108 int PlayerSAO::getWieldIndex() const
1110 return m_wield_index;
1113 void PlayerSAO::setWieldIndex(int i)
1115 if(i != m_wield_index)
1118 m_wielded_item_not_sent = true;
1122 void PlayerSAO::disconnected()
1126 if(m_player->getPlayerSAO() == this)
1128 m_player->setPlayerSAO(NULL);
1129 m_player->peer_id = 0;
1133 void PlayerSAO::createCreativeInventory()
1135 if(m_inventory != &m_player->inventory)
1138 m_inventory = new Inventory(m_player->inventory);
1139 m_inventory->clearContents();
1140 scriptapi_get_creative_inventory(m_env->getLua(), this);
1143 std::string PlayerSAO::getPropertyPacket()
1145 m_prop.is_visible = (getHP() != 0);
1146 return gob_cmd_set_properties(m_prop);