subgame.cpp
inventorymanager.cpp
mods.cpp
- serverremoteplayer.cpp
content_abm.cpp
craftdef.cpp
nameidmapping.cpp
}
else if(command == TOCLIENT_PLAYERITEM)
{
- std::string datastring((char*)&data[2], datasize-2);
- std::istringstream is(datastring, std::ios_base::binary);
-
- u16 count = readU16(is);
-
- for (u16 i = 0; i < count; ++i) {
- u16 peer_id = readU16(is);
- Player *player = m_env.getPlayer(peer_id);
-
- if (player == NULL)
- {
- infostream<<"Client: ignoring player item "
- << deSerializeString(is)
- << " for non-existing peer id " << peer_id
- << std::endl;
- continue;
- } else if (player->isLocal()) {
- infostream<<"Client: ignoring player item "
- << deSerializeString(is)
- << " for local player" << std::endl;
- continue;
- } else {
- InventoryList *inv = player->inventory.getList("main");
- std::string itemstring(deSerializeString(is));
- ItemStack item;
- item.deSerialize(itemstring, m_itemdef);
- inv->changeItem(0, item);
- if(itemstring.empty())
- {
- infostream<<"Client: empty player item for peer "
- <<peer_id<<std::endl;
- }
- else
- {
- infostream<<"Client: player item for peer "
- <<peer_id<<": "<<itemstring<<std::endl;
- }
- }
- }
+ infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
}
else if(command == TOCLIENT_DEATHSCREEN)
{
wstring reason
*/
- TOCLIENT_PLAYERITEM = 0x36,
+ TOCLIENT_PLAYERITEM = 0x36, // Obsolete
/*
u16 command
u16 count of player items
// Length of cracking animation in count of images
#define CRACK_ANIMATION_LENGTH 5
-// Some stuff needed by old code moved to here from heightmap.h
-#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
-#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
+// Maximum hit points of a player
+#define PLAYER_MAX_HP 20
#endif
float m_damage_visual_timer;
bool m_dead;
float m_step_distance_counter;
+ std::string m_wielded_item;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
m_local_player(NULL),
m_damage_visual_timer(0),
m_dead(false),
- m_step_distance_counter(0)
+ m_step_distance_counter(0),
+ m_wielded_item("")
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
m_yaw = readF1000(is);
// dead
m_dead = readU8(is);
+ // wielded item
+ try{
+ m_wielded_item = deSerializeString(is);
+ }
+ catch(SerializationError &e){}
pos_translator.init(m_position);
m_dead = readU8(is);
updateVisibility();
}
+ else if(cmd == 3) // wielded item
+ {
+ m_wielded_item = deSerializeString(is);
+ updateWieldedItem();
+ }
}
void updateTextures(const std::string &mod)
}
}
}
+
+ void updateWieldedItem()
+ {
+ if(m_is_local_player)
+ {
+ // ignoring player item for local player
+ return;
+ }
+
+ ItemStack item;
+ try
+ {
+ item.deSerialize(m_wielded_item, m_gamedef->idef());
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"PlayerCAO: SerializationError "
+ "while reading wielded item: "
+ <<m_wielded_item<<std::endl;
+ return;
+ }
+
+ // do something with the item, for example:
+ Player *player = m_env->getPlayer(m_name.c_str());
+ if(player)
+ {
+ InventoryList *inv = player->inventory.getList("main");
+ assert(inv);
+ inv->changeItem(0, item);
+ }
+
+ if(item.empty())
+ {
+ infostream<<"PlayerCAO: empty player item for player "
+ <<m_name<<std::endl;
+ }
+ else
+ {
+ infostream<<"PlayerCAO: player item for player "
+ <<m_name<<": "
+ <<item.getItemString()<<std::endl;
+ }
+ }
+
};
// Prototype
#include "serialization.h" // For compressZlib
#include "tool.h" // For ToolCapabilities
#include "gamedef.h"
+#include "player.h"
+#include "scriptapi.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
LuaEntitySAO
*/
-#include "scriptapi.h"
#include "luaentity_common.h"
// Prototype (registers item for deserialization)
m_hp = hp;
}
-s16 LuaEntitySAO::getHP()
+s16 LuaEntitySAO::getHP() const
{
return m_hp;
}
m_messages_out.push_back(aom);
}
+/*
+ PlayerSAO
+*/
+
+// No prototype, PlayerSAO does not need to be deserialized
+
+PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
+ ServerActiveObject(env_, v3f(0,0,0)),
+ m_player(player_),
+ m_peer_id(peer_id_),
+ m_inventory(NULL),
+ m_last_good_position(0,0,0),
+ m_last_good_position_age(0),
+ m_time_from_last_punch(0),
+ m_wield_index(0),
+ m_position_not_sent(false),
+ m_teleported(false),
+ m_inventory_not_sent(false),
+ m_hp_not_sent(false),
+ m_wielded_item_not_sent(false)
+{
+ assert(m_player);
+ assert(m_peer_id != 0);
+ setBasePosition(m_player->getPosition());
+ m_inventory = &m_player->inventory;
+}
+
+PlayerSAO::~PlayerSAO()
+{
+ if(m_inventory != &m_player->inventory)
+ delete m_inventory;
+
+}
+
+std::string PlayerSAO::getDescription()
+{
+ return std::string("player ") + m_player->getName();
+}
+
+// Called after id has been set and has been inserted in environment
+void PlayerSAO::addedToEnvironment()
+{
+ ServerActiveObject::addedToEnvironment();
+ ServerActiveObject::setBasePosition(m_player->getPosition());
+ m_player->setPlayerSAO(this);
+ m_player->peer_id = m_peer_id;
+ m_last_good_position = m_player->getPosition();
+ m_last_good_position_age = 0.0;
+}
+
+// Called before removing from environment
+void PlayerSAO::removingFromEnvironment()
+{
+ ServerActiveObject::removingFromEnvironment();
+ if(m_player->getPlayerSAO() == this)
+ {
+ m_player->setPlayerSAO(NULL);
+ m_player->peer_id = 0;
+ }
+}
+
+bool PlayerSAO::isStaticAllowed() const
+{
+ return false;
+}
+
+bool PlayerSAO::unlimitedTransferDistance() const
+{
+ return g_settings->getBool("unlimited_player_transfer_distance");
+}
+
+std::string PlayerSAO::getClientInitializationData()
+{
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // name
+ os<<serializeString(m_player->getName());
+ // pos
+ writeV3F1000(os, m_player->getPosition());
+ // yaw
+ writeF1000(os, m_player->getYaw());
+ // dead
+ writeU8(os, getHP() == 0);
+ // wielded item
+ os<<serializeString(getWieldedItem().getItemString());
+ return os.str();
+}
+
+std::string PlayerSAO::getStaticData()
+{
+ assert(0);
+ return "";
+}
+
+void PlayerSAO::step(float dtime, bool send_recommended)
+{
+ m_time_from_last_punch += dtime;
+
+ /*
+ Check player movements
+
+ NOTE: Actually the server should handle player physics like the
+ client does and compare player's position to what is calculated
+ on our side. This is required when eg. players fly due to an
+ explosion.
+ */
+
+ //float player_max_speed = BS * 4.0; // Normal speed
+ float player_max_speed = BS * 20; // Fast speed
+ float player_max_speed_up = BS * 20;
+ player_max_speed *= 2.5; // Tolerance
+ player_max_speed_up *= 2.5;
+
+ m_last_good_position_age += dtime;
+ if(m_last_good_position_age >= 1.0){
+ float age = m_last_good_position_age;
+ v3f diff = (m_player->getPosition() - m_last_good_position);
+ float d_vert = diff.Y;
+ diff.Y = 0;
+ float d_horiz = diff.getLength();
+ /*infostream<<m_player->getName()<<"'s horizontal speed is "
+ <<(d_horiz/age)<<std::endl;*/
+ if(d_horiz <= age * player_max_speed &&
+ (d_vert < 0 || d_vert < age * player_max_speed_up)){
+ m_last_good_position = m_player->getPosition();
+ } else {
+ actionstream<<"Player "<<m_player->getName()
+ <<" moved too fast; resetting position"
+ <<std::endl;
+ m_player->setPosition(m_last_good_position);
+ m_teleported = true;
+ }
+ m_last_good_position_age = 0;
+ }
+
+ if(send_recommended == false)
+ return;
+
+ if(m_position_not_sent)
+ {
+ m_position_not_sent = false;
+
+ std::ostringstream os(std::ios::binary);
+ // command (0 = update position)
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_player->getPosition());
+ // yaw
+ writeF1000(os, m_player->getYaw());
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+
+ if(m_wielded_item_not_sent)
+ {
+ m_wielded_item_not_sent = false;
+
+ std::ostringstream os(std::ios::binary);
+ // command (3 = wielded item)
+ writeU8(os, 3);
+ // wielded item
+ os<<serializeString(getWieldedItem().getItemString());
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+void PlayerSAO::setBasePosition(const v3f &position)
+{
+ ServerActiveObject::setBasePosition(position);
+ m_position_not_sent = true;
+}
+
+void PlayerSAO::setPos(v3f pos)
+{
+ m_player->setPosition(pos);
+ // Movement caused by this command is always valid
+ m_last_good_position = pos;
+ m_last_good_position_age = 0;
+ // Force position change on client
+ m_teleported = true;
+}
+
+void PlayerSAO::moveTo(v3f pos, bool continuous)
+{
+ m_player->setPosition(pos);
+ // Movement caused by this command is always valid
+ m_last_good_position = pos;
+ m_last_good_position_age = 0;
+ // Force position change on client
+ m_teleported = true;
+}
+
+int PlayerSAO::punch(v3f dir,
+ const ToolCapabilities *toolcap,
+ ServerActiveObject *puncher,
+ float time_from_last_punch)
+{
+ if(!toolcap)
+ return 0;
+
+ // No effect if PvP disabled
+ if(g_settings->getBool("enable_pvp") == false){
+ if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ return 0;
+ }
+
+ // "Material" groups of the player
+ ItemGroupList groups;
+ groups["choppy"] = 2;
+ groups["fleshy"] = 3;
+
+ HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
+
+ actionstream<<"Player "<<m_player->getName()<<" punched by "
+ <<puncher->getDescription()<<", damage "<<hitparams.hp
+ <<" HP"<<std::endl;
+
+ setHP(getHP() - hitparams.hp);
+
+ if(hitparams.hp != 0)
+ {
+ std::ostringstream os(std::ios::binary);
+ // command (1 = punched)
+ writeU8(os, 1);
+ // damage
+ writeS16(os, hitparams.hp);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+
+ return hitparams.wear;
+}
+
+void PlayerSAO::rightClick(ServerActiveObject *clicker)
+{
+}
+
+s16 PlayerSAO::getHP() const
+{
+ return m_player->hp;
+}
+
+void PlayerSAO::setHP(s16 hp)
+{
+ s16 oldhp = m_player->hp;
+
+ if(hp < 0)
+ hp = 0;
+ else if(hp > PLAYER_MAX_HP)
+ hp = PLAYER_MAX_HP;
+
+ if(hp < oldhp && g_settings->getBool("enable_damage") == false)
+ {
+ m_hp_not_sent = true; // fix wrong prediction on client
+ return;
+ }
+
+ m_player->hp = hp;
+
+ if(hp != oldhp)
+ m_hp_not_sent = true;
+
+ // On death or reincarnation send an active object message
+ if((hp == 0) != (oldhp == 0))
+ {
+ std::ostringstream os(std::ios::binary);
+ // command (2 = update death state)
+ writeU8(os, 2);
+ // dead?
+ writeU8(os, hp == 0);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+Inventory* PlayerSAO::getInventory()
+{
+ return m_inventory;
+}
+const Inventory* PlayerSAO::getInventory() const
+{
+ return m_inventory;
+}
+
+InventoryLocation PlayerSAO::getInventoryLocation() const
+{
+ InventoryLocation loc;
+ loc.setPlayer(m_player->getName());
+ return loc;
+}
+
+void PlayerSAO::setInventoryModified()
+{
+ m_inventory_not_sent = true;
+}
+
+std::string PlayerSAO::getWieldList() const
+{
+ return "main";
+}
+
+int PlayerSAO::getWieldIndex() const
+{
+ return m_wield_index;
+}
+
+void PlayerSAO::setWieldIndex(int i)
+{
+ if(i != m_wield_index)
+ {
+ m_wield_index = i;
+ m_wielded_item_not_sent = true;
+ }
+}
+
+void PlayerSAO::disconnected()
+{
+ m_peer_id = 0;
+ m_removed = true;
+ if(m_player->getPlayerSAO() == this)
+ {
+ m_player->setPlayerSAO(NULL);
+ m_player->peer_id = 0;
+ }
+}
+
+void PlayerSAO::createCreativeInventory()
+{
+ if(m_inventory != &m_player->inventory)
+ delete m_inventory;
+
+ m_inventory = new Inventory(m_player->inventory);
+ m_inventory->clearContents();
+ scriptapi_get_creative_inventory(m_env->getLua(), this);
+}
+
#include "serverobject.h"
#include "content_object.h"
#include "itemgroup.h"
+#include "player.h"
ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
const std::string itemstring);
/*
- LuaEntitySAO
-
- This is the only SAO that needs to have a bunch of it's internals exposed.
+ LuaEntitySAO needs some internals exposed.
*/
struct LuaEntityProperties;
float getMinimumSavedMovement();
std::string getDescription();
void setHP(s16 hp);
- s16 getHP();
+ s16 getHP() const;
/* LuaEntitySAO-specific */
void setVelocity(v3f velocity);
v3f getVelocity();
bool m_armor_groups_sent;
};
+/*
+ PlayerSAO needs some internals exposed.
+*/
+
+class PlayerSAO : public ServerActiveObject
+{
+public:
+ PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_);
+ ~PlayerSAO();
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_PLAYER;}
+ std::string getDescription();
+
+ /*
+ Active object <-> environment interface
+ */
+
+ void addedToEnvironment();
+ void removingFromEnvironment();
+ bool isStaticAllowed() const;
+ bool unlimitedTransferDistance() const;
+ std::string getClientInitializationData();
+ std::string getStaticData();
+ void step(float dtime, bool send_recommended);
+ void setBasePosition(const v3f &position);
+ void setPos(v3f pos);
+ void moveTo(v3f pos, bool continuous);
+
+ /*
+ Interaction interface
+ */
+
+ int punch(v3f dir,
+ const ToolCapabilities *toolcap,
+ ServerActiveObject *puncher,
+ float time_from_last_punch);
+ void rightClick(ServerActiveObject *clicker);
+ s16 getHP() const;
+ void setHP(s16 hp);
+
+ /*
+ Inventory interface
+ */
+
+ Inventory* getInventory();
+ const Inventory* getInventory() const;
+ InventoryLocation getInventoryLocation() const;
+ void setInventoryModified();
+ std::string getWieldList() const;
+ int getWieldIndex() const;
+ void setWieldIndex(int i);
+
+ /*
+ PlayerSAO-specific
+ */
+
+ void disconnected();
+
+ void createCreativeInventory();
+
+ Player* getPlayer()
+ {
+ return m_player;
+ }
+ u16 getPeerID() const
+ {
+ return m_peer_id;
+ }
+ v3f getLastGoodPosition() const
+ {
+ return m_last_good_position;
+ }
+ float resetTimeFromLastPunch()
+ {
+ float r = m_time_from_last_punch;
+ m_time_from_last_punch = 0.0;
+ return r;
+ }
+
+private:
+ Player *m_player;
+ u16 m_peer_id;
+ Inventory *m_inventory;
+ v3f m_last_good_position;
+ float m_last_good_position_age;
+ float m_time_from_last_punch;
+ int m_wield_index;
+ bool m_position_not_sent;
+
+public:
+ // Some flags used by Server
+ bool m_teleported;
+ bool m_inventory_not_sent;
+ bool m_hp_not_sent;
+ bool m_wielded_item_not_sent;
+};
+
#endif
#include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler
#include "gamedef.h"
-#include "serverremoteplayer.h"
#ifndef SERVER
#include "clientmap.h"
#endif
//infostream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
- ServerRemotePlayer testplayer(this);
+ RemotePlayer testplayer(m_gamedef);
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
//infostream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
- ServerRemotePlayer testplayer(this);
+ RemotePlayer testplayer(m_gamedef);
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
if(player == NULL)
{
//infostream<<"Is a new player"<<std::endl;
- player = new ServerRemotePlayer(this);
+ player = new RemotePlayer(m_gamedef);
newplayer = true;
}
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
-
// Load player
{
verbosestream<<"Reading player "<<testplayer.getName()<<" from "
infostream<<"Failed to read "<<path<<std::endl;
continue;
}
- srp->deSerialize(is);
- srp->m_last_good_position = srp->getBasePosition();
- srp->m_last_good_position_age = 0;
+ player->deSerialize(is);
}
if(newplayer)
catch(InvalidPositionException &e){
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
}
- player->updateLight(light);
+ player->light = light;
}
/*
obj->setId(id);
- obj->initialize(init_data);
-
+ try
+ {
+ obj->initialize(init_data);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"ClientEnvironment::addActiveObject():"
+ <<" id="<<id<<" type="<<type
+ <<": SerializationError in initialize(),"
+ <<" init_data="<<serializeJsonString(init_data)
+ <<std::endl;
+ }
+
addActiveObject(obj);
}
<<std::endl;
return;
}
- obj->processMessage(data);
+ try
+ {
+ obj->processMessage(data);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"ClientEnvironment::processActiveObjectMessage():"
+ <<" id="<<id<<" type="<<obj->getType()
+ <<" SerializationError in processMessage(),"
+ <<" message="<<serializeJsonString(data)
+ <<std::endl;
+ }
}
/*
m_lists.clear();
}
+void Inventory::clearContents()
+{
+ for(u32 i=0; i<m_lists.size(); i++)
+ {
+ InventoryList *list = m_lists[i];
+ for(u32 j=0; j<list->getSize(); j++)
+ {
+ list->deleteItem(j);
+ }
+ }
+}
+
Inventory::Inventory(IItemDefManager *itemdef)
{
m_itemdef = itemdef;
~Inventory();
void clear();
+ void clearContents();
Inventory(IItemDefManager *itemdef);
Inventory(const Inventory &other);
#include "environment.h"
#include "gamedef.h"
#include "event.h"
+#include "content_sao.h"
Player::Player(IGameDef *gamedef):
touching_ground(false),
is_climbing(false),
swimming_up(false),
inventory(gamedef->idef()),
- inventory_backup(NULL),
- hp(20),
+ hp(PLAYER_MAX_HP),
peer_id(PEER_ID_INEXISTENT),
// protected
m_gamedef(gamedef),
m_position(0,0,0)
{
updateName("<not set>");
- resetInventory();
-}
-
-Player::~Player()
-{
- delete inventory_backup;
-}
-
-void Player::resetInventory()
-{
inventory.clear();
inventory.addList("main", PLAYER_INVENTORY_SIZE);
inventory.addList("craft", 9);
inventory.addList("craftresult", 1);
}
+Player::~Player()
+{
+}
+
// Y direction is ignored
void Player::accelerate(v3f target_speed, f32 max_increase)
{
os<<"PlayerArgsEnd\n";
- // If actual inventory is backed up due to creative mode, save it
- // instead of the dummy creative mode inventory
- if(inventory_backup)
- inventory_backup->serialize(os);
- else
- inventory.serialize(os);
+ inventory.serialize(os);
}
void Player::deSerialize(std::istream &is)
#endif
+/*
+ RemotePlayer
+*/
+
+void RemotePlayer::setPosition(const v3f &position)
+{
+ Player::setPosition(position);
+ if(m_sao)
+ m_sao->setBasePosition(position);
+}
class Map;
class IGameDef;
struct CollisionInfo;
+class PlayerSAO;
class Player
{
public:
Player(IGameDef *gamedef);
- virtual ~Player();
+ virtual ~Player() = 0;
- void resetInventory();
-
- //void move(f32 dtime, Map &map);
- virtual void move(f32 dtime, Map &map, f32 pos_max_d) = 0;
+ virtual void move(f32 dtime, Map &map, f32 pos_max_d)
+ {}
v3f getSpeed()
{
return (m_yaw + 90.) * core::DEGTORAD;
}
- virtual void updateName(const char *name)
+ void updateName(const char *name)
{
snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
}
return m_name;
}
- virtual bool isLocal() const = 0;
+ virtual bool isLocal() const
+ { return false; }
+ virtual PlayerSAO *getPlayerSAO()
+ { return NULL; }
+ virtual void setPlayerSAO(PlayerSAO *sao)
+ { assert(0); }
- virtual void updateLight(u8 light_at_pos)
- {
- light = light_at_pos;
- }
-
- // NOTE: Use peer_id == 0 for disconnected
- /*virtual bool isClientConnected() { return false; }
- virtual void setClientConnected(bool) {}*/
-
/*
serialize() writes a bunch of text that can contain
any characters except a '\0', and such an ending that
u8 light;
+ // In creative mode, this is the invisible backup inventory
Inventory inventory;
- // Actual inventory is backed up here when creative mode is used
- Inventory *inventory_backup;
u16 hp;
f32 m_yaw;
v3f m_speed;
v3f m_position;
-
-public:
-
};
#ifndef SERVER
};
#endif // !SERVER
+/*
+ Player on the server
+*/
+class RemotePlayer : public Player
+{
+public:
+ RemotePlayer(IGameDef *gamedef): Player(gamedef), m_sao(0) {}
+ virtual ~RemotePlayer() {}
+
+ PlayerSAO *getPlayerSAO()
+ { return m_sao; }
+ void setPlayerSAO(PlayerSAO *sao)
+ { m_sao = sao; }
+ void setPosition(const v3f &position);
+
+private:
+ PlayerSAO *m_sao;
+};
+
#endif
#include "script.h"
//#include "luna.h"
#include "luaentity_common.h"
-#include "content_sao.h" // For LuaEntitySAO
+#include "content_sao.h" // For LuaEntitySAO and PlayerSAO
#include "itemdef.h"
#include "nodedef.h"
#include "craftdef.h"
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
lua_State *L, int tableindex, int forcesize=-1)
{
- dstream<<"inventory_set_list_from_lua\n";
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
invlist->deleteItem(index);
index++;
}
- dstream<<"inventory_set_list_from_lua done\n";
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
return (LuaEntitySAO*)obj;
}
- static ServerRemotePlayer* getplayer(ObjectRef *ref)
+ static PlayerSAO* getplayersao(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
if(obj == NULL)
return NULL;
if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
return NULL;
- return static_cast<ServerRemotePlayer*>(obj);
+ return (PlayerSAO*)obj;
+ }
+
+ static Player* getplayer(ObjectRef *ref)
+ {
+ PlayerSAO *playersao = getplayersao(ref);
+ if(playersao == NULL)
+ return NULL;
+ return playersao->getPlayer();
}
// Exported functions
v3f pos = checkFloatPos(L, 2);
// Do it
co->setPos(pos);
- // Move player if applicable
- ServerRemotePlayer *player = getplayer(ref);
- if(player != NULL)
- get_server(L)->SendMovePlayer(player);
return 0;
}
static int l_get_player_name(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL){
lua_pushnil(L);
return 1;
static int l_get_look_dir(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
float pitch = player->getRadPitch();
static int l_get_look_pitch(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadPitch());
static int l_get_look_yaw(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
+ Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadYaw());
if(env == NULL) return 0;
// Do it
const char *name = luaL_checkstring(L, 2);
- ServerRemotePlayer *player =
- static_cast<ServerRemotePlayer*>(env->getPlayer(name));
+ Player *player = env->getPlayer(name);
if(player == NULL){
lua_pushnil(L);
return 1;
}
+ PlayerSAO *sao = player->getPlayerSAO();
+ if(sao == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
// Put player on stack
- objectref_get_or_create(L, player);
+ objectref_get_or_create(L, sao);
return 1;
}
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
- dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
-
bool positioning_handled_by_some = false;
// Get minetest.registered_on_respawnplayers
return positioning_handled_by_some;
}
-void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
+void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
{
+ Inventory *inv = player->getInventory();
+ assert(inv);
+
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
- inventory_set_list_from_lua(&player->inventory, "main", L, -1,
- PLAYER_INVENTORY_SIZE);
+ inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
}
/*
class Server;
class ServerEnvironment;
class ServerActiveObject;
-class ServerRemotePlayer;
typedef struct lua_State lua_State;
struct LuaEntityProperties;
struct ItemStack;
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
-void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
+void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
/* item callbacks */
bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
#include "config.h"
#include "servercommand.h"
#include "filesys.h"
-#include "content_mapnode.h"
-#include "content_nodemeta.h"
#include "mapblock.h"
#include "serverobject.h"
#include "settings.h"
#include "itemdef.h"
#include "craftdef.h"
#include "mapgen.h"
+#include "content_mapnode.h"
+#include "content_nodemeta.h"
#include "content_abm.h"
+#include "content_sao.h"
#include "mods.h"
#include "sha1.h"
#include "base64.h"
return NULL;
}
+v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
+{
+ if(pos_exists) *pos_exists = false;
+ switch(type){
+ case SSP_LOCAL:
+ return v3f(0,0,0);
+ case SSP_POSITIONAL:
+ if(pos_exists) *pos_exists = true;
+ return pos;
+ case SSP_OBJECT: {
+ if(object == 0)
+ return v3f(0,0,0);
+ ServerActiveObject *sao = env->getActiveObject(object);
+ if(!sao)
+ return v3f(0,0,0);
+ if(pos_exists) *pos_exists = true;
+ return sao->getBasePosition(); }
+ }
+ return v3f(0,0,0);
+}
+
void RemoteClient::GetNextBlocks(Server *server, float dtime,
core::array<PrioritySortedBlockTransfer> &dest)
{
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
- //Player *player = m_env->getPlayer(client->peer_id);
-
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
// Send as reliable
ScopeProfiler sp(g_profiler, "Server: handle players");
- //float player_max_speed = BS * 4.0; // Normal speed
- float player_max_speed = BS * 20; // Fast speed
- float player_max_speed_up = BS * 20;
-
- player_max_speed *= 2.5; // Tolerance
- player_max_speed_up *= 2.5;
-
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
- ServerRemotePlayer *player =
- static_cast<ServerRemotePlayer*>
- (m_env->getPlayer(client->peer_id));
- if(player==NULL)
+ PlayerSAO *playersao = getPlayerSAO(client->peer_id);
+ if(playersao == NULL){
+ errorstream<<"Handling client without PlayerSAO, peer_id="<<client->peer_id<<std::endl;
continue;
-
- /*
- Check player movements
-
- NOTE: Actually the server should handle player physics like the
- client does and compare player's position to what is calculated
- on our side. This is required when eg. players fly due to an
- explosion.
- */
- player->m_last_good_position_age += dtime;
- if(player->m_last_good_position_age >= 1.0){
- float age = player->m_last_good_position_age;
- v3f diff = (player->getPosition() - player->m_last_good_position);
- float d_vert = diff.Y;
- diff.Y = 0;
- float d_horiz = diff.getLength();
- /*infostream<<player->getName()<<"'s horizontal speed is "
- <<(d_horiz/age)<<std::endl;*/
- if(d_horiz <= age * player_max_speed &&
- (d_vert < 0 || d_vert < age * player_max_speed_up)){
- player->m_last_good_position = player->getPosition();
- } else {
- actionstream<<"Player "<<player->getName()
- <<" moved too fast; resetting position"
- <<std::endl;
- player->setPosition(player->m_last_good_position);
- SendMovePlayer(player);
- }
- player->m_last_good_position_age = 0;
}
/*
Handle player HPs (die if hp=0)
*/
- if(player->hp == 0 && player->m_hp_not_sent)
- DiePlayer(player);
+ if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
+ DiePlayer(client->peer_id);
/*
Send player inventories and HPs if necessary
*/
- if(player->m_inventory_not_sent){
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
+ if(playersao->m_teleported){
+ SendMovePlayer(client->peer_id);
+ playersao->m_teleported = false;
}
- if(player->m_hp_not_sent){
- SendPlayerHP(player);
+ if(playersao->m_inventory_not_sent){
+ UpdateCrafting(client->peer_id);
+ SendInventory(client->peer_id);
}
-
- /*
- Add to environment
- */
- if(!player->m_is_in_environment){
- player->m_removed = false;
- player->setId(0);
- m_env->addActiveObject(player);
+ if(playersao->m_hp_not_sent){
+ SendPlayerHP(client->peer_id);
}
}
}
}
// Get player
- ServerRemotePlayer *player = emergePlayer(playername, peer_id);
+ PlayerSAO *playersao = emergePlayer(playername, peer_id);
// If failed, cancel
- if(player == NULL)
+ if(playersao == NULL)
{
errorstream<<"Server: peer_id="<<peer_id
<<": failed to emerge player"<<std::endl;
SharedBuffer<u8> reply(2+1+6+8);
writeU16(&reply[0], TOCLIENT_INIT);
writeU8(&reply[2], deployed);
- writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+ writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
// Send as reliable
/*
Send complete position information
*/
- SendMovePlayer(player);
+ SendMovePlayer(peer_id);
return;
}
UpdateCrafting(peer_id);
SendInventory(peer_id);
- // Send player items to all players
- SendPlayerItems();
-
Player *player = m_env->getPlayer(peer_id);
// Send HP
- SendPlayerHP(player);
+ SendPlayerHP(peer_id);
// Show death screen if necessary
if(player->hp == 0)
- SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
+ SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
// Send time of day
{
}
Player *player = m_env->getPlayer(peer_id);
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
-
if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
"No player for peer_id="<<peer_id
<<std::endl;
return;
}
+
+ PlayerSAO *playersao = player->getPlayerSAO();
+ if(playersao == NULL){
+ infostream<<"Server::ProcessData(): Cancelling: "
+ "No player object for peer_id="<<peer_id
+ <<std::endl;
+ return;
+ }
+
if(command == TOSERVER_PLAYERPOS)
{
if(datasize < 2+12+12+4+4)
}
// Do the action
- a->apply(this, srp, this);
+ a->apply(this, playersao, this);
// Eat the action
delete a;
}
std::istringstream is(datastring, std::ios_base::binary);
u8 damage = readU8(is);
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
-
- if(g_settings->getBool("enable_damage"))
- {
- actionstream<<player->getName()<<" damaged by "
- <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
- <<std::endl;
+ actionstream<<player->getName()<<" damaged by "
+ <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
+ <<std::endl;
- srp->setHP(srp->getHP() - damage);
+ playersao->setHP(playersao->getHP() - damage);
- if(srp->getHP() == 0 && srp->m_hp_not_sent)
- DiePlayer(srp);
+ if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
+ DiePlayer(peer_id);
- if(srp->m_hp_not_sent)
- SendPlayerHP(player);
- }
- else
- {
- // Force send (to correct the client's predicted HP)
- SendPlayerHP(player);
- }
+ if(playersao->m_hp_not_sent)
+ SendPlayerHP(peer_id);
}
else if(command == TOSERVER_PASSWORD)
{
return;
u16 item = readU16(&data[2]);
- srp->setWieldIndex(item);
- SendWieldedItem(srp);
+ playersao->setWieldIndex(item);
}
else if(command == TOSERVER_RESPAWN)
{
if(player->hp != 0)
return;
- RespawnPlayer(player);
+ RespawnPlayer(peer_id);
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
if(player->hp == 0)
{
- verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
+ verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
<<" tried to interact, but is dead!"<<std::endl;
return;
}
- v3f player_pos = srp->m_last_good_position;
+ v3f player_pos = playersao->getLastGoodPosition();
// Update wielded item
- if(srp->getWieldIndex() != item_i)
- {
- srp->setWieldIndex(item_i);
- SendWieldedItem(srp);
- }
+ playersao->setWieldIndex(item_i);
// Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface;
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
if(n.getContent() != CONTENT_IGNORE)
- scriptapi_node_on_punch(m_lua, p_under, n, srp);
+ scriptapi_node_on_punch(m_lua, p_under, n, playersao);
}
else if(pointed.type == POINTEDTHING_OBJECT)
{
<<pointed.object_id<<": "
<<pointed_object->getDescription()<<std::endl;
- ItemStack punchitem = srp->getWieldedItem();
+ ItemStack punchitem = playersao->getWieldedItem();
ToolCapabilities toolcap =
punchitem.getToolCapabilities(m_itemdef);
v3f dir = (pointed_object->getBasePosition() -
- (srp->getPosition() + srp->getEyeOffset())
+ (player->getPosition() + player->getEyeOffset())
).normalize();
- pointed_object->punch(dir, &toolcap, srp,
- srp->m_time_from_last_punch);
- srp->m_time_from_last_punch = 0;
+ float time_from_last_punch =
+ playersao->resetTimeFromLastPunch();
+ pointed_object->punch(dir, &toolcap, playersao,
+ time_from_last_punch);
}
} // action == 0
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
if(n.getContent() != CONTENT_IGNORE)
- scriptapi_node_on_dig(m_lua, p_under, n, srp);
+ scriptapi_node_on_dig(m_lua, p_under, n, playersao);
}
} // action == 2
*/
else if(action == 3)
{
- ItemStack item = srp->getWieldedItem();
+ ItemStack item = playersao->getWieldedItem();
// Reset build time counter
if(pointed.type == POINTEDTHING_NODE &&
<<pointed_object->getDescription()<<std::endl;
// Do stuff
- pointed_object->rightClick(srp);
+ pointed_object->rightClick(playersao);
}
else if(scriptapi_item_on_place(m_lua,
- item, srp, pointed))
+ item, playersao, pointed))
{
// Placement was handled in lua
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
- srp->setWieldedItem(item);
+ playersao->setWieldedItem(item);
}
} // action == 3
*/
else if(action == 4)
{
- ItemStack item = srp->getWieldedItem();
+ ItemStack item = playersao->getWieldedItem();
actionstream<<player->getName()<<" uses "<<item.name
<<", pointing at "<<pointed.dump()<<std::endl;
if(scriptapi_item_on_use(m_lua,
- item, srp, pointed))
+ item, playersao, pointed))
{
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
- srp->setWieldedItem(item);
+ playersao->setWieldedItem(item);
}
} // action == 4
Player *player = m_env->getPlayer(loc.name.c_str());
if(!player)
return NULL;
- return &player->inventory;
+ PlayerSAO *playersao = player->getPlayerSAO();
+ if(!playersao)
+ return NULL;
+ return playersao->getInventory();
}
break;
case InventoryLocation::NODEMETA:
break;
case InventoryLocation::PLAYER:
{
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
- (m_env->getPlayer(loc.name.c_str()));
- if(!srp)
+ Player *player = m_env->getPlayer(loc.name.c_str());
+ if(!player)
+ return;
+ PlayerSAO *playersao = player->getPlayerSAO();
+ if(!playersao)
return;
- srp->m_inventory_not_sent = true;
+ playersao->m_inventory_not_sent = true;
+ playersao->m_wielded_item_not_sent = true;
}
break;
case InventoryLocation::NODEMETA:
{
DSTACK(__FUNCTION_NAME);
- ServerRemotePlayer* player =
- static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
- assert(player);
+ PlayerSAO *playersao = getPlayerSAO(peer_id);
+ assert(playersao);
- player->m_inventory_not_sent = false;
+ playersao->m_inventory_not_sent = false;
/*
Serialize it
*/
std::ostringstream os;
- //os.imbue(std::locale("C"));
-
- player->inventory.serialize(os);
+ playersao->getInventory()->serialize(os);
std::string s = os.str();
m_con.Send(peer_id, 0, data, true);
}
-void Server::SendWieldedItem(const ServerRemotePlayer* srp)
-{
- DSTACK(__FUNCTION_NAME);
-
- assert(srp);
-
- std::ostringstream os(std::ios_base::binary);
-
- writeU16(os, TOCLIENT_PLAYERITEM);
- writeU16(os, 1);
- writeU16(os, srp->peer_id);
- os<<serializeString(srp->getWieldedItem().getItemString());
-
- // Make data buffer
- std::string s = os.str();
- SharedBuffer<u8> data((u8*)s.c_str(), s.size());
-
- m_con.SendToAll(0, data, true);
-}
-
-void Server::SendPlayerItems()
-{
- DSTACK(__FUNCTION_NAME);
-
- std::ostringstream os(std::ios_base::binary);
- core::list<Player *> players = m_env->getPlayers(true);
-
- writeU16(os, TOCLIENT_PLAYERITEM);
- writeU16(os, players.size());
- core::list<Player *>::Iterator i;
- for(i = players.begin(); i != players.end(); ++i)
- {
- Player *p = *i;
- ServerRemotePlayer *srp =
- static_cast<ServerRemotePlayer*>(p);
- writeU16(os, p->peer_id);
- os<<serializeString(srp->getWieldedItem().getItemString());
- }
-
- // Make data buffer
- std::string s = os.str();
- SharedBuffer<u8> data((u8*)s.c_str(), s.size());
-
- m_con.SendToAll(0, data, true);
-}
-
void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
{
DSTACK(__FUNCTION_NAME);
}
}
-void Server::SendPlayerHP(Player *player)
+void Server::SendPlayerHP(u16 peer_id)
{
- SendHP(m_con, player->peer_id, player->hp);
- static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
+ DSTACK(__FUNCTION_NAME);
+ PlayerSAO *playersao = getPlayerSAO(peer_id);
+ assert(playersao);
+ playersao->m_hp_not_sent = false;
+ SendHP(m_con, peer_id, playersao->getHP());
}
-void Server::SendMovePlayer(Player *player)
+void Server::SendMovePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
- std::ostringstream os(std::ios_base::binary);
+ Player *player = m_env->getPlayer(peer_id);
+ assert(player);
+ std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_MOVE_PLAYER);
writeV3F1000(os, player->getPosition());
writeF1000(os, player->getPitch());
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(player->peer_id, 0, data, true);
+ m_con.Send(peer_id, 0, data, true);
}
s32 Server::playSound(const SimpleSoundSpec &spec,
Something random
*/
-void Server::DiePlayer(Player *player)
+void Server::DiePlayer(u16 peer_id)
{
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+ DSTACK(__FUNCTION_NAME);
+
+ PlayerSAO *playersao = getPlayerSAO(peer_id);
+ assert(playersao);
infostream<<"Server::DiePlayer(): Player "
- <<player->getName()<<" dies"<<std::endl;
-
- srp->setHP(0);
-
+ <<playersao->getPlayer()->getName()
+ <<" dies"<<std::endl;
+
+ playersao->setHP(0);
+
// Trigger scripted stuff
- scriptapi_on_dieplayer(m_lua, srp);
-
- // Handle players that are not connected
- if(player->peer_id == PEER_ID_INEXISTENT){
- RespawnPlayer(player);
- return;
- }
+ scriptapi_on_dieplayer(m_lua, playersao);
- SendPlayerHP(player);
- SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
+ SendPlayerHP(peer_id);
+ SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
}
-void Server::RespawnPlayer(Player *player)
+void Server::RespawnPlayer(u16 peer_id)
{
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
- srp->setHP(20);
- bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
+ DSTACK(__FUNCTION_NAME);
+
+ PlayerSAO *playersao = getPlayerSAO(peer_id);
+ assert(playersao);
+
+ infostream<<"Server::RespawnPlayer(): Player "
+ <<playersao->getPlayer()->getName()
+ <<" respawns"<<std::endl;
+
+ playersao->setHP(PLAYER_MAX_HP);
+
+ bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
if(!repositioned){
v3f pos = findSpawnPos(m_env->getServerMap());
- player->setPosition(pos);
- srp->m_last_good_position = pos;
- srp->m_last_good_position_age = 0;
+ playersao->setPos(pos);
}
- SendMovePlayer(player);
- SendPlayerHP(player);
}
void Server::UpdateCrafting(u16 peer_id)
return intToFloat(nodepos, BS);
}
-ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
+PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
{
+ RemotePlayer *player = NULL;
+ bool newplayer = false;
+
/*
Try to get an existing player
*/
- ServerRemotePlayer *player =
- static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
- if(player != NULL)
- {
- // If player is already connected, cancel
- if(player->peer_id != 0)
- {
- infostream<<"emergePlayer(): Player already connected"<<std::endl;
- return NULL;
- }
-
- // Got one.
- player->peer_id = peer_id;
-
- // Re-add player to environment
- if(player->m_removed)
- {
- player->m_removed = false;
- player->setId(0);
- m_env->addActiveObject(player);
- }
+ player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
- // Reset inventory to creative if in creative mode
- if(g_settings->getBool("creative_mode"))
- {
- // Warning: double code below
- // Backup actual inventory
- player->inventory_backup = new Inventory(m_itemdef);
- *(player->inventory_backup) = player->inventory;
- // Set creative inventory
- player->resetInventory();
- scriptapi_get_creative_inventory(m_lua, player);
- }
-
- return player;
+ // If player is already connected, cancel
+ if(player != NULL && player->peer_id != 0)
+ {
+ infostream<<"emergePlayer(): Player already connected"<<std::endl;
+ return NULL;
}
/*
" peer_id already exists"<<std::endl;
return NULL;
}
-
+
/*
- Create a new player
+ Create a new player if it doesn't exist yet
*/
+ if(player == NULL)
{
+ newplayer = true;
+ player = new RemotePlayer(this);
+ player->updateName(name);
+
/* Set player position */
-
infostream<<"Server: Finding spawn place for player \""
<<name<<"\""<<std::endl;
-
v3f pos = findSpawnPos(m_env->getServerMap());
-
- player = new ServerRemotePlayer(m_env, pos, peer_id, name);
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+ player->setPosition(pos);
/* Add player to environment */
m_env->addPlayer(player);
- m_env->addActiveObject(srp);
+ }
- /* Run scripts */
- scriptapi_on_newplayer(m_lua, srp);
+ /*
+ Create a new player active object
+ */
+ PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id);
- /* Add stuff to inventory */
- if(g_settings->getBool("creative_mode"))
- {
- // Warning: double code above
- // Backup actual inventory
- player->inventory_backup = new Inventory(m_itemdef);
- *(player->inventory_backup) = player->inventory;
- // Set creative inventory
- player->resetInventory();
- scriptapi_get_creative_inventory(m_lua, player);
- }
+ /* Add object to environment */
+ m_env->addActiveObject(playersao);
- return player;
-
- } // create new player
+ /* Run scripts */
+ if(newplayer)
+ scriptapi_on_newplayer(m_lua, playersao);
+
+ /* Creative mode */
+ if(g_settings->getBool("creative_mode"))
+ playersao->createCreativeInventory();
+
+ return playersao;
}
void Server::handlePeerChange(PeerChange &c)
i++;
}
- ServerRemotePlayer* player =
- static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
+ Player *player = m_env->getPlayer(c.peer_id);
// Collect information about leaving in chat
std::wstring message;
}
// Remove from environment
- if(player != NULL)
- player->m_removed = true;
-
- // Set player client disconnected
- if(player != NULL)
- player->peer_id = 0;
+ if(player->getPlayerSAO())
+ player->getPlayerSAO()->disconnected();
/*
Print out action
#include "ban.h"
#include "gamedef.h"
#include "serialization.h" // For SER_FMT_VER_INVALID
-#include "serverremoteplayer.h"
#include "mods.h"
#include "inventorymanager.h"
#include "subgame.h"
class IWritableNodeDefManager;
class IWritableCraftDefManager;
class EventManager;
+class PlayerSAO;
class ServerError : public std::exception
{
loop(false)
{}
- v3f getPos(ServerEnvironment *env, bool *pos_exists) const
- {
- if(pos_exists) *pos_exists = false;
- switch(type){
- case SSP_LOCAL:
- return v3f(0,0,0);
- case SSP_POSITIONAL:
- if(pos_exists) *pos_exists = true;
- return pos;
- case SSP_OBJECT: {
- if(object == 0)
- return v3f(0,0,0);
- ServerActiveObject *sao = env->getActiveObject(object);
- if(!sao)
- return v3f(0,0,0);
- if(pos_exists) *pos_exists = true;
- return sao->getBasePosition(); }
- }
- return v3f(0,0,0);
- }
+ v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
};
struct ServerPlayingSound
m_shutdown_requested = true;
}
- // Envlock and conlock should be locked when calling this
- void SendMovePlayer(Player *player);
-
// Returns -1 if failed, sound handle on success
// Envlock + conlock
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
*/
// Envlock and conlock should be locked when calling these
+ void SendMovePlayer(u16 peer_id);
void SendInventory(u16 peer_id);
- // send wielded item info about player to all
- void SendWieldedItem(const ServerRemotePlayer *srp);
- // send wielded item info about all players to all players
- void SendPlayerItems();
void SendChatMessage(u16 peer_id, const std::wstring &message);
void BroadcastChatMessage(const std::wstring &message);
- void SendPlayerHP(Player *player);
+ void SendPlayerHP(u16 peer_id);
/*
Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than
Something random
*/
- void DiePlayer(Player *player);
- void RespawnPlayer(Player *player);
+ void DiePlayer(u16 peer_id);
+ void RespawnPlayer(u16 peer_id);
void UpdateCrafting(u16 peer_id);
return player->getName();
}
+ // When called, environment mutex should be locked
+ PlayerSAO* getPlayerSAO(u16 peer_id)
+ {
+ Player *player = m_env->getPlayer(peer_id);
+ if(player == NULL)
+ return NULL;
+ return player->getPlayerSAO();
+ }
+
/*
Get a player from memory or creates one.
If player is already connected, return NULL
Call with env and con locked.
*/
- ServerRemotePlayer *emergePlayer(const char *name, u16 peer_id);
+ PlayerSAO *emergePlayer(const char *name, u16 peer_id);
// Locks environment and connection by its own
struct PeerChange;
#include "utility.h"
#include "settings.h"
#include "main.h" // For g_settings
+#include "content_sao.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
return;
}
- v3f dest(stoi(coords[0])*10, stoi(coords[1])*10, stoi(coords[2])*10);
+ v3f dest(stoi(coords[0])*BS, stoi(coords[1])*BS, stoi(coords[2])*BS);
actionstream<<ctx->player->getName()<<" teleports from "
<<PP(ctx->player->getPosition()/BS)<<" to "
<<PP(dest/BS)<<std::endl;
- //ctx->player->setPosition(dest);
-
- // Use the ServerActiveObject interface of ServerRemotePlayer
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(ctx->player);
- srp->setPos(dest);
- ctx->server->SendMovePlayer(ctx->player);
-
- os<< L"-!- Teleported.";
+ // Use the ServerActiveObject interface of RemotePlayer
+ // This forces a position change on the client
+ ServerActiveObject *sao = ctx->player->getPlayerSAO();
+ if(sao)
+ {
+ sao->setPos(dest);
+ os<< L"-!- Teleported.";
+ }
+ else
+ {
+ errorstream<<"Teleport failed, player object not found!"
+ <<std::endl;
+ os<< L"-!- Teleport failed.";
+ }
}
void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
{}
virtual void setHP(s16 hp)
{}
- virtual s16 getHP()
+ virtual s16 getHP() const
{ return 0; }
// Inventory and wielded item
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "serverremoteplayer.h"
-#include "main.h" // For g_settings
-#include "settings.h"
-#include "log.h"
-#include "gamedef.h"
-#include "inventory.h"
-#include "environment.h"
-#include "tool.h"
-
-ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
- Player(env->getGameDef()),
- ServerActiveObject(env, v3f(0,0,0)),
- m_last_good_position(0,0,0),
- m_last_good_position_age(0),
- m_wield_index(0),
- m_inventory_not_sent(false),
- m_hp_not_sent(false),
- m_is_in_environment(false),
- m_time_from_last_punch(0),
- m_position_not_sent(false)
-{
-}
-ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
- const char *name_):
- Player(env->getGameDef()),
- ServerActiveObject(env, pos_),
- m_last_good_position(0,0,0),
- m_last_good_position_age(0),
- m_wield_index(0),
- m_inventory_not_sent(false),
- m_hp_not_sent(false),
- m_is_in_environment(false),
- m_time_from_last_punch(0),
- m_position_not_sent(false)
-{
- setPosition(pos_);
- peer_id = peer_id_;
- updateName(name_);
-}
-ServerRemotePlayer::~ServerRemotePlayer()
-{
-}
-
-void ServerRemotePlayer::setPosition(const v3f &position)
-{
- Player::setPosition(position);
- ServerActiveObject::setBasePosition(position);
- m_position_not_sent = true;
-}
-
-Inventory* ServerRemotePlayer::getInventory()
-{
- return &inventory;
-}
-
-const Inventory* ServerRemotePlayer::getInventory() const
-{
- return &inventory;
-}
-
-InventoryLocation ServerRemotePlayer::getInventoryLocation() const
-{
- InventoryLocation loc;
- loc.setPlayer(getName());
- return loc;
-}
-
-void ServerRemotePlayer::setInventoryModified()
-{
- m_inventory_not_sent = true;
-}
-
-std::string ServerRemotePlayer::getWieldList() const
-{
- return "main";
-}
-
-int ServerRemotePlayer::getWieldIndex() const
-{
- return m_wield_index;
-}
-
-void ServerRemotePlayer::setWieldIndex(int i)
-{
- m_wield_index = i;
-}
-
-/* ServerActiveObject interface */
-
-void ServerRemotePlayer::addedToEnvironment()
-{
- assert(!m_is_in_environment);
- m_is_in_environment = true;
-}
-
-void ServerRemotePlayer::removingFromEnvironment()
-{
- assert(m_is_in_environment);
- m_is_in_environment = false;
-}
-
-bool ServerRemotePlayer::unlimitedTransferDistance() const
-{
- return g_settings->getBool("unlimited_player_transfer_distance");
-}
-
-void ServerRemotePlayer::step(float dtime, bool send_recommended)
-{
- m_time_from_last_punch += dtime;
-
- if(send_recommended == false)
- return;
-
- if(m_position_not_sent)
- {
- m_position_not_sent = false;
-
- std::ostringstream os(std::ios::binary);
- // command (0 = update position)
- writeU8(os, 0);
- // pos
- writeV3F1000(os, getPosition());
- // yaw
- writeF1000(os, getYaw());
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- m_messages_out.push_back(aom);
- }
-}
-
-std::string ServerRemotePlayer::getClientInitializationData()
-{
- std::ostringstream os(std::ios::binary);
- // version
- writeU8(os, 0);
- // name
- os<<serializeString(getName());
- // pos
- writeV3F1000(os, getPosition());
- // yaw
- writeF1000(os, getYaw());
- // dead
- writeU8(os, getHP() == 0);
- return os.str();
-}
-
-std::string ServerRemotePlayer::getStaticData()
-{
- assert(0);
- return "";
-}
-
-int ServerRemotePlayer::punch(v3f dir,
- const ToolCapabilities *toolcap,
- ServerActiveObject *puncher,
- float time_from_last_punch)
-{
- if(!toolcap)
- return 0;
-
- // No effect if PvP disabled
- if(g_settings->getBool("enable_pvp") == false){
- if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
- return 0;
- }
-
- // "Material" groups of the player
- ItemGroupList groups;
- groups["choppy"] = 2;
- groups["fleshy"] = 3;
-
- HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
-
- actionstream<<"Player "<<getName()<<" punched by "
- <<puncher->getDescription()<<", damage "<<hitparams.hp
- <<" HP"<<std::endl;
-
- setHP(getHP() - hitparams.hp);
-
- if(hitparams.hp != 0)
- {
- std::ostringstream os(std::ios::binary);
- // command (1 = punched)
- writeU8(os, 1);
- // damage
- writeS16(os, hitparams.hp);
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- m_messages_out.push_back(aom);
- }
-
- return hitparams.wear;
-}
-
-void ServerRemotePlayer::rightClick(ServerActiveObject *clicker)
-{
-}
-
-void ServerRemotePlayer::setPos(v3f pos)
-{
- setPosition(pos);
- // Movement caused by this command is always valid
- m_last_good_position = pos;
- m_last_good_position_age = 0;
-}
-void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
-{
- setPosition(pos);
- // Movement caused by this command is always valid
- m_last_good_position = pos;
- m_last_good_position_age = 0;
-}
-
-void ServerRemotePlayer::setHP(s16 hp_)
-{
- s16 oldhp = hp;
-
- // FIXME: don't hardcode maximum HP, make configurable per object
- if(hp_ < 0)
- hp_ = 0;
- else if(hp_ > 20)
- hp_ = 20;
- hp = hp_;
-
- if(hp != oldhp)
- m_hp_not_sent = true;
-
- // On death or reincarnation send an active object message
- if((hp == 0) != (oldhp == 0))
- {
- std::ostringstream os(std::ios::binary);
- // command (2 = update death state)
- writeU8(os, 2);
- // dead?
- writeU8(os, hp == 0);
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- m_messages_out.push_back(aom);
- }
-}
-s16 ServerRemotePlayer::getHP()
-{
- return hp;
-}
-
-
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#ifndef SERVERREMOTEPLAYER_HEADER
-#define SERVERREMOTEPLAYER_HEADER
-
-#include "player.h"
-#include "serverobject.h"
-#include "content_object.h" // Object type IDs
-
-/*
- Player on the server
-*/
-
-class ServerRemotePlayer : public Player, public ServerActiveObject
-{
-public:
- ServerRemotePlayer(ServerEnvironment *env);
- ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
- const char *name_);
-
- virtual ~ServerRemotePlayer();
-
- virtual bool isLocal() const
- { return false; }
-
- virtual void move(f32 dtime, Map &map, f32 pos_max_d)
- {
- }
-
- virtual void setPosition(const v3f &position);
-
- /* ServerActiveObject interface */
-
- u8 getType() const
- {return ACTIVEOBJECT_TYPE_PLAYER;}
-
- // Called after id has been set and has been inserted in environment
- void addedToEnvironment();
- // Called before removing from environment
- void removingFromEnvironment();
-
- bool environmentDeletes() const
- { return false; }
-
- virtual bool unlimitedTransferDistance() const;
-
- bool isStaticAllowed() const
- { return false; }
-
- void step(float dtime, bool send_recommended);
- std::string getClientInitializationData();
- std::string getStaticData();
- int punch(v3f dir,
- const ToolCapabilities *toolcap,
- ServerActiveObject *puncher,
- float time_from_last_punch);
- void rightClick(ServerActiveObject *clicker);
- void setPos(v3f pos);
- void moveTo(v3f pos, bool continuous);
- virtual std::string getDescription()
- {return std::string("player ")+getName();}
-
- virtual Inventory* getInventory();
- virtual const Inventory* getInventory() const;
- virtual InventoryLocation getInventoryLocation() const;
- virtual void setInventoryModified();
- virtual std::string getWieldList() const;
- virtual int getWieldIndex() const;
- virtual void setWieldIndex(int i);
-
- virtual void setHP(s16 hp_);
- virtual s16 getHP();
-
- v3f m_last_good_position;
- float m_last_good_position_age;
- int m_wield_index;
- bool m_inventory_not_sent;
- bool m_hp_not_sent;
- bool m_is_in_environment;
- // Incremented by step(), read and reset by Server
- float m_time_from_last_punch;
-
-private:
- bool m_position_not_sent;
-};
-
-#endif
-