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"
32 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
38 class DummyLoadSAO : public ServerActiveObject
41 DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type):
42 ServerActiveObject(env, pos)
44 ServerActiveObject::registerType(type, create);
46 // Pretend to be the test object (to fool the client)
48 { return ACTIVEOBJECT_TYPE_TEST; }
49 // And never save to disk
50 bool isStaticAllowed() const
53 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
54 const std::string &data)
56 return new DummyLoadSAO(env, pos, 0);
59 void step(float dtime, bool send_recommended)
62 infostream<<"DummyLoadSAO step"<<std::endl;
68 // Prototype (registers item for deserialization)
69 DummyLoadSAO proto1_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_RAT);
70 DummyLoadSAO proto2_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_OERKKI1);
71 DummyLoadSAO proto3_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_FIREFLY);
72 DummyLoadSAO proto4_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_MOBV2);
78 class TestSAO : public ServerActiveObject
81 TestSAO(ServerEnvironment *env, v3f pos):
82 ServerActiveObject(env, pos),
86 ServerActiveObject::registerType(getType(), create);
89 { return ACTIVEOBJECT_TYPE_TEST; }
91 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
92 const std::string &data)
94 return new TestSAO(env, pos);
97 void step(float dtime, bool send_recommended)
106 m_base_position.Y += dtime * BS * 2;
107 if(m_base_position.Y > 8*BS)
108 m_base_position.Y = 2*BS;
110 if(send_recommended == false)
120 data += itos(0); // 0 = position
122 data += itos(m_base_position.X);
124 data += itos(m_base_position.Y);
126 data += itos(m_base_position.Z);
128 ActiveObjectMessage aom(getId(), false, data);
129 m_messages_out.push_back(aom);
138 // Prototype (registers item for deserialization)
139 TestSAO proto_TestSAO(NULL, v3f(0,0,0));
145 class ItemSAO : public ServerActiveObject
149 { return ACTIVEOBJECT_TYPE_ITEM; }
151 float getMinimumSavedMovement()
154 static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
155 const std::string &data)
157 std::istringstream is(data, std::ios::binary);
162 // check if version is supported
165 std::string itemstring = deSerializeString(is);
166 infostream<<"create(): Creating item \""
167 <<itemstring<<"\""<<std::endl;
168 return new ItemSAO(env, pos, itemstring);
171 ItemSAO(ServerEnvironment *env, v3f pos,
172 const std::string itemstring):
173 ServerActiveObject(env, pos),
174 m_itemstring(itemstring),
175 m_itemstring_changed(false),
177 m_last_sent_position(0,0,0)
179 ServerActiveObject::registerType(getType(), create);
182 void step(float dtime, bool send_recommended)
184 ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
188 const float interval = 0.2;
189 if(m_move_interval.step(dtime, interval)==false)
193 core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
194 collisionMoveResult moveresult;
196 m_speed_f += v3f(0, -dtime*9.81*BS, 0);
197 // Maximum movement without glitches
198 f32 pos_max_d = BS*0.25;
200 if(m_speed_f.getLength()*dtime > pos_max_d)
201 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
202 v3f pos_f = getBasePosition();
203 v3f pos_f_old = pos_f;
204 IGameDef *gamedef = m_env->getGameDef();
205 moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
206 pos_max_d, box, dtime, pos_f, m_speed_f);
208 if(send_recommended == false)
211 if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
213 setBasePosition(pos_f);
214 m_last_sent_position = pos_f;
216 std::ostringstream os(std::ios::binary);
217 // command (0 = update position)
220 writeV3F1000(os, m_base_position);
221 // create message and add to list
222 ActiveObjectMessage aom(getId(), false, os.str());
223 m_messages_out.push_back(aom);
225 if(m_itemstring_changed)
227 m_itemstring_changed = false;
229 std::ostringstream os(std::ios::binary);
230 // command (1 = update itemstring)
233 os<<serializeString(m_itemstring);
234 // create message and add to list
235 ActiveObjectMessage aom(getId(), false, os.str());
236 m_messages_out.push_back(aom);
240 std::string getClientInitializationData()
242 std::ostringstream os(std::ios::binary);
246 writeV3F1000(os, m_base_position);
248 os<<serializeString(m_itemstring);
252 std::string getStaticData()
254 infostream<<__FUNCTION_NAME<<std::endl;
255 std::ostringstream os(std::ios::binary);
259 os<<serializeString(m_itemstring);
263 ItemStack createItemStack()
266 IItemDefManager *idef = m_env->getGameDef()->idef();
268 item.deSerialize(m_itemstring, idef);
269 infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
270 <<"\" -> item=\""<<item.getItemString()<<"\""
274 catch(SerializationError &e)
276 infostream<<__FUNCTION_NAME<<": serialization error: "
277 <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
283 const ToolCapabilities *toolcap,
284 ServerActiveObject *puncher,
285 float time_from_last_punch)
287 // Directly delete item in creative mode
288 if(g_settings->getBool("creative_mode") == true)
294 // Take item into inventory
295 ItemStack item = createItemStack();
296 Inventory *inv = puncher->getInventory();
299 std::string wieldlist = puncher->getWieldList();
300 ItemStack leftover = inv->addItem(wieldlist, item);
301 puncher->setInventoryModified();
308 m_itemstring = leftover.getItemString();
309 m_itemstring_changed = true;
318 std::string m_itemstring;
319 bool m_itemstring_changed;
321 v3f m_last_sent_position;
322 IntervalLimiter m_move_interval;
325 // Prototype (registers item for deserialization)
326 ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
328 ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
329 const std::string itemstring)
331 return new ItemSAO(env, pos, itemstring);
338 #include "luaentity_common.h"
340 // Prototype (registers item for deserialization)
341 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
343 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
344 const std::string &name, const std::string &state):
345 ServerActiveObject(env, pos),
349 m_prop(new LuaEntityProperties),
352 m_acceleration(0,0,0),
355 m_last_sent_position(0,0,0),
356 m_last_sent_velocity(0,0,0),
357 m_last_sent_position_timer(0),
358 m_last_sent_move_precision(0),
359 m_armor_groups_sent(false)
361 // Only register type if no environment supplied
363 ServerActiveObject::registerType(getType(), create);
367 // Initialize something to armor groups
368 m_armor_groups["fleshy"] = 3;
369 m_armor_groups["snappy"] = 2;
372 LuaEntitySAO::~LuaEntitySAO()
375 lua_State *L = m_env->getLua();
376 scriptapi_luaentity_rm(L, m_id);
381 void LuaEntitySAO::addedToEnvironment()
383 ServerActiveObject::addedToEnvironment();
385 // Create entity from name
386 lua_State *L = m_env->getLua();
387 m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
391 scriptapi_luaentity_get_properties(L, m_id, m_prop);
392 // Initialize HP from properties
393 m_hp = m_prop->hp_max;
396 // Activate entity, supplying serialized state
397 scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
400 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
401 const std::string &data)
409 std::istringstream is(data, std::ios::binary);
411 u8 version = readU8(is);
412 // check if version is supported
414 name = deSerializeString(is);
415 state = deSerializeLongString(is);
417 else if(version == 1){
418 name = deSerializeString(is);
419 state = deSerializeLongString(is);
421 velocity = readV3F1000(is);
426 infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
427 <<state<<"\")"<<std::endl;
428 LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
430 sao->m_velocity = velocity;
435 void LuaEntitySAO::step(float dtime, bool send_recommended)
437 m_last_sent_position_timer += dtime;
439 if(m_prop->physical){
440 core::aabbox3d<f32> box = m_prop->collisionbox;
443 collisionMoveResult moveresult;
444 f32 pos_max_d = BS*0.25; // Distance per iteration
445 v3f p_pos = getBasePosition();
446 v3f p_velocity = m_velocity;
447 IGameDef *gamedef = m_env->getGameDef();
448 moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
449 pos_max_d, box, dtime, p_pos, p_velocity);
451 setBasePosition(p_pos);
452 m_velocity = p_velocity;
454 m_velocity += dtime * m_acceleration;
456 m_base_position += dtime * m_velocity + 0.5 * dtime
457 * dtime * m_acceleration;
458 m_velocity += dtime * m_acceleration;
462 lua_State *L = m_env->getLua();
463 scriptapi_luaentity_step(L, m_id, dtime);
466 if(send_recommended == false)
469 // TODO: force send when acceleration changes enough?
470 float minchange = 0.2*BS;
471 if(m_last_sent_position_timer > 1.0){
473 } else if(m_last_sent_position_timer > 0.2){
476 float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
477 move_d += m_last_sent_move_precision;
478 float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
479 if(move_d > minchange || vel_d > minchange ||
480 fabs(m_yaw - m_last_sent_yaw) > 1.0){
481 sendPosition(true, false);
484 if(m_armor_groups_sent == false){
485 m_armor_groups_sent = true;
486 std::ostringstream os(std::ios::binary);
487 writeU8(os, LUAENTITY_CMD_UPDATE_ARMOR_GROUPS);
488 writeU16(os, m_armor_groups.size());
489 for(ItemGroupList::const_iterator i = m_armor_groups.begin();
490 i != m_armor_groups.end(); i++){
491 os<<serializeString(i->first);
492 writeS16(os, i->second);
494 // create message and add to list
495 ActiveObjectMessage aom(getId(), true, os.str());
496 m_messages_out.push_back(aom);
500 std::string LuaEntitySAO::getClientInitializationData()
502 std::ostringstream os(std::ios::binary);
506 writeV3F1000(os, m_base_position);
508 writeF1000(os, m_yaw);
512 std::ostringstream prop_os(std::ios::binary);
513 m_prop->serialize(prop_os);
514 os<<serializeLongString(prop_os.str());
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::ostringstream os(std::ios::binary);
579 writeU8(os, LUAENTITY_CMD_PUNCHED);
581 writeS16(os, result.damage);
583 writeS16(os, getHP());
584 // create message and add to list
585 ActiveObjectMessage aom(getId(), true, os.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::ostringstream os(std::ios::binary);
688 writeU8(os, LUAENTITY_CMD_SET_TEXTURE_MOD);
690 os<<serializeString(mod);
691 // create message and add to list
692 ActiveObjectMessage aom(getId(), false, os.str());
693 m_messages_out.push_back(aom);
696 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
697 bool select_horiz_by_yawpitch)
699 std::ostringstream os(std::ios::binary);
701 writeU8(os, LUAENTITY_CMD_SET_SPRITE);
704 writeU16(os, num_frames);
705 writeF1000(os, framelength);
706 writeU8(os, select_horiz_by_yawpitch);
707 // create message and add to list
708 ActiveObjectMessage aom(getId(), false, os.str());
709 m_messages_out.push_back(aom);
712 std::string LuaEntitySAO::getName()
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::ostringstream os(std::ios::binary);
731 writeU8(os, LUAENTITY_CMD_UPDATE_POSITION);
734 writeU8(os, do_interpolate);
736 writeV3F1000(os, m_base_position);
738 writeV3F1000(os, m_velocity);
740 writeV3F1000(os, m_acceleration);
742 writeF1000(os, m_yaw);
743 // is_end_position (for interpolation)
744 writeU8(os, is_movement_end);
745 // update_interval (for interpolation)
746 writeF1000(os, update_interval);
748 // create message and add to list
749 ActiveObjectMessage aom(getId(), false, os.str());
750 m_messages_out.push_back(aom);
757 // No prototype, PlayerSAO does not need to be deserialized
759 PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
760 ServerActiveObject(env_, v3f(0,0,0)),
764 m_last_good_position(0,0,0),
765 m_last_good_position_age(0),
766 m_time_from_last_punch(0),
768 m_position_not_sent(false),
769 m_armor_groups_sent(false),
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);
833 os<<serializeString(m_player->getName());
835 writeV3F1000(os, m_player->getPosition());
837 writeF1000(os, m_player->getYaw());
839 writeU8(os, getHP() == 0);
841 os<<serializeString(getWieldedItem().getItemString());
845 std::string PlayerSAO::getStaticData()
851 void PlayerSAO::step(float dtime, bool send_recommended)
853 m_time_from_last_punch += dtime;
856 Check player movements
858 NOTE: Actually the server should handle player physics like the
859 client does and compare player's position to what is calculated
860 on our side. This is required when eg. players fly due to an
864 //float player_max_speed = BS * 4.0; // Normal speed
865 float player_max_speed = BS * 20; // Fast speed
866 float player_max_speed_up = BS * 20;
867 player_max_speed *= 2.5; // Tolerance
868 player_max_speed_up *= 2.5;
870 m_last_good_position_age += dtime;
871 if(m_last_good_position_age >= 1.0){
872 float age = m_last_good_position_age;
873 v3f diff = (m_player->getPosition() - m_last_good_position);
874 float d_vert = diff.Y;
876 float d_horiz = diff.getLength();
877 /*infostream<<m_player->getName()<<"'s horizontal speed is "
878 <<(d_horiz/age)<<std::endl;*/
879 if(d_horiz <= age * player_max_speed &&
880 (d_vert < 0 || d_vert < age * player_max_speed_up)){
881 m_last_good_position = m_player->getPosition();
883 actionstream<<"Player "<<m_player->getName()
884 <<" moved too fast; resetting position"
886 m_player->setPosition(m_last_good_position);
889 m_last_good_position_age = 0;
892 if(send_recommended == false)
895 if(m_position_not_sent)
897 m_position_not_sent = false;
899 std::ostringstream os(std::ios::binary);
900 // command (0 = update position)
903 writeV3F1000(os, m_player->getPosition());
905 writeF1000(os, m_player->getYaw());
906 // create message and add to list
907 ActiveObjectMessage aom(getId(), false, os.str());
908 m_messages_out.push_back(aom);
911 if(m_wielded_item_not_sent)
913 m_wielded_item_not_sent = false;
915 std::ostringstream os(std::ios::binary);
916 // command (3 = wielded item)
919 os<<serializeString(getWieldedItem().getItemString());
920 // create message and add to list
921 ActiveObjectMessage aom(getId(), false, os.str());
922 m_messages_out.push_back(aom);
926 void PlayerSAO::setBasePosition(const v3f &position)
928 ServerActiveObject::setBasePosition(position);
929 m_position_not_sent = true;
932 void PlayerSAO::setPos(v3f pos)
934 m_player->setPosition(pos);
935 // Movement caused by this command is always valid
936 m_last_good_position = pos;
937 m_last_good_position_age = 0;
938 // Force position change on client
942 void PlayerSAO::moveTo(v3f pos, bool continuous)
944 m_player->setPosition(pos);
945 // Movement caused by this command is always valid
946 m_last_good_position = pos;
947 m_last_good_position_age = 0;
948 // Force position change on client
952 int PlayerSAO::punch(v3f dir,
953 const ToolCapabilities *toolcap,
954 ServerActiveObject *puncher,
955 float time_from_last_punch)
960 // No effect if PvP disabled
961 if(g_settings->getBool("enable_pvp") == false){
962 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
966 HitParams hitparams = getHitParams(m_armor_groups, toolcap,
967 time_from_last_punch);
969 actionstream<<"Player "<<m_player->getName()<<" punched by "
970 <<puncher->getDescription()<<", damage "<<hitparams.hp
973 setHP(getHP() - hitparams.hp);
975 if(hitparams.hp != 0)
977 std::ostringstream os(std::ios::binary);
978 // command (1 = punched)
981 writeS16(os, hitparams.hp);
982 // create message and add to list
983 ActiveObjectMessage aom(getId(), false, os.str());
984 m_messages_out.push_back(aom);
987 return hitparams.wear;
990 void PlayerSAO::rightClick(ServerActiveObject *clicker)
994 s16 PlayerSAO::getHP() const
999 void PlayerSAO::setHP(s16 hp)
1001 s16 oldhp = m_player->hp;
1005 else if(hp > PLAYER_MAX_HP)
1008 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1010 m_hp_not_sent = true; // fix wrong prediction on client
1017 m_hp_not_sent = true;
1019 // On death or reincarnation send an active object message
1020 if((hp == 0) != (oldhp == 0))
1022 std::ostringstream os(std::ios::binary);
1023 // command (2 = update death state)
1026 writeU8(os, hp == 0);
1027 // create message and add to list
1028 ActiveObjectMessage aom(getId(), false, os.str());
1029 m_messages_out.push_back(aom);
1033 void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1035 m_armor_groups = armor_groups;
1036 m_armor_groups_sent = false;
1039 Inventory* PlayerSAO::getInventory()
1043 const Inventory* PlayerSAO::getInventory() const
1048 InventoryLocation PlayerSAO::getInventoryLocation() const
1050 InventoryLocation loc;
1051 loc.setPlayer(m_player->getName());
1055 void PlayerSAO::setInventoryModified()
1057 m_inventory_not_sent = true;
1060 std::string PlayerSAO::getWieldList() const
1065 int PlayerSAO::getWieldIndex() const
1067 return m_wield_index;
1070 void PlayerSAO::setWieldIndex(int i)
1072 if(i != m_wield_index)
1075 m_wielded_item_not_sent = true;
1079 void PlayerSAO::disconnected()
1083 if(m_player->getPlayerSAO() == this)
1085 m_player->setPlayerSAO(NULL);
1086 m_player->peer_id = 0;
1090 void PlayerSAO::createCreativeInventory()
1092 if(m_inventory != &m_player->inventory)
1095 m_inventory = new Inventory(m_player->inventory);
1096 m_inventory->clearContents();
1097 scriptapi_get_creative_inventory(m_env->getLua(), this);