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 #include "luaentity_common.h"
341 // Prototype (registers item for deserialization)
342 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
344 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
345 const std::string &name, const std::string &state):
346 ServerActiveObject(env, pos),
350 m_prop(new LuaEntityProperties),
353 m_acceleration(0,0,0),
355 m_properties_sent(true),
357 m_last_sent_position(0,0,0),
358 m_last_sent_velocity(0,0,0),
359 m_last_sent_position_timer(0),
360 m_last_sent_move_precision(0),
361 m_armor_groups_sent(false)
363 // Only register type if no environment supplied
365 ServerActiveObject::registerType(getType(), create);
369 // Initialize something to armor groups
370 m_armor_groups["fleshy"] = 3;
371 m_armor_groups["snappy"] = 2;
374 LuaEntitySAO::~LuaEntitySAO()
377 lua_State *L = m_env->getLua();
378 scriptapi_luaentity_rm(L, m_id);
383 void LuaEntitySAO::addedToEnvironment()
385 ServerActiveObject::addedToEnvironment();
387 // Create entity from name
388 lua_State *L = m_env->getLua();
389 m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
393 scriptapi_luaentity_get_properties(L, m_id, m_prop);
394 // Initialize HP from properties
395 m_hp = m_prop->hp_max;
398 // Activate entity, supplying serialized state
399 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
402 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
403 const std::string &data)
411 std::istringstream is(data, std::ios::binary);
413 u8 version = readU8(is);
414 // check if version is supported
416 name = deSerializeString(is);
417 state = deSerializeLongString(is);
419 else if(version == 1){
420 name = deSerializeString(is);
421 state = deSerializeLongString(is);
423 velocity = readV3F1000(is);
428 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
429 <<state<<"\")"<<std::endl;
430 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
432 sao->m_velocity = velocity;
437 void LuaEntitySAO::step(float dtime, bool send_recommended)
439 if(!m_properties_sent)
441 m_properties_sent = true;
442 std::string str = getPropertyPacket();
443 // create message and add to list
444 ActiveObjectMessage aom(getId(), true, str);
445 m_messages_out.push_back(aom);
448 m_last_sent_position_timer += dtime;
450 if(m_prop->physical){
451 core::aabbox3d<f32> box = m_prop->collisionbox;
454 collisionMoveResult moveresult;
455 f32 pos_max_d = BS*0.25; // Distance per iteration
456 v3f p_pos = getBasePosition();
457 v3f p_velocity = m_velocity;
458 IGameDef *gamedef = m_env->getGameDef();
459 moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
460 pos_max_d, box, dtime, p_pos, p_velocity);
462 setBasePosition(p_pos);
463 m_velocity = p_velocity;
465 m_velocity += dtime * m_acceleration;
467 m_base_position += dtime * m_velocity + 0.5 * dtime
468 * dtime * m_acceleration;
469 m_velocity += dtime * m_acceleration;
473 lua_State *L = m_env->getLua();
474 scriptapi_luaentity_step(L, m_id, dtime);
477 if(send_recommended == false)
480 // TODO: force send when acceleration changes enough?
481 float minchange = 0.2*BS;
482 if(m_last_sent_position_timer > 1.0){
484 } else if(m_last_sent_position_timer > 0.2){
487 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
488 move_d += m_last_sent_move_precision;
489 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
490 if(move_d > minchange || vel_d > minchange ||
491 fabs(m_yaw - m_last_sent_yaw) > 1.0){
492 sendPosition(true, false);
495 if(m_armor_groups_sent == false){
496 m_armor_groups_sent = true;
497 std::string str = gob_cmd_update_armor_groups(
499 // create message and add to list
500 ActiveObjectMessage aom(getId(), true, str);
501 m_messages_out.push_back(aom);
505 std::string LuaEntitySAO::getClientInitializationData()
507 std::ostringstream os(std::ios::binary);
508 writeU8(os, 0); // version
509 os<<serializeString(""); // name
510 writeU8(os, 0); // is_player
511 writeV3F1000(os, m_base_position);
512 writeF1000(os, m_yaw);
514 writeU8(os, 3); // number of messages stuffed in here
515 os<<serializeLongString(getPropertyPacket()); // message 1
516 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
517 os<<serializeLongString(gob_cmd_set_sprite( // 3
518 m_prop->initial_sprite_basepos,
525 std::string LuaEntitySAO::getStaticData()
527 verbosestream<<__FUNCTION_NAME<<std::endl;
528 std::ostringstream os(std::ios::binary);
532 os<<serializeString(m_init_name);
535 lua_State *L = m_env->getLua();
536 std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
537 os<<serializeLongString(state);
539 os<<serializeLongString(m_init_state);
544 writeV3F1000(os, m_velocity);
546 writeF1000(os, m_yaw);
550 int LuaEntitySAO::punch(v3f dir,
551 const ToolCapabilities *toolcap,
552 ServerActiveObject *puncher,
553 float time_from_last_punch)
556 // Delete unknown LuaEntities when punched
561 ItemStack *punchitem = NULL;
562 ItemStack punchitem_static;
564 punchitem_static = puncher->getWieldedItem();
565 punchitem = &punchitem_static;
568 PunchDamageResult result = getPunchDamage(
572 time_from_last_punch);
576 setHP(getHP() - result.damage);
578 actionstream<<getDescription()<<" punched by "
579 <<puncher->getDescription()<<", damage "<<result.damage
580 <<" hp, health now "<<getHP()<<" hp"<<std::endl;
583 std::string str = gob_cmd_punched(result.damage, getHP());
584 // create message and add to list
585 ActiveObjectMessage aom(getId(), true, str);
586 m_messages_out.push_back(aom);
593 lua_State *L = m_env->getLua();
594 scriptapi_luaentity_punch(L, m_id, puncher,
595 time_from_last_punch, toolcap, dir);
600 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
604 lua_State *L = m_env->getLua();
605 scriptapi_luaentity_rightclick(L, m_id, clicker);
608 void LuaEntitySAO::setPos(v3f pos)
610 m_base_position = pos;
611 sendPosition(false, true);
614 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
616 m_base_position = pos;
618 sendPosition(true, true);
621 float LuaEntitySAO::getMinimumSavedMovement()
626 std::string LuaEntitySAO::getDescription()
628 std::ostringstream os(std::ios::binary);
629 os<<"LuaEntitySAO at (";
630 os<<(m_base_position.X/BS)<<",";
631 os<<(m_base_position.Y/BS)<<",";
632 os<<(m_base_position.Z/BS);
637 void LuaEntitySAO::setHP(s16 hp)
643 s16 LuaEntitySAO::getHP() const
648 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
650 m_armor_groups = armor_groups;
651 m_armor_groups_sent = false;
654 void LuaEntitySAO::setVelocity(v3f velocity)
656 m_velocity = velocity;
659 v3f LuaEntitySAO::getVelocity()
664 void LuaEntitySAO::setAcceleration(v3f acceleration)
666 m_acceleration = acceleration;
669 v3f LuaEntitySAO::getAcceleration()
671 return m_acceleration;
674 void LuaEntitySAO::setYaw(float yaw)
679 float LuaEntitySAO::getYaw()
684 void LuaEntitySAO::setTextureMod(const std::string &mod)
686 std::string str = gob_cmd_set_texture_mod(mod);
687 // create message and add to list
688 ActiveObjectMessage aom(getId(), true, str);
689 m_messages_out.push_back(aom);
692 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
693 bool select_horiz_by_yawpitch)
695 std::string str = gob_cmd_set_sprite(
699 select_horiz_by_yawpitch
701 // create message and add to list
702 ActiveObjectMessage aom(getId(), true, str);
703 m_messages_out.push_back(aom);
706 std::string LuaEntitySAO::getName()
711 std::string LuaEntitySAO::getPropertyPacket()
713 return gob_cmd_set_properties(
717 m_prop->collisionbox,
723 false // makes_footstep_sound
727 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
729 m_last_sent_move_precision = m_base_position.getDistanceFrom(
730 m_last_sent_position);
731 m_last_sent_position_timer = 0;
732 m_last_sent_yaw = m_yaw;
733 m_last_sent_position = m_base_position;
734 m_last_sent_velocity = m_velocity;
735 //m_last_sent_acceleration = m_acceleration;
737 float update_interval = m_env->getSendRecommendedInterval();
739 std::string str = gob_cmd_update_position(
748 // create message and add to list
749 ActiveObjectMessage aom(getId(), false, str);
756 // No prototype, PlayerSAO does not need to be deserialized
758 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
759 ServerActiveObject(env_, v3f(0,0,0)),
763 m_last_good_position(0,0,0),
764 m_last_good_position_age(0),
765 m_time_from_last_punch(0),
767 m_position_not_sent(false),
768 m_armor_groups_sent(false),
769 m_properties_sent(true),
771 m_inventory_not_sent(false),
772 m_hp_not_sent(false),
773 m_wielded_item_not_sent(false)
776 assert(m_peer_id != 0);
777 setBasePosition(m_player->getPosition());
778 m_inventory = &m_player->inventory;
779 m_armor_groups["choppy"] = 2;
780 m_armor_groups["fleshy"] = 3;
783 PlayerSAO::~PlayerSAO()
785 if(m_inventory != &m_player->inventory)
790 std::string PlayerSAO::getDescription()
792 return std::string("player ") + m_player->getName();
795 // Called after id has been set and has been inserted in environment
796 void PlayerSAO::addedToEnvironment()
798 ServerActiveObject::addedToEnvironment();
799 ServerActiveObject::setBasePosition(m_player->getPosition());
800 m_player->setPlayerSAO(this);
801 m_player->peer_id = m_peer_id;
802 m_last_good_position = m_player->getPosition();
803 m_last_good_position_age = 0.0;
806 // Called before removing from environment
807 void PlayerSAO::removingFromEnvironment()
809 ServerActiveObject::removingFromEnvironment();
810 if(m_player->getPlayerSAO() == this)
812 m_player->setPlayerSAO(NULL);
813 m_player->peer_id = 0;
817 bool PlayerSAO::isStaticAllowed() const
822 bool PlayerSAO::unlimitedTransferDistance() const
824 return g_settings->getBool("unlimited_player_transfer_distance");
827 std::string PlayerSAO::getClientInitializationData()
829 std::ostringstream os(std::ios::binary);
830 writeU8(os, 0); // version
831 os<<serializeString(m_player->getName()); // name
832 writeU8(os, 1); // is_player
833 writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
834 writeF1000(os, m_player->getYaw());
835 writeS16(os, getHP());
836 writeU8(os, 2); // number of messages stuffed in here
837 os<<serializeLongString(getPropertyPacket()); // message 1
838 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
842 std::string PlayerSAO::getStaticData()
848 void PlayerSAO::step(float dtime, bool send_recommended)
850 if(!m_properties_sent)
852 m_properties_sent = true;
853 std::string str = getPropertyPacket();
854 // create message and add to list
855 ActiveObjectMessage aom(getId(), true, str);
856 m_messages_out.push_back(aom);
859 m_time_from_last_punch += dtime;
862 Check player movements
864 NOTE: Actually the server should handle player physics like the
865 client does and compare player's position to what is calculated
866 on our side. This is required when eg. players fly due to an
870 //float player_max_speed = BS * 4.0; // Normal speed
871 float player_max_speed = BS * 20; // Fast speed
872 float player_max_speed_up = BS * 20;
873 player_max_speed *= 2.5; // Tolerance
874 player_max_speed_up *= 2.5;
876 m_last_good_position_age += dtime;
877 if(m_last_good_position_age >= 1.0){
878 float age = m_last_good_position_age;
879 v3f diff = (m_player->getPosition() - m_last_good_position);
880 float d_vert = diff.Y;
882 float d_horiz = diff.getLength();
883 /*infostream<<m_player->getName()<<"'s horizontal speed is "
884 <<(d_horiz/age)<<std::endl;*/
885 if(d_horiz <= age * player_max_speed &&
886 (d_vert < 0 || d_vert < age * player_max_speed_up)){
887 m_last_good_position = m_player->getPosition();
889 actionstream<<"Player "<<m_player->getName()
890 <<" moved too fast; resetting position"
892 m_player->setPosition(m_last_good_position);
895 m_last_good_position_age = 0;
898 if(send_recommended == false)
901 if(m_position_not_sent)
903 m_position_not_sent = false;
904 float update_interval = m_env->getSendRecommendedInterval();
905 std::string str = gob_cmd_update_position(
906 m_player->getPosition() + v3f(0,BS*1,0),
914 // create message and add to list
915 ActiveObjectMessage aom(getId(), false, str);
916 m_messages_out.push_back(aom);
919 if(m_wielded_item_not_sent)
921 m_wielded_item_not_sent = false;
922 // GenericCAO has no special way to show this
925 if(m_armor_groups_sent == false){
926 m_armor_groups_sent = true;
927 std::string str = gob_cmd_update_armor_groups(
929 // create message and add to list
930 ActiveObjectMessage aom(getId(), true, str);
931 m_messages_out.push_back(aom);
935 void PlayerSAO::setBasePosition(const v3f &position)
937 ServerActiveObject::setBasePosition(position);
938 m_position_not_sent = true;
941 void PlayerSAO::setPos(v3f pos)
943 m_player->setPosition(pos);
944 // Movement caused by this command is always valid
945 m_last_good_position = pos;
946 m_last_good_position_age = 0;
947 // Force position change on client
951 void PlayerSAO::moveTo(v3f pos, bool continuous)
953 m_player->setPosition(pos);
954 // Movement caused by this command is always valid
955 m_last_good_position = pos;
956 m_last_good_position_age = 0;
957 // Force position change on client
961 int PlayerSAO::punch(v3f dir,
962 const ToolCapabilities *toolcap,
963 ServerActiveObject *puncher,
964 float time_from_last_punch)
969 // No effect if PvP disabled
970 if(g_settings->getBool("enable_pvp") == false){
971 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
972 std::string str = gob_cmd_punched(0, getHP());
973 // create message and add to list
974 ActiveObjectMessage aom(getId(), true, str);
975 m_messages_out.push_back(aom);
980 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
981 time_from_last_punch);
983 actionstream<<"Player "<<m_player->getName()<<" punched by "
984 <<puncher->getDescription()<<", damage "<<hitparams.hp
987 setHP(getHP() - hitparams.hp);
989 if(hitparams.hp != 0)
991 std::string str = gob_cmd_punched(hitparams.hp, getHP());
992 // create message and add to list
993 ActiveObjectMessage aom(getId(), true, str);
994 m_messages_out.push_back(aom);
997 return hitparams.wear;
1000 void PlayerSAO::rightClick(ServerActiveObject *clicker)
1004 s16 PlayerSAO::getHP() const
1006 return m_player->hp;
1009 void PlayerSAO::setHP(s16 hp)
1011 s16 oldhp = m_player->hp;
1015 else if(hp > PLAYER_MAX_HP)
1018 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1020 m_hp_not_sent = true; // fix wrong prediction on client
1027 m_hp_not_sent = true;
1029 // On death or reincarnation send an active object message
1030 if((hp == 0) != (oldhp == 0))
1032 // Will send new is_visible value based on (getHP()!=0)
1033 m_properties_sent = false;
1035 std::string str = gob_cmd_punched(0, getHP());
1036 ActiveObjectMessage aom(getId(), true, str);
1037 m_messages_out.push_back(aom);
1041 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1043 m_armor_groups = armor_groups;
1044 m_armor_groups_sent = false;
1047 Inventory* PlayerSAO::getInventory()
1051 const Inventory* PlayerSAO::getInventory() const
1056 InventoryLocation PlayerSAO::getInventoryLocation() const
1058 InventoryLocation loc;
1059 loc.setPlayer(m_player->getName());
1063 void PlayerSAO::setInventoryModified()
1065 m_inventory_not_sent = true;
1068 std::string PlayerSAO::getWieldList() const
1073 int PlayerSAO::getWieldIndex() const
1075 return m_wield_index;
1078 void PlayerSAO::setWieldIndex(int i)
1080 if(i != m_wield_index)
1083 m_wielded_item_not_sent = true;
1087 void PlayerSAO::disconnected()
1091 if(m_player->getPlayerSAO() == this)
1093 m_player->setPlayerSAO(NULL);
1094 m_player->peer_id = 0;
1098 void PlayerSAO::createCreativeInventory()
1100 if(m_inventory != &m_player->inventory)
1103 m_inventory = new Inventory(m_player->inventory);
1104 m_inventory->clearContents();
1105 scriptapi_get_creative_inventory(m_env->getLua(), this);
1108 std::string PlayerSAO::getPropertyPacket()
1110 core::array<std::string> textures;
1111 textures.push_back("player.png");
1112 textures.push_back("player_back.png");
1113 return gob_cmd_set_properties(
1117 core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.),
1122 (getHP() != 0), // is_visible
1123 true // makes_footstep_sound