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::setHP(s16 hp)
614 s16 LuaEntitySAO::getHP() const
619 void LuaEntitySAO::setPos(v3f pos)
621 m_base_position = pos;
622 sendPosition(false, true);
625 void LuaEntitySAO::moveTo(v3f pos, bool continuous)
627 m_base_position = pos;
629 sendPosition(true, true);
632 float LuaEntitySAO::getMinimumSavedMovement()
637 std::string LuaEntitySAO::getDescription()
639 std::ostringstream os(std::ios::binary);
640 os<<"LuaEntitySAO at (";
641 os<<(m_base_position.X/BS)<<",";
642 os<<(m_base_position.Y/BS)<<",";
643 os<<(m_base_position.Z/BS);
648 void LuaEntitySAO::setVelocity(v3f velocity)
650 m_velocity = velocity;
653 v3f LuaEntitySAO::getVelocity()
658 void LuaEntitySAO::setAcceleration(v3f acceleration)
660 m_acceleration = acceleration;
663 v3f LuaEntitySAO::getAcceleration()
665 return m_acceleration;
668 void LuaEntitySAO::setYaw(float yaw)
673 float LuaEntitySAO::getYaw()
678 void LuaEntitySAO::setTextureMod(const std::string &mod)
680 std::ostringstream os(std::ios::binary);
682 writeU8(os, LUAENTITY_CMD_SET_TEXTURE_MOD);
684 os<<serializeString(mod);
685 // create message and add to list
686 ActiveObjectMessage aom(getId(), false, os.str());
687 m_messages_out.push_back(aom);
690 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
691 bool select_horiz_by_yawpitch)
693 std::ostringstream os(std::ios::binary);
695 writeU8(os, LUAENTITY_CMD_SET_SPRITE);
698 writeU16(os, num_frames);
699 writeF1000(os, framelength);
700 writeU8(os, select_horiz_by_yawpitch);
701 // create message and add to list
702 ActiveObjectMessage aom(getId(), false, os.str());
703 m_messages_out.push_back(aom);
706 std::string LuaEntitySAO::getName()
711 void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
713 m_armor_groups = armor_groups;
714 m_armor_groups_sent = false;
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),
770 m_inventory_not_sent(false),
771 m_hp_not_sent(false),
772 m_wielded_item_not_sent(false)
775 assert(m_peer_id != 0);
776 setBasePosition(m_player->getPosition());
777 m_inventory = &m_player->inventory;
780 PlayerSAO::~PlayerSAO()
782 if(m_inventory != &m_player->inventory)
787 std::string PlayerSAO::getDescription()
789 return std::string("player ") + m_player->getName();
792 // Called after id has been set and has been inserted in environment
793 void PlayerSAO::addedToEnvironment()
795 ServerActiveObject::addedToEnvironment();
796 ServerActiveObject::setBasePosition(m_player->getPosition());
797 m_player->setPlayerSAO(this);
798 m_player->peer_id = m_peer_id;
799 m_last_good_position = m_player->getPosition();
800 m_last_good_position_age = 0.0;
803 // Called before removing from environment
804 void PlayerSAO::removingFromEnvironment()
806 ServerActiveObject::removingFromEnvironment();
807 if(m_player->getPlayerSAO() == this)
809 m_player->setPlayerSAO(NULL);
810 m_player->peer_id = 0;
814 bool PlayerSAO::isStaticAllowed() const
819 bool PlayerSAO::unlimitedTransferDistance() const
821 return g_settings->getBool("unlimited_player_transfer_distance");
824 std::string PlayerSAO::getClientInitializationData()
826 std::ostringstream os(std::ios::binary);
830 os<<serializeString(m_player->getName());
832 writeV3F1000(os, m_player->getPosition());
834 writeF1000(os, m_player->getYaw());
836 writeU8(os, getHP() == 0);
838 os<<serializeString(getWieldedItem().getItemString());
842 std::string PlayerSAO::getStaticData()
848 void PlayerSAO::step(float dtime, bool send_recommended)
850 m_time_from_last_punch += dtime;
853 Check player movements
855 NOTE: Actually the server should handle player physics like the
856 client does and compare player's position to what is calculated
857 on our side. This is required when eg. players fly due to an
861 //float player_max_speed = BS * 4.0; // Normal speed
862 float player_max_speed = BS * 20; // Fast speed
863 float player_max_speed_up = BS * 20;
864 player_max_speed *= 2.5; // Tolerance
865 player_max_speed_up *= 2.5;
867 m_last_good_position_age += dtime;
868 if(m_last_good_position_age >= 1.0){
869 float age = m_last_good_position_age;
870 v3f diff = (m_player->getPosition() - m_last_good_position);
871 float d_vert = diff.Y;
873 float d_horiz = diff.getLength();
874 /*infostream<<m_player->getName()<<"'s horizontal speed is "
875 <<(d_horiz/age)<<std::endl;*/
876 if(d_horiz <= age * player_max_speed &&
877 (d_vert < 0 || d_vert < age * player_max_speed_up)){
878 m_last_good_position = m_player->getPosition();
880 actionstream<<"Player "<<m_player->getName()
881 <<" moved too fast; resetting position"
883 m_player->setPosition(m_last_good_position);
886 m_last_good_position_age = 0;
889 if(send_recommended == false)
892 if(m_position_not_sent)
894 m_position_not_sent = false;
896 std::ostringstream os(std::ios::binary);
897 // command (0 = update position)
900 writeV3F1000(os, m_player->getPosition());
902 writeF1000(os, m_player->getYaw());
903 // create message and add to list
904 ActiveObjectMessage aom(getId(), false, os.str());
905 m_messages_out.push_back(aom);
908 if(m_wielded_item_not_sent)
910 m_wielded_item_not_sent = false;
912 std::ostringstream os(std::ios::binary);
913 // command (3 = wielded item)
916 os<<serializeString(getWieldedItem().getItemString());
917 // create message and add to list
918 ActiveObjectMessage aom(getId(), false, os.str());
919 m_messages_out.push_back(aom);
923 void PlayerSAO::setBasePosition(const v3f &position)
925 ServerActiveObject::setBasePosition(position);
926 m_position_not_sent = true;
929 void PlayerSAO::setPos(v3f pos)
931 m_player->setPosition(pos);
932 // Movement caused by this command is always valid
933 m_last_good_position = pos;
934 m_last_good_position_age = 0;
935 // Force position change on client
939 void PlayerSAO::moveTo(v3f pos, bool continuous)
941 m_player->setPosition(pos);
942 // Movement caused by this command is always valid
943 m_last_good_position = pos;
944 m_last_good_position_age = 0;
945 // Force position change on client
949 int PlayerSAO::punch(v3f dir,
950 const ToolCapabilities *toolcap,
951 ServerActiveObject *puncher,
952 float time_from_last_punch)
957 // No effect if PvP disabled
958 if(g_settings->getBool("enable_pvp") == false){
959 if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
963 // "Material" groups of the player
964 ItemGroupList groups;
965 groups["choppy"] = 2;
966 groups["fleshy"] = 3;
968 HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
970 actionstream<<"Player "<<m_player->getName()<<" punched by "
971 <<puncher->getDescription()<<", damage "<<hitparams.hp
974 setHP(getHP() - hitparams.hp);
976 if(hitparams.hp != 0)
978 std::ostringstream os(std::ios::binary);
979 // command (1 = punched)
982 writeS16(os, hitparams.hp);
983 // create message and add to list
984 ActiveObjectMessage aom(getId(), false, os.str());
985 m_messages_out.push_back(aom);
988 return hitparams.wear;
991 void PlayerSAO::rightClick(ServerActiveObject *clicker)
995 s16 PlayerSAO::getHP() const
1000 void PlayerSAO::setHP(s16 hp)
1002 s16 oldhp = m_player->hp;
1006 else if(hp > PLAYER_MAX_HP)
1009 if(hp < oldhp && g_settings->getBool("enable_damage") == false)
1011 m_hp_not_sent = true; // fix wrong prediction on client
1018 m_hp_not_sent = true;
1020 // On death or reincarnation send an active object message
1021 if((hp == 0) != (oldhp == 0))
1023 std::ostringstream os(std::ios::binary);
1024 // command (2 = update death state)
1027 writeU8(os, hp == 0);
1028 // create message and add to list
1029 ActiveObjectMessage aom(getId(), false, os.str());
1030 m_messages_out.push_back(aom);
1034 Inventory* PlayerSAO::getInventory()
1038 const Inventory* PlayerSAO::getInventory() const
1043 InventoryLocation PlayerSAO::getInventoryLocation() const
1045 InventoryLocation loc;
1046 loc.setPlayer(m_player->getName());
1050 void PlayerSAO::setInventoryModified()
1052 m_inventory_not_sent = true;
1055 std::string PlayerSAO::getWieldList() const
1060 int PlayerSAO::getWieldIndex() const
1062 return m_wield_index;
1065 void PlayerSAO::setWieldIndex(int i)
1067 if(i != m_wield_index)
1070 m_wielded_item_not_sent = true;
1074 void PlayerSAO::disconnected()
1078 if(m_player->getPlayerSAO() == this)
1080 m_player->setPlayerSAO(NULL);
1081 m_player->peer_id = 0;
1085 void PlayerSAO::createCreativeInventory()
1087 if(m_inventory != &m_player->inventory)
1090 m_inventory = new Inventory(m_player->inventory);
1091 m_inventory->clearContents();
1092 scriptapi_get_creative_inventory(m_env->getLua(), this);