diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/client.cpp | 40 | ||||
-rw-r--r-- | src/clientserver.h | 2 | ||||
-rw-r--r-- | src/constants.h | 5 | ||||
-rw-r--r-- | src/content_cao.cpp | 58 | ||||
-rw-r--r-- | src/content_sao.cpp | 347 | ||||
-rw-r--r-- | src/content_sao.h | 104 | ||||
-rw-r--r-- | src/environment.cpp | 43 | ||||
-rw-r--r-- | src/inventory.cpp | 12 | ||||
-rw-r--r-- | src/inventory.h | 1 | ||||
-rw-r--r-- | src/player.cpp | 35 | ||||
-rw-r--r-- | src/player.h | 52 | ||||
-rw-r--r-- | src/scriptapi.cpp | 48 | ||||
-rw-r--r-- | src/scriptapi.h | 3 | ||||
-rw-r--r-- | src/server.cpp | 439 | ||||
-rw-r--r-- | src/server.h | 48 | ||||
-rw-r--r-- | src/servercommand.cpp | 25 | ||||
-rw-r--r-- | src/serverobject.h | 2 | ||||
-rw-r--r-- | src/serverremoteplayer.cpp | 265 | ||||
-rw-r--r-- | src/serverremoteplayer.h | 105 |
20 files changed, 829 insertions, 806 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f963e24d..2558be9cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -159,7 +159,6 @@ set(common_SRCS subgame.cpp inventorymanager.cpp mods.cpp - serverremoteplayer.cpp content_abm.cpp craftdef.cpp nameidmapping.cpp diff --git a/src/client.cpp b/src/client.cpp index 29872fb6e..7f1b39c33 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1397,45 +1397,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) } 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) { diff --git a/src/clientserver.h b/src/clientserver.h index 203f8a727..def4570e1 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -200,7 +200,7 @@ enum ToClientCommand wstring reason */ - TOCLIENT_PLAYERITEM = 0x36, + TOCLIENT_PLAYERITEM = 0x36, // Obsolete /* u16 command u16 count of player items diff --git a/src/constants.h b/src/constants.h index a7cf1709b..d4afc96d7 100644 --- a/src/constants.h +++ b/src/constants.h @@ -99,9 +99,8 @@ with this program; if not, write to the Free Software Foundation, Inc., // 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 diff --git a/src/content_cao.cpp b/src/content_cao.cpp index fc1df377a..11c9ad9c6 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1011,6 +1011,7 @@ private: float m_damage_visual_timer; bool m_dead; float m_step_distance_counter; + std::string m_wielded_item; public: PlayerCAO(IGameDef *gamedef, ClientEnvironment *env): @@ -1024,7 +1025,8 @@ public: 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); @@ -1048,6 +1050,11 @@ public: 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); @@ -1263,6 +1270,11 @@ public: m_dead = readU8(is); updateVisibility(); } + else if(cmd == 3) // wielded item + { + m_wielded_item = deSerializeString(is); + updateWieldedItem(); + } } void updateTextures(const std::string &mod) @@ -1288,6 +1300,50 @@ public: } } } + + 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 diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 85340981d..d01b023de 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #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; @@ -333,7 +335,6 @@ ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos, LuaEntitySAO */ -#include "scriptapi.h" #include "luaentity_common.h" // Prototype (registers item for deserialization) @@ -610,7 +611,7 @@ void LuaEntitySAO::setHP(s16 hp) m_hp = hp; } -s16 LuaEntitySAO::getHP() +s16 LuaEntitySAO::getHP() const { return m_hp; } @@ -749,3 +750,345 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) 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); +} + diff --git a/src/content_sao.h b/src/content_sao.h index 53e701d8c..9ceb6ed6a 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -23,14 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #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; @@ -59,7 +58,7 @@ public: float getMinimumSavedMovement(); std::string getDescription(); void setHP(s16 hp); - s16 getHP(); + s16 getHP() const; /* LuaEntitySAO-specific */ void setVelocity(v3f velocity); v3f getVelocity(); @@ -94,5 +93,102 @@ private: 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 diff --git a/src/environment.cpp b/src/environment.cpp index e713ab610..5e8f5edba 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -37,7 +37,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodemetadata.h" #include "main.h" // For g_settings, g_profiler #include "gamedef.h" -#include "serverremoteplayer.h" #ifndef SERVER #include "clientmap.h" #endif @@ -368,7 +367,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir) //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); @@ -482,7 +481,7 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir) //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); @@ -510,12 +509,10 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir) 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 " @@ -527,9 +524,7 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir) 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) @@ -2074,7 +2069,7 @@ void ClientEnvironment::step(float dtime) catch(InvalidPositionException &e){ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); } - player->updateLight(light); + player->light = light; } /* @@ -2226,8 +2221,19 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type, 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); } @@ -2258,7 +2264,18 @@ void ClientEnvironment::processActiveObjectMessage(u16 id, <<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; + } } /* diff --git a/src/inventory.cpp b/src/inventory.cpp index 056cf552d..3d6707f60 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -795,6 +795,18 @@ void Inventory::clear() 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; diff --git a/src/inventory.h b/src/inventory.h index e27da15d5..0f620e83c 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -250,6 +250,7 @@ public: ~Inventory(); void clear(); + void clearContents(); Inventory(IItemDefManager *itemdef); Inventory(const Inventory &other); diff --git a/src/player.cpp b/src/player.cpp index 0d4a1cb69..ff272322f 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "gamedef.h" #include "event.h" +#include "content_sao.h" Player::Player(IGameDef *gamedef): touching_ground(false), @@ -40,8 +41,7 @@ Player::Player(IGameDef *gamedef): 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), @@ -51,16 +51,6 @@ Player::Player(IGameDef *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); @@ -68,6 +58,10 @@ void Player::resetInventory() inventory.addList("craftresult", 1); } +Player::~Player() +{ +} + // Y direction is ignored void Player::accelerate(v3f target_speed, f32 max_increase) { @@ -126,12 +120,7 @@ void Player::serialize(std::ostream &os) 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) @@ -779,3 +768,13 @@ v3s16 LocalPlayer::getStandingNodePos() #endif +/* + RemotePlayer +*/ + +void RemotePlayer::setPosition(const v3f &position) +{ + Player::setPosition(position); + if(m_sao) + m_sao->setBasePosition(position); +} diff --git a/src/player.h b/src/player.h index d0e1ac799..b6856b1d0 100644 --- a/src/player.h +++ b/src/player.h @@ -31,18 +31,17 @@ with this program; if not, write to the Free Software Foundation, Inc., 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() { @@ -112,7 +111,7 @@ public: return (m_yaw + 90.) * core::DEGTORAD; } - virtual void updateName(const char *name) + void updateName(const char *name) { snprintf(m_name, PLAYERNAME_SIZE, "%s", name); } @@ -122,17 +121,13 @@ public: 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 @@ -151,9 +146,8 @@ public: 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; @@ -167,9 +161,6 @@ protected: f32 m_yaw; v3f m_speed; v3f m_position; - -public: - }; #ifndef SERVER @@ -249,5 +240,24 @@ private: }; #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 diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 863e2ba28..f8e4c471c 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -35,7 +35,7 @@ extern "C" { #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" @@ -1095,7 +1095,6 @@ static ItemStack read_item(lua_State *L, int index); 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 @@ -1127,7 +1126,6 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name, invlist->deleteItem(index); index++; } - dstream<<"inventory_set_list_from_lua done\n"; } static void inventory_get_list_to_lua(Inventory *inv, const char *name, @@ -2259,14 +2257,22 @@ private: 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 @@ -2319,10 +2325,6 @@ private: 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; } @@ -2626,7 +2628,7 @@ private: 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; @@ -2640,7 +2642,7 @@ private: 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(); @@ -2654,7 +2656,7 @@ private: 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()); @@ -2665,7 +2667,7 @@ private: 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()); @@ -2996,14 +2998,18 @@ private: 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; } @@ -4211,8 +4217,6 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) 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 @@ -4238,13 +4242,15 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) 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); } /* diff --git a/src/scriptapi.h b/src/scriptapi.h index 373262888..c2c099a6d 100644 --- a/src/scriptapi.h +++ b/src/scriptapi.h @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., class Server; class ServerEnvironment; class ServerActiveObject; -class ServerRemotePlayer; typedef struct lua_State lua_State; struct LuaEntityProperties; struct ItemStack; @@ -58,7 +57,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp, 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, diff --git a/src/server.cpp b/src/server.cpp index c83fce3b0..163528235 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -30,8 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #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" @@ -43,7 +41,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #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" @@ -379,6 +380,27 @@ void * EmergeThread::Thread() 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) { @@ -1250,8 +1272,6 @@ void Server::AsyncRunStep() 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 @@ -1291,78 +1311,36 @@ void Server::AsyncRunStep() 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); } } } @@ -2167,10 +2145,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 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; @@ -2184,7 +2162,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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 @@ -2194,7 +2172,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Send complete position information */ - SendMovePlayer(player); + SendMovePlayer(peer_id); return; } @@ -2231,17 +2209,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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 { @@ -2314,14 +2289,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } 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) @@ -2644,7 +2626,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } // Do the action - a->apply(this, srp, this); + a->apply(this, playersao, this); // Eat the action delete a; } @@ -2775,27 +2757,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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) { @@ -2865,15 +2837,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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; @@ -2934,19 +2905,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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; @@ -3038,7 +3005,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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) { @@ -3050,15 +3017,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<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 @@ -3092,7 +3060,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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 @@ -3101,7 +3069,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else if(action == 3) { - ItemStack item = srp->getWieldedItem(); + ItemStack item = playersao->getWieldedItem(); // Reset build time counter if(pointed.type == POINTEDTHING_NODE && @@ -3121,16 +3089,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<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 @@ -3140,17 +3108,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ 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 @@ -3222,7 +3190,10 @@ Inventory* Server::getInventory(const InventoryLocation &loc) 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: @@ -3273,11 +3244,14 @@ void Server::setInventoryModified(const InventoryLocation &loc) 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: @@ -3482,20 +3456,17 @@ void Server::SendInventory(u16 peer_id) { 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(); @@ -3507,52 +3478,6 @@ void Server::SendInventory(u16 peer_id) 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); @@ -3599,17 +3524,22 @@ void Server::BroadcastChatMessage(const std::wstring &message) } } -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()); @@ -3630,7 +3560,7 @@ void Server::SendMovePlayer(Player *player) 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, @@ -4242,41 +4172,44 @@ void Server::sendRequestedMedia(u16 peer_id, 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) @@ -4542,46 +4475,21 @@ v3f findSpawnPos(ServerMap &map) 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; } /* @@ -4593,43 +4501,43 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) " 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) @@ -4699,8 +4607,7 @@ 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; @@ -4717,12 +4624,8 @@ void Server::handlePeerChange(PeerChange &c) } // 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 diff --git a/src/server.h b/src/server.h index 1b0cff783..d40c7c73e 100644 --- a/src/server.h +++ b/src/server.h @@ -31,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #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" @@ -42,6 +41,7 @@ class IWritableItemDefManager; class IWritableNodeDefManager; class IWritableCraftDefManager; class EventManager; +class PlayerSAO; class ServerError : public std::exception { @@ -299,26 +299,7 @@ struct ServerSoundParams 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 @@ -514,9 +495,6 @@ public: 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); @@ -620,14 +598,11 @@ private: */ // 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 @@ -655,8 +630,8 @@ private: 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); @@ -672,6 +647,15 @@ private: 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 @@ -679,7 +663,7 @@ private: 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; diff --git a/src/servercommand.cpp b/src/servercommand.cpp index e2e84bacb..c5b242b2e 100644 --- a/src/servercommand.cpp +++ b/src/servercommand.cpp @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #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<<")" @@ -216,20 +217,26 @@ void cmd_teleport(std::wostringstream &os, 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) diff --git a/src/serverobject.h b/src/serverobject.h index 15bbe52f7..8719267d7 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -143,7 +143,7 @@ public: {} virtual void setHP(s16 hp) {} - virtual s16 getHP() + virtual s16 getHP() const { return 0; } // Inventory and wielded item diff --git a/src/serverremoteplayer.cpp b/src/serverremoteplayer.cpp deleted file mode 100644 index 667ece7f2..000000000 --- a/src/serverremoteplayer.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* -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; -} - - diff --git a/src/serverremoteplayer.h b/src/serverremoteplayer.h deleted file mode 100644 index 2ff1b0013..000000000 --- a/src/serverremoteplayer.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -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 - |