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 // 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(u32 dtime_s)
381 ServerActiveObject::addedToEnvironment(dtime_s);
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(), dtime_s);
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 f32 stepheight = 0; // Maximum climbable step height
452 v3f p_pos = m_base_position;
453 v3f p_velocity = m_velocity;
454 v3f p_acceleration = m_acceleration;
455 IGameDef *gamedef = m_env->getGameDef();
456 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
457 pos_max_d, box, stepheight, dtime,
458 p_pos, p_velocity, p_acceleration);
460 m_base_position = p_pos;
461 m_velocity = p_velocity;
462 m_acceleration = p_acceleration;
464 m_base_position += dtime * m_velocity + 0.5 * dtime
465 * dtime * m_acceleration;
466 m_velocity += dtime * m_acceleration;
470 lua_State *L = m_env->getLua();
471 scriptapi_luaentity_step(L, m_id, dtime);
474 if(send_recommended == false)
477 // TODO: force send when acceleration changes enough?
478 float minchange = 0.2*BS;
479 if(m_last_sent_position_timer > 1.0){
481 } else if(m_last_sent_position_timer > 0.2){
484 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
485 move_d += m_last_sent_move_precision;
486 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
487 if(move_d > minchange || vel_d > minchange ||
488 fabs(m_yaw - m_last_sent_yaw) > 1.0){
489 sendPosition(true, false);
492 if(m_armor_groups_sent == false){
493 m_armor_groups_sent = true;
494 std::string str = gob_cmd_update_armor_groups(
496 // create message and add to list
497 ActiveObjectMessage aom(getId(), true, str);
498 m_messages_out.push_back(aom);
502 std::string LuaEntitySAO::getClientInitializationData()
504 std::ostringstream os(std::ios::binary);
505 writeU8(os, 0); // version
506 os<<serializeString(""); // name
507 writeU8(os, 0); // is_player
508 writeV3F1000(os, m_base_position);
509 writeF1000(os, m_yaw);
511 writeU8(os, 2); // number of messages stuffed in here
512 os<<serializeLongString(getPropertyPacket()); // message 1
513 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
518 std::string LuaEntitySAO::getStaticData()
520 verbosestream<<__FUNCTION_NAME<<std::endl;
521 std::ostringstream os(std::ios::binary);
525 os<<serializeString(m_init_name);
528 lua_State *L = m_env->getLua();
529 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
530 os<<serializeLongString(state);
532 os<<serializeLongString(m_init_state);
537 writeV3F1000(os, m_velocity);
539 writeF1000(os, m_yaw);
543 int LuaEntitySAO::punch(v3f dir,
544 const ToolCapabilities *toolcap,
545 ServerActiveObject *puncher,
546 float time_from_last_punch)
549 // Delete unknown LuaEntities when punched
554 ItemStack *punchitem = NULL;
555 ItemStack punchitem_static;
557 punchitem_static = puncher->getWieldedItem();
558 punchitem = &punchitem_static;
561 PunchDamageResult result = getPunchDamage(
565 time_from_last_punch);
569 setHP(getHP() - result.damage);
571 actionstream<<getDescription()<<" punched by "
572 <<puncher->getDescription()<<", damage "<<result.damage
573 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
576 std::string str = gob_cmd_punched(result.damage, getHP());
577 // create message and add to list
578 ActiveObjectMessage aom(getId(), true, str);
579 m_messages_out.push_back(aom);
586 lua_State *L = m_env->getLua();
587 scriptapi_luaentity_punch(L, m_id, puncher,
588 time_from_last_punch, toolcap, dir);
593 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
597 lua_State *L = m_env->getLua();
598 scriptapi_luaentity_rightclick(L, m_id, clicker);
601 void LuaEntitySAO::setPos(v3f pos)
603 m_base_position = pos;
604 sendPosition(false, true);
607 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
609 m_base_position = pos;
611 sendPosition(true, true);
614 float LuaEntitySAO::getMinimumSavedMovement()
619 std::string LuaEntitySAO::getDescription()
621 std::ostringstream os(std::ios::binary);
622 os<<"LuaEntitySAO at (";
623 os<<(m_base_position.X/BS)<<",";
624 os<<(m_base_position.Y/BS)<<",";
625 os<<(m_base_position.Z/BS);
630 void LuaEntitySAO::setHP(s16 hp)
636 s16 LuaEntitySAO::getHP() const
641 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
643 m_armor_groups = armor_groups;
644 m_armor_groups_sent = false;
647 void LuaEntitySAO::setAnimations(v2f frames, float frame_speed, float frame_blend)
649 std::string str = gob_cmd_set_animations(frames, frame_speed, frame_blend);
650 // create message and add to list
651 ActiveObjectMessage aom(getId(), true, str);
652 m_messages_out.push_back(aom);
655 void LuaEntitySAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
657 std::string str = gob_cmd_set_bone_posrot(bone, position, rotation);
658 // create message and add to list
659 ActiveObjectMessage aom(getId(), true, str);
660 m_messages_out.push_back(aom);
663 ObjectProperties* LuaEntitySAO::accessObjectProperties()
668 void LuaEntitySAO::notifyObjectPropertiesModified()
670 m_properties_sent = false;
673 void LuaEntitySAO::setVelocity(v3f velocity)
675 m_velocity = velocity;
678 v3f LuaEntitySAO::getVelocity()
683 void LuaEntitySAO::setAcceleration(v3f acceleration)
685 m_acceleration = acceleration;
688 v3f LuaEntitySAO::getAcceleration()
690 return m_acceleration;
693 void LuaEntitySAO::setYaw(float yaw)
698 float LuaEntitySAO::getYaw()
703 void LuaEntitySAO::setTextureMod(const std::string &mod)
705 std::string str = gob_cmd_set_texture_mod(mod);
706 // create message and add to list
707 ActiveObjectMessage aom(getId(), true, str);
708 m_messages_out.push_back(aom);
711 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
712 bool select_horiz_by_yawpitch)
714 std::string str = gob_cmd_set_sprite(
718 select_horiz_by_yawpitch
720 // create message and add to list
721 ActiveObjectMessage aom(getId(), true, str);
722 m_messages_out.push_back(aom);
725 std::string LuaEntitySAO::getName()
730 std::string LuaEntitySAO::getPropertyPacket()
732 return gob_cmd_set_properties(m_prop);
735 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
737 m_last_sent_move_precision = m_base_position.getDistanceFrom(
738 m_last_sent_position);
739 m_last_sent_position_timer = 0;
740 m_last_sent_yaw = m_yaw;
741 m_last_sent_position = m_base_position;
742 m_last_sent_velocity = m_velocity;
743 //m_last_sent_acceleration = m_acceleration;
745 float update_interval = m_env->getSendRecommendedInterval();
747 std::string str = gob_cmd_update_position(
756 // create message and add to list
757 ActiveObjectMessage aom(getId(), false, str);
758 m_messages_out.push_back(aom);
765 // No prototype, PlayerSAO does not need to be deserialized
767 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
768 const std::set<std::string> &privs, bool is_singleplayer):
769 ServerActiveObject(env_, v3f(0,0,0)),
773 m_last_good_position(0,0,0),
774 m_last_good_position_age(0),
775 m_time_from_last_punch(0),
776 m_nocheat_dig_pos(32767, 32767, 32767),
777 m_nocheat_dig_time(0),
779 m_position_not_sent(false),
780 m_armor_groups_sent(false),
781 m_properties_sent(true),
783 m_is_singleplayer(is_singleplayer),
786 m_inventory_not_sent(false),
787 m_hp_not_sent(false),
788 m_wielded_item_not_sent(false)
791 assert(m_peer_id != 0);
792 setBasePosition(m_player->getPosition());
793 m_inventory = &m_player->inventory;
794 m_armor_groups["choppy"] = 2;
795 m_armor_groups["fleshy"] = 3;
797 m_prop.hp_max = PLAYER_MAX_HP;
798 m_prop.physical = false;
800 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
801 // start of default appearance, this should be overwritten by LUA
802 m_prop.visual = "upright_sprite";
803 m_prop.visual_size = v2f(1, 2);
804 m_prop.textures.clear();
805 m_prop.textures.push_back("player.png");
806 m_prop.textures.push_back("player_back.png");
807 m_prop.spritediv = v2s16(1,1);
808 // end of default appearance
809 m_prop.is_visible = (getHP() != 0); // TODO: Use a death animation instead for mesh players
810 m_prop.makes_footstep_sound = true;
813 PlayerSAO::~PlayerSAO()
815 if(m_inventory != &m_player->inventory)
820 std::string PlayerSAO::getDescription()
822 return std::string("player ") + m_player->getName();
825 // Called after id has been set and has been inserted in environment
826 void PlayerSAO::addedToEnvironment(u32 dtime_s)
828 ServerActiveObject::addedToEnvironment(dtime_s);
829 ServerActiveObject::setBasePosition(m_player->getPosition());
830 m_player->setPlayerSAO(this);
831 m_player->peer_id = m_peer_id;
832 m_last_good_position = m_player->getPosition();
833 m_last_good_position_age = 0.0;
836 // Called before removing from environment
837 void PlayerSAO::removingFromEnvironment()
839 ServerActiveObject::removingFromEnvironment();
840 if(m_player->getPlayerSAO() == this)
842 m_player->setPlayerSAO(NULL);
843 m_player->peer_id = 0;
847 bool PlayerSAO::isStaticAllowed() const
852 bool PlayerSAO::unlimitedTransferDistance() const
854 return g_settings->getBool("unlimited_player_transfer_distance");
857 std::string PlayerSAO::getClientInitializationData()
859 std::ostringstream os(std::ios::binary);
860 writeU8(os, 0); // version
861 os<<serializeString(m_player->getName()); // name
862 writeU8(os, 1); // is_player
863 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
864 writeF1000(os, m_player->getYaw());
865 writeS16(os, getHP());
866 writeU8(os, 2); // number of messages stuffed in here
867 os<<serializeLongString(getPropertyPacket()); // message 1
868 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
872 std::string PlayerSAO::getStaticData()
878 void PlayerSAO::step(float dtime, bool send_recommended)
880 if(!m_properties_sent)
882 m_properties_sent = true;
883 std::string str = getPropertyPacket();
884 // create message and add to list
885 ActiveObjectMessage aom(getId(), true, str);
886 m_messages_out.push_back(aom);
889 m_time_from_last_punch += dtime;
890 m_nocheat_dig_time += dtime;
892 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
894 m_last_good_position = m_player->getPosition();
895 m_last_good_position_age = 0;
900 Check player movements
902 NOTE: Actually the server should handle player physics like the
903 client does and compare player's position to what is calculated
904 on our side. This is required when eg. players fly due to an
905 explosion. Altough a node-based alternative might be possible
906 too, and much more lightweight.
909 float player_max_speed = 0;
910 float player_max_speed_up = 0;
911 if(m_privs.count("fast") != 0){
913 player_max_speed = BS * 20;
914 player_max_speed_up = BS * 20;
917 player_max_speed = BS * 4.0;
918 player_max_speed_up = BS * 4.0;
921 player_max_speed *= 2.5;
922 player_max_speed_up *= 2.5;
924 m_last_good_position_age += dtime;
925 if(m_last_good_position_age >= 1.0){
926 float age = m_last_good_position_age;
927 v3f diff = (m_player->getPosition() - m_last_good_position);
928 float d_vert = diff.Y;
930 float d_horiz = diff.getLength();
931 /*infostream<<m_player->getName()<<"'s horizontal speed is "
932 <<(d_horiz/age)<<std::endl;*/
933 if(d_horiz <= age * player_max_speed &&
934 (d_vert < 0 || d_vert < age * player_max_speed_up)){
935 m_last_good_position = m_player->getPosition();
937 actionstream<<"Player "<<m_player->getName()
938 <<" moved too fast; resetting position"
940 m_player->setPosition(m_last_good_position);
943 m_last_good_position_age = 0;
947 if(send_recommended == false)
950 if(m_position_not_sent)
952 m_position_not_sent = false;
953 float update_interval = m_env->getSendRecommendedInterval();
954 std::string str = gob_cmd_update_position(
955 m_player->getPosition() + v3f(0,BS*1,0),
963 // create message and add to list
964 ActiveObjectMessage aom(getId(), false, str);
965 m_messages_out.push_back(aom);
968 if(m_wielded_item_not_sent)
970 m_wielded_item_not_sent = false;
971 // GenericCAO has no special way to show this
974 if(m_armor_groups_sent == false){
975 m_armor_groups_sent = true;
976 std::string str = gob_cmd_update_armor_groups(
978 // create message and add to list
979 ActiveObjectMessage aom(getId(), true, str);
980 m_messages_out.push_back(aom);
984 void PlayerSAO::setBasePosition(const v3f &position)
986 ServerActiveObject::setBasePosition(position);
987 m_position_not_sent = true;
990 void PlayerSAO::setPos(v3f pos)
992 m_player->setPosition(pos);
993 // Movement caused by this command is always valid
994 m_last_good_position = pos;
995 m_last_good_position_age = 0;
996 // Force position change on client
1000 void PlayerSAO::moveTo(v3f pos, bool continuous)
1002 m_player->setPosition(pos);
1003 // Movement caused by this command is always valid
1004 m_last_good_position = pos;
1005 m_last_good_position_age = 0;
1006 // Force position change on client
1007 m_teleported = true;
1010 int PlayerSAO::punch(v3f dir,
1011 const ToolCapabilities *toolcap,
1012 ServerActiveObject *puncher,
1013 float time_from_last_punch)
1018 // No effect if PvP disabled
1019 if(g_settings->getBool("enable_pvp") == false){
1020 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1021 std::string str = gob_cmd_punched(0, getHP());
1022 // create message and add to list
1023 ActiveObjectMessage aom(getId(), true, str);
1024 m_messages_out.push_back(aom);
1029 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1030 time_from_last_punch);
1032 actionstream<<"Player "<<m_player->getName()<<" punched by "
1033 <<puncher->getDescription()<<", damage "<<hitparams.hp
1036 setHP(getHP() - hitparams.hp);
1038 if(hitparams.hp != 0)
1040 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1041 // create message and add to list
1042 ActiveObjectMessage aom(getId(), true, str);
1043 m_messages_out.push_back(aom);
1046 return hitparams.wear;
1049 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1053 s16 PlayerSAO::getHP() const
1055 return m_player->hp;
1058 void PlayerSAO::setHP(s16 hp)
1060 s16 oldhp = m_player->hp;
1064 else if(hp > PLAYER_MAX_HP)
1067 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1069 m_hp_not_sent = true; // fix wrong prediction on client
1076 m_hp_not_sent = true;
1078 // On death or reincarnation send an active object message
1079 if((hp == 0) != (oldhp == 0))
1081 // Will send new is_visible value based on (getHP()!=0)
1082 m_properties_sent = false;
1084 std::string str = gob_cmd_punched(0, getHP());
1085 ActiveObjectMessage aom(getId(), true, str);
1086 m_messages_out.push_back(aom);
1090 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1092 m_armor_groups = armor_groups;
1093 m_armor_groups_sent = false;
1096 void PlayerSAO::setAnimations(v2f frames, float frame_speed, float frame_blend)
1098 std::string str = gob_cmd_set_animations(frames, frame_speed, frame_blend);
1099 // create message and add to list
1100 ActiveObjectMessage aom(getId(), true, str);
1101 m_messages_out.push_back(aom);
1104 void PlayerSAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
1106 std::string str = gob_cmd_set_bone_posrot(bone, position, rotation);
1107 // create message and add to list
1108 ActiveObjectMessage aom(getId(), true, str);
1109 m_messages_out.push_back(aom);
1112 ObjectProperties* PlayerSAO::accessObjectProperties()
1117 void PlayerSAO::notifyObjectPropertiesModified()
1119 m_properties_sent = false;
1122 Inventory* PlayerSAO::getInventory()
1126 const Inventory* PlayerSAO::getInventory() const
1131 InventoryLocation PlayerSAO::getInventoryLocation() const
1133 InventoryLocation loc;
1134 loc.setPlayer(m_player->getName());
1138 void PlayerSAO::setInventoryModified()
1140 m_inventory_not_sent = true;
1143 std::string PlayerSAO::getWieldList() const
1148 int PlayerSAO::getWieldIndex() const
1150 return m_wield_index;
1153 void PlayerSAO::setWieldIndex(int i)
1155 if(i != m_wield_index)
1158 m_wielded_item_not_sent = true;
1162 void PlayerSAO::disconnected()
1166 if(m_player->getPlayerSAO() == this)
1168 m_player->setPlayerSAO(NULL);
1169 m_player->peer_id = 0;
1173 std::string PlayerSAO::getPropertyPacket()
1175 m_prop.is_visible = (getHP() != 0);
1176 return gob_cmd_set_properties(m_prop);