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 writeS16(os, getId()); //id
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 void LuaEntitySAO::setAnimations(v2f frames, float frame_speed, float frame_blend)
650 std::string str = gob_cmd_set_animations(frames, frame_speed, frame_blend);
651 // create message and add to list
652 ActiveObjectMessage aom(getId(), true, str);
653 m_messages_out.push_back(aom);
656 void LuaEntitySAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
658 std::string str = gob_cmd_set_bone_posrot(bone, position, rotation);
659 // create message and add to list
660 ActiveObjectMessage aom(getId(), true, str);
661 m_messages_out.push_back(aom);
664 // Part of the attachment structure, not used yet!
665 void LuaEntitySAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation)
667 // Parent should be translated from a ServerActiveObject into something
668 // the client will recognize (as a ClientActiveObject) then sent in
669 // gob_cmd_set_attachment that way.
671 std::string str = gob_cmd_set_attachment(); // <- parameters here
672 // create message and add to list
673 ActiveObjectMessage aom(getId(), true, str);
674 m_messages_out.push_back(aom);
677 ObjectProperties* LuaEntitySAO::accessObjectProperties()
682 void LuaEntitySAO::notifyObjectPropertiesModified()
684 m_properties_sent = false;
687 void LuaEntitySAO::setVelocity(v3f velocity)
689 m_velocity = velocity;
692 v3f LuaEntitySAO::getVelocity()
697 void LuaEntitySAO::setAcceleration(v3f acceleration)
699 m_acceleration = acceleration;
702 v3f LuaEntitySAO::getAcceleration()
704 return m_acceleration;
707 void LuaEntitySAO::setYaw(float yaw)
712 float LuaEntitySAO::getYaw()
717 void LuaEntitySAO::setTextureMod(const std::string &mod)
719 std::string str = gob_cmd_set_texture_mod(mod);
720 // create message and add to list
721 ActiveObjectMessage aom(getId(), true, str);
722 m_messages_out.push_back(aom);
725 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
726 bool select_horiz_by_yawpitch)
728 std::string str = gob_cmd_set_sprite(
732 select_horiz_by_yawpitch
734 // create message and add to list
735 ActiveObjectMessage aom(getId(), true, str);
736 m_messages_out.push_back(aom);
739 std::string LuaEntitySAO::getName()
744 std::string LuaEntitySAO::getPropertyPacket()
746 return gob_cmd_set_properties(m_prop);
749 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
751 m_last_sent_move_precision = m_base_position.getDistanceFrom(
752 m_last_sent_position);
753 m_last_sent_position_timer = 0;
754 m_last_sent_yaw = m_yaw;
755 m_last_sent_position = m_base_position;
756 m_last_sent_velocity = m_velocity;
757 //m_last_sent_acceleration = m_acceleration;
759 float update_interval = m_env->getSendRecommendedInterval();
761 std::string str = gob_cmd_update_position(
770 // create message and add to list
771 ActiveObjectMessage aom(getId(), false, str);
772 m_messages_out.push_back(aom);
779 // No prototype, PlayerSAO does not need to be deserialized
781 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
782 const std::set<std::string> &privs, bool is_singleplayer):
783 ServerActiveObject(env_, v3f(0,0,0)),
787 m_last_good_position(0,0,0),
788 m_last_good_position_age(0),
789 m_time_from_last_punch(0),
790 m_nocheat_dig_pos(32767, 32767, 32767),
791 m_nocheat_dig_time(0),
793 m_position_not_sent(false),
794 m_armor_groups_sent(false),
795 m_properties_sent(true),
797 m_is_singleplayer(is_singleplayer),
800 m_inventory_not_sent(false),
801 m_hp_not_sent(false),
802 m_wielded_item_not_sent(false)
805 assert(m_peer_id != 0);
806 setBasePosition(m_player->getPosition());
807 m_inventory = &m_player->inventory;
808 m_armor_groups["choppy"] = 2;
809 m_armor_groups["fleshy"] = 3;
811 m_prop.hp_max = PLAYER_MAX_HP;
812 m_prop.physical = false;
814 m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
815 // start of default appearance, this should be overwritten by LUA
816 m_prop.visual = "upright_sprite";
817 m_prop.visual_size = v2f(1, 2);
818 m_prop.textures.clear();
819 m_prop.textures.push_back("player.png");
820 m_prop.textures.push_back("player_back.png");
821 m_prop.colors.clear();
822 m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
823 m_prop.spritediv = v2s16(1,1);
824 // end of default appearance
825 m_prop.is_visible = (getHP() != 0); // TODO: Use a death animation instead for mesh players
826 m_prop.makes_footstep_sound = true;
829 PlayerSAO::~PlayerSAO()
831 if(m_inventory != &m_player->inventory)
836 std::string PlayerSAO::getDescription()
838 return std::string("player ") + m_player->getName();
841 // Called after id has been set and has been inserted in environment
842 void PlayerSAO::addedToEnvironment(u32 dtime_s)
844 ServerActiveObject::addedToEnvironment(dtime_s);
845 ServerActiveObject::setBasePosition(m_player->getPosition());
846 m_player->setPlayerSAO(this);
847 m_player->peer_id = m_peer_id;
848 m_last_good_position = m_player->getPosition();
849 m_last_good_position_age = 0.0;
852 // Called before removing from environment
853 void PlayerSAO::removingFromEnvironment()
855 ServerActiveObject::removingFromEnvironment();
856 if(m_player->getPlayerSAO() == this)
858 m_player->setPlayerSAO(NULL);
859 m_player->peer_id = 0;
863 bool PlayerSAO::isStaticAllowed() const
868 bool PlayerSAO::unlimitedTransferDistance() const
870 return g_settings->getBool("unlimited_player_transfer_distance");
873 std::string PlayerSAO::getClientInitializationData()
875 std::ostringstream os(std::ios::binary);
876 writeU8(os, 0); // version
877 os<<serializeString(m_player->getName()); // name
878 writeU8(os, 1); // is_player
879 writeS16(os, getId()); //id
880 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
881 writeF1000(os, m_player->getYaw());
882 writeS16(os, getHP());
883 writeU8(os, 2); // number of messages stuffed in here
884 os<<serializeLongString(getPropertyPacket()); // message 1
885 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
889 std::string PlayerSAO::getStaticData()
895 void PlayerSAO::step(float dtime, bool send_recommended)
897 if(!m_properties_sent)
899 m_properties_sent = true;
900 std::string str = getPropertyPacket();
901 // create message and add to list
902 ActiveObjectMessage aom(getId(), true, str);
903 m_messages_out.push_back(aom);
906 m_time_from_last_punch += dtime;
907 m_nocheat_dig_time += dtime;
909 if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
911 m_last_good_position = m_player->getPosition();
912 m_last_good_position_age = 0;
917 Check player movements
919 NOTE: Actually the server should handle player physics like the
920 client does and compare player's position to what is calculated
921 on our side. This is required when eg. players fly due to an
922 explosion. Altough a node-based alternative might be possible
923 too, and much more lightweight.
926 float player_max_speed = 0;
927 float player_max_speed_up = 0;
928 if(m_privs.count("fast") != 0){
930 player_max_speed = BS * 20;
931 player_max_speed_up = BS * 20;
934 player_max_speed = BS * 4.0;
935 player_max_speed_up = BS * 4.0;
938 player_max_speed *= 2.5;
939 player_max_speed_up *= 2.5;
941 m_last_good_position_age += dtime;
942 if(m_last_good_position_age >= 1.0){
943 float age = m_last_good_position_age;
944 v3f diff = (m_player->getPosition() - m_last_good_position);
945 float d_vert = diff.Y;
947 float d_horiz = diff.getLength();
948 /*infostream<<m_player->getName()<<"'s horizontal speed is "
949 <<(d_horiz/age)<<std::endl;*/
950 if(d_horiz <= age * player_max_speed &&
951 (d_vert < 0 || d_vert < age * player_max_speed_up)){
952 m_last_good_position = m_player->getPosition();
954 actionstream<<"Player "<<m_player->getName()
955 <<" moved too fast; resetting position"
957 m_player->setPosition(m_last_good_position);
960 m_last_good_position_age = 0;
964 if(send_recommended == false)
967 if(m_position_not_sent)
969 m_position_not_sent = false;
970 float update_interval = m_env->getSendRecommendedInterval();
971 std::string str = gob_cmd_update_position(
972 m_player->getPosition() + v3f(0,BS*1,0),
980 // create message and add to list
981 ActiveObjectMessage aom(getId(), false, str);
982 m_messages_out.push_back(aom);
985 if(m_wielded_item_not_sent)
987 m_wielded_item_not_sent = false;
988 // GenericCAO has no special way to show this
991 if(m_armor_groups_sent == false){
992 m_armor_groups_sent = true;
993 std::string str = gob_cmd_update_armor_groups(
995 // create message and add to list
996 ActiveObjectMessage aom(getId(), true, str);
997 m_messages_out.push_back(aom);
1001 void PlayerSAO::setBasePosition(const v3f &position)
1003 ServerActiveObject::setBasePosition(position);
1004 m_position_not_sent = true;
1007 void PlayerSAO::setPos(v3f pos)
1009 m_player->setPosition(pos);
1010 // Movement caused by this command is always valid
1011 m_last_good_position = pos;
1012 m_last_good_position_age = 0;
1013 // Force position change on client
1014 m_teleported = true;
1017 void PlayerSAO::moveTo(v3f pos, bool continuous)
1019 m_player->setPosition(pos);
1020 // Movement caused by this command is always valid
1021 m_last_good_position = pos;
1022 m_last_good_position_age = 0;
1023 // Force position change on client
1024 m_teleported = true;
1027 int PlayerSAO::punch(v3f dir,
1028 const ToolCapabilities *toolcap,
1029 ServerActiveObject *puncher,
1030 float time_from_last_punch)
1035 // No effect if PvP disabled
1036 if(g_settings->getBool("enable_pvp") == false){
1037 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
1038 std::string str = gob_cmd_punched(0, getHP());
1039 // create message and add to list
1040 ActiveObjectMessage aom(getId(), true, str);
1041 m_messages_out.push_back(aom);
1046 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1047 time_from_last_punch);
1049 actionstream<<"Player "<<m_player->getName()<<" punched by "
1050 <<puncher->getDescription()<<", damage "<<hitparams.hp
1053 setHP(getHP() - hitparams.hp);
1055 if(hitparams.hp != 0)
1057 std::string str = gob_cmd_punched(hitparams.hp, getHP());
1058 // create message and add to list
1059 ActiveObjectMessage aom(getId(), true, str);
1060 m_messages_out.push_back(aom);
1063 return hitparams.wear;
1066 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1070 s16 PlayerSAO::getHP() const
1072 return m_player->hp;
1075 void PlayerSAO::setHP(s16 hp)
1077 s16 oldhp = m_player->hp;
1081 else if(hp > PLAYER_MAX_HP)
1084 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1086 m_hp_not_sent = true; // fix wrong prediction on client
1093 m_hp_not_sent = true;
1095 // On death or reincarnation send an active object message
1096 if((hp == 0) != (oldhp == 0))
1098 // Will send new is_visible value based on (getHP()!=0)
1099 m_properties_sent = false;
1101 std::string str = gob_cmd_punched(0, getHP());
1102 ActiveObjectMessage aom(getId(), true, str);
1103 m_messages_out.push_back(aom);
1107 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1109 m_armor_groups = armor_groups;
1110 m_armor_groups_sent = false;
1113 void PlayerSAO::setAnimations(v2f frames, float frame_speed, float frame_blend)
1115 std::string str = gob_cmd_set_animations(frames, frame_speed, frame_blend);
1116 // create message and add to list
1117 ActiveObjectMessage aom(getId(), true, str);
1118 m_messages_out.push_back(aom);
1121 void PlayerSAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
1123 std::string str = gob_cmd_set_bone_posrot(bone, position, rotation);
1124 // create message and add to list
1125 ActiveObjectMessage aom(getId(), true, str);
1126 m_messages_out.push_back(aom);
1129 // Part of the attachment structure, not used yet!
1130 void PlayerSAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation)
1132 std::string str = gob_cmd_set_attachment(); // <- parameters here
1133 // create message and add to list
1134 ActiveObjectMessage aom(getId(), true, str);
1135 m_messages_out.push_back(aom);
1138 ObjectProperties* PlayerSAO::accessObjectProperties()
1143 void PlayerSAO::notifyObjectPropertiesModified()
1145 m_properties_sent = false;
1148 Inventory* PlayerSAO::getInventory()
1152 const Inventory* PlayerSAO::getInventory() const
1157 InventoryLocation PlayerSAO::getInventoryLocation() const
1159 InventoryLocation loc;
1160 loc.setPlayer(m_player->getName());
1164 void PlayerSAO::setInventoryModified()
1166 m_inventory_not_sent = true;
1169 std::string PlayerSAO::getWieldList() const
1174 int PlayerSAO::getWieldIndex() const
1176 return m_wield_index;
1179 void PlayerSAO::setWieldIndex(int i)
1181 if(i != m_wield_index)
1184 m_wielded_item_not_sent = true;
1188 void PlayerSAO::disconnected()
1192 if(m_player->getPlayerSAO() == this)
1194 m_player->setPlayerSAO(NULL);
1195 m_player->peer_id = 0;
1199 std::string PlayerSAO::getPropertyPacket()
1201 m_prop.is_visible = (getHP() != 0);
1202 return gob_cmd_set_properties(m_prop);