diff options
author | ShadowNinja <shadowninja@minetest.net> | 2014-05-30 16:04:07 -0400 |
---|---|---|
committer | ShadowNinja <shadowninja@minetest.net> | 2014-06-23 15:45:59 -0400 |
commit | 7e6db1b80344a519e53a9967a159c8d3585a9b9d (patch) | |
tree | dcdd53f2f558b8c57ca4b58a754e7ed0be015c6c | |
parent | 50127510e72732b069be040db2d2bbdad4d0be1c (diff) | |
download | minetest-7e6db1b80344a519e53a9967a159c8d3585a9b9d.tar.gz minetest-7e6db1b80344a519e53a9967a159c8d3585a9b9d.tar.bz2 minetest-7e6db1b80344a519e53a9967a159c8d3585a9b9d.zip |
Only keep players loaded while they're connected
-rw-r--r-- | src/content_sao.cpp | 2 | ||||
-rw-r--r-- | src/environment.cpp | 231 | ||||
-rw-r--r-- | src/environment.h | 18 | ||||
-rw-r--r-- | src/player.cpp | 67 | ||||
-rw-r--r-- | src/player.h | 2 | ||||
-rw-r--r-- | src/server.cpp | 103 |
6 files changed, 181 insertions, 242 deletions
diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 095c6b5bf..4ee92f4d3 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1027,6 +1027,8 @@ void PlayerSAO::removingFromEnvironment() { m_player->setPlayerSAO(NULL); m_player->peer_id = 0; + m_env->savePlayer(m_player->getName()); + m_env->removePlayer(m_player->getName()); } } diff --git a/src/environment.cpp b/src/environment.cpp index 6bbc715d0..91f5ea2b6 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -100,6 +100,18 @@ void Environment::removePlayer(u16 peer_id) } } +void Environment::removePlayer(const char *name) +{ + for (std::list<Player*>::iterator it = m_players.begin(); + it != m_players.end(); ++it) { + if (strcmp((*it)->getName(), name) == 0) { + delete *it; + m_players.erase(it); + return; + } + } +} + Player * Environment::getPlayer(u16 peer_id) { for(std::list<Player*>::iterator i = m_players.begin(); @@ -332,10 +344,12 @@ void ActiveBlockList::update(std::list<v3s16> &active_positions, */ ServerEnvironment::ServerEnvironment(ServerMap *map, - GameScripting *scriptIface, IGameDef *gamedef): + GameScripting *scriptIface, IGameDef *gamedef, + const std::string &path_world) : m_map(map), m_script(scriptIface), m_gamedef(gamedef), + m_path_world(path_world), m_send_recommended_timer(0), m_active_block_interval_overload_skip(0), m_game_time(0), @@ -401,196 +415,85 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 return true; } -void ServerEnvironment::serializePlayers(const std::string &savedir) +void ServerEnvironment::saveLoadedPlayers() { - std::string players_path = savedir + "/players"; + std::string players_path = m_path_world + DIR_DELIM "players"; fs::CreateDir(players_path); - std::set<Player*> saved_players; - - std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path); - for(u32 i=0; i<player_files.size(); i++) - { - if(player_files[i].dir || player_files[i].name[0] == '.') - continue; - - // Full path to this file - std::string path = players_path + "/" + player_files[i].name; - - //infostream<<"Checking player file "<<path<<std::endl; - - // Load player to see what is its name - RemotePlayer testplayer(m_gamedef); - { - // Open file and deserialize - std::ifstream is(path.c_str(), std::ios_base::binary); - if(is.good() == false) - { - infostream<<"Failed to read "<<path<<std::endl; - continue; - } - testplayer.deSerialize(is, player_files[i].name); - } - - //infostream<<"Loaded test player with name "<<testplayer.getName()<<std::endl; - - // Search for the player - std::string playername = testplayer.getName(); - Player *player = getPlayer(playername.c_str()); - if(player == NULL) - { - infostream<<"Didn't find matching player, ignoring file "<<path<<std::endl; - continue; - } - - //infostream<<"Found matching player, overwriting."<<std::endl; - - // OK, found. Save player there. - if(player->checkModified()) - { - // Open file and serialize - std::ostringstream ss(std::ios_base::binary); - player->serialize(ss); - if(!fs::safeWriteToFile(path, ss.str())) - { - infostream<<"Failed to write "<<path<<std::endl; - continue; - } - saved_players.insert(player); - } else { - saved_players.insert(player); + for (std::list<Player*>::iterator it = m_players.begin(); + it != m_players.end(); + ++it) { + RemotePlayer *player = static_cast<RemotePlayer*>(*it); + if (player->checkModified()) { + player->save(players_path); } } +} - for(std::list<Player*>::iterator i = m_players.begin(); - i != m_players.end(); ++i) - { - Player *player = *i; - if(saved_players.find(player) != saved_players.end()) - { - /*infostream<<"Player "<<player->getName() - <<" was already saved."<<std::endl;*/ - continue; - } - std::string playername = player->getName(); - // Don't save unnamed player - if(playername == "") - { - //infostream<<"Not saving unnamed player."<<std::endl; - continue; - } - /* - Find a sane filename - */ - if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false) - playername = "player"; - std::string path = players_path + "/" + playername; - bool found = false; - for(u32 i=0; i<1000; i++) - { - if(fs::PathExists(path) == false) - { - found = true; - break; - } - path = players_path + "/" + playername + itos(i); - } - if(found == false) - { - infostream<<"Didn't find free file for player"<<std::endl; - continue; - } +void ServerEnvironment::savePlayer(const std::string &playername) +{ + std::string players_path = m_path_world + DIR_DELIM "players"; + fs::CreateDir(players_path); - { - /*infostream<<"Saving player "<<player->getName()<<" to " - <<path<<std::endl;*/ - // Open file and serialize - std::ostringstream ss(std::ios_base::binary); - player->serialize(ss); - if(!fs::safeWriteToFile(path, ss.str())) - { - infostream<<"Failed to write "<<path<<std::endl; - continue; - } - saved_players.insert(player); - } + RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str())); + if (player) { + player->save(players_path); } - - //infostream<<"Saved "<<saved_players.size()<<" players."<<std::endl; } -void ServerEnvironment::deSerializePlayers(const std::string &savedir) +Player *ServerEnvironment::loadPlayer(const std::string &playername) { - std::string players_path = savedir + "/players"; + std::string players_path = m_path_world + DIR_DELIM "players"; + + RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str())); + bool newplayer = false; + bool foundplayer = false; + if (!player) { + player = new RemotePlayer(m_gamedef); + newplayer = true; + } std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path); - for(u32 i=0; i<player_files.size(); i++) - { - if(player_files[i].dir) + for (u32 i = 0; i < player_files.size(); i++) { + if (player_files[i].dir) continue; // Full path to this file std::string path = players_path + "/" + player_files[i].name; - //infostream<<"Checking player file "<<path<<std::endl; - // Load player to see what is its name - RemotePlayer testplayer(m_gamedef); - { - // Open file and deserialize - std::ifstream is(path.c_str(), std::ios_base::binary); - if(is.good() == false) - { - infostream<<"Failed to read "<<path<<std::endl; - continue; - } - testplayer.deSerialize(is, player_files[i].name); - } - - if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS)) - { - infostream<<"Not loading player with invalid name: " - <<testplayer.getName()<<std::endl; + std::ifstream is(path.c_str(), std::ios_base::binary); + if (!is.good()) { + infostream << "Failed to read " << path << std::endl; + continue; } + player->deSerialize(is, player_files[i].name); - /*infostream<<"Loaded test player with name "<<testplayer.getName() - <<std::endl;*/ - - // Search for the player - std::string playername = testplayer.getName(); - Player *player = getPlayer(playername.c_str()); - bool newplayer = false; - if(player == NULL) - { - //infostream<<"Is a new player"<<std::endl; - player = new RemotePlayer(m_gamedef); - newplayer = true; + if (!string_allowed(player->getName(), PLAYERNAME_ALLOWED_CHARS)) { + infostream << "Not loading player with invalid name: " + << player->getName() << std::endl; + continue; } - // Load player - { - verbosestream<<"Reading player "<<testplayer.getName()<<" from " - <<path<<std::endl; - // Open file and deserialize - std::ifstream is(path.c_str(), std::ios_base::binary); - if(is.good() == false) - { - infostream<<"Failed to read "<<path<<std::endl; - continue; - } - player->deSerialize(is, player_files[i].name); + if (player->getName() == playername) { + // We found our player + foundplayer = true; + break; } - if(newplayer) - { - addPlayer(player); - } } + if (!foundplayer) { + return NULL; + } + if (newplayer) { + addPlayer(player); + } + return player; } -void ServerEnvironment::saveMeta(const std::string &savedir) +void ServerEnvironment::saveMeta() { - std::string path = savedir + "/env_meta.txt"; + std::string path = m_path_world + DIR_DELIM "env_meta.txt"; // Open file and serialize std::ostringstream ss(std::ios_base::binary); @@ -609,9 +512,9 @@ void ServerEnvironment::saveMeta(const std::string &savedir) } } -void ServerEnvironment::loadMeta(const std::string &savedir) +void ServerEnvironment::loadMeta() { - std::string path = savedir + "/env_meta.txt"; + std::string path = m_path_world + DIR_DELIM "env_meta.txt"; // Open file and deserialize std::ifstream is(path.c_str(), std::ios_base::binary); diff --git a/src/environment.h b/src/environment.h index a59bbd9a1..e8ae044e3 100644 --- a/src/environment.h +++ b/src/environment.h @@ -70,6 +70,7 @@ public: virtual void addPlayer(Player *player); void removePlayer(u16 peer_id); + void removePlayer(const char *name); Player * getPlayer(u16 peer_id); Player * getPlayer(const char *name); Player * getRandomConnectedPlayer(); @@ -199,7 +200,7 @@ class ServerEnvironment : public Environment { public: ServerEnvironment(ServerMap *map, GameScripting *scriptIface, - IGameDef *gamedef); + IGameDef *gamedef, const std::string &path_world); ~ServerEnvironment(); Map & getMap(); @@ -216,17 +217,16 @@ public: float getSendRecommendedInterval() { return m_recommended_send_interval; } - /* - Save players - */ - void serializePlayers(const std::string &savedir); - void deSerializePlayers(const std::string &savedir); + // Save players + void saveLoadedPlayers(); + void savePlayer(const std::string &playername); + Player *loadPlayer(const std::string &playername); /* Save and load time of day and game timer */ - void saveMeta(const std::string &savedir); - void loadMeta(const std::string &savedir); + void saveMeta(); + void loadMeta(); /* External ActiveObject interface @@ -368,6 +368,8 @@ private: GameScripting* m_script; // Game definition IGameDef *m_gamedef; + // World path + const std::string m_path_world; // Active object list std::map<u16, ServerActiveObject*> m_active_objects; // Outgoing network message buffer for active objects diff --git a/src/player.cpp b/src/player.cpp index 4dadf26d0..78ba17e89 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -283,6 +283,72 @@ void Player::clearHud() } } + +void RemotePlayer::save(const std::string &savedir) +{ + bool newplayer = true; + + /* We have to iterate through all files in the players directory + * and check their player names because some file systems are not + * case-sensitive and player names are case-sensitive. + */ + + // A player to deserialize files into to check their names + RemotePlayer testplayer(m_gamedef); + + std::vector<fs::DirListNode> player_files = fs::GetDirListing(savedir); + for(u32 i = 0; i < player_files.size(); i++) { + if (player_files[i].dir || player_files[i].name[0] == '.') { + continue; + } + + // Full path to this file + std::string path = savedir + "/" + player_files[i].name; + + // Open file and deserialize + std::ifstream is(path.c_str(), std::ios_base::binary); + if (!is.good()) { + infostream << "Failed to read " << path << std::endl; + continue; + } + testplayer.deSerialize(is, player_files[i].name); + + if (strcmp(testplayer.getName(), m_name) == 0) { + // Open file and serialize + std::ostringstream ss(std::ios_base::binary); + serialize(ss); + if (!fs::safeWriteToFile(path, ss.str())) { + infostream << "Failed to write " << path << std::endl; + } + newplayer = false; + break; + } + } + + if (newplayer) { + bool found = false; + std::string path = savedir + "/" + m_name; + for (u32 i = 0; i < 1000; i++) { + if (!fs::PathExists(path)) { + found = true; + break; + } + path = savedir + "/" + m_name + itos(i); + } + if (!found) { + infostream << "Didn't find free file for player " << m_name << std::endl; + return; + } + + // Open file and serialize + std::ostringstream ss(std::ios_base::binary); + serialize(ss); + if (!fs::safeWriteToFile(path, ss.str())) { + infostream << "Failed to write " << path << std::endl; + } + } +} + /* RemotePlayer */ @@ -292,3 +358,4 @@ void RemotePlayer::setPosition(const v3f &position) if(m_sao) m_sao->setBasePosition(position); } + diff --git a/src/player.h b/src/player.h index 2b04a310c..098a4d153 100644 --- a/src/player.h +++ b/src/player.h @@ -335,6 +335,8 @@ public: RemotePlayer(IGameDef *gamedef): Player(gamedef), m_sao(0) {} virtual ~RemotePlayer() {} + void save(const std::string &savedir); + PlayerSAO *getPlayerSAO() { return m_sao; } void setPlayerSAO(PlayerSAO *sao) diff --git a/src/server.cpp b/src/server.cpp index 54a139849..516a9d2f9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -344,7 +344,7 @@ Server::Server( // Initialize Environment ServerMap *servermap = new ServerMap(path_world, this, m_emerge); - m_env = new ServerEnvironment(servermap, m_script, this); + m_env = new ServerEnvironment(servermap, m_script, this, m_path_world); m_clients.setEnv(m_env); @@ -361,19 +361,13 @@ Server::Server( servermap->addEventReceiver(this); // If file exists, load environment metadata - if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt")) + if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) { infostream<<"Server: Loading environment metadata"<<std::endl; - m_env->loadMeta(m_path_world); + m_env->loadMeta(); } - // Load players - infostream<<"Server: Loading players"<<std::endl; - m_env->deSerializePlayers(m_path_world); - - /* - Add some test ActiveBlockModifiers to environment - */ + // Add some test ActiveBlockModifiers to environment add_legacy_abms(m_env, m_nodedef); m_liquid_transform_every = g_settings->getFloat("liquid_update"); @@ -383,42 +377,23 @@ Server::~Server() { infostream<<"Server destructing"<<std::endl; - /* - Send shutdown message - */ - { - std::wstring line = L"*** Server shutting down"; - SendChatMessage(PEER_ID_INEXISTENT, line); - } + // Send shutdown message + SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down"); { JMutexAutoLock envlock(m_env_mutex); - /* - Execute script shutdown hooks - */ + // Execute script shutdown hooks m_script->on_shutdown(); - } - - { - JMutexAutoLock envlock(m_env_mutex); - /* - Save players - */ infostream<<"Server: Saving players"<<std::endl; - m_env->serializePlayers(m_path_world); + m_env->saveLoadedPlayers(); - /* - Save environment metadata - */ infostream<<"Server: Saving environment metadata"<<std::endl; - m_env->saveMeta(m_path_world); + m_env->saveMeta(); } - /* - Stop threads - */ + // Stop threads stop(); delete m_thread; @@ -444,12 +419,10 @@ Server::~Server() delete m_script; // Delete detached inventories - { - for(std::map<std::string, Inventory*>::iterator - i = m_detached_inventories.begin(); - i != m_detached_inventories.end(); i++){ - delete i->second; - } + for (std::map<std::string, Inventory*>::iterator + i = m_detached_inventories.begin(); + i != m_detached_inventories.end(); i++) { + delete i->second; } } @@ -1141,18 +1114,19 @@ void Server::AsyncRunStep(bool initial_step) ScopeProfiler sp(g_profiler, "Server: saving stuff"); - //Ban stuff - if(m_banmanager->isModified()) + // Save ban file + if (m_banmanager->isModified()) { m_banmanager->save(); + } // Save changed parts of map m_env->getMap().save(MOD_STATE_WRITE_NEEDED); // Save players - m_env->serializePlayers(m_path_world); + m_env->saveLoadedPlayers(); // Save environment metadata - m_env->saveMeta(m_path_world); + m_env->saveMeta(); } } } @@ -1178,27 +1152,16 @@ void Server::Receive() "SerializationError: what()=" <<e.what()<<std::endl; } - catch(con::PeerNotFoundException &e) - { - //NOTE: This is not needed anymore - - // The peer has been disconnected. - // Find the associated player and remove it. - - /*JMutexAutoLock envlock(m_env_mutex); - - infostream<<"ServerThread: peer_id="<<peer_id - <<" has apparently closed connection. " - <<"Removing player."<<std::endl; - - m_env->removePlayer(peer_id);*/ - } catch(ClientStateError &e) { errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl; DenyAccess(peer_id, L"Your client sent something server didn't expect." L"Try reconnecting or updating your client"); } + catch(con::PeerNotFoundException &e) + { + // Do nothing + } } PlayerSAO* Server::StageTwoClientInit(u16 peer_id) @@ -5032,15 +4995,16 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id) return NULL; } - /* - Create a new player if it doesn't exist yet - */ - if(player == NULL) - { + // Load player if it isn't already loaded + if (!player) { + player = static_cast<RemotePlayer*>(m_env->loadPlayer(name)); + } + + // Create player if it doesn't exist + if (!player) { newplayer = true; player = new RemotePlayer(this); player->updateName(name); - /* Set player position */ infostream<<"Server: Finding spawn place for player \"" <<name<<"\""<<std::endl; @@ -5051,9 +5015,7 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id) m_env->addPlayer(player); } - /* - Create a new player active object - */ + // Create a new player active object PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id, getPlayerEffectivePrivs(player->getName()), isSingleplayer()); @@ -5065,8 +5027,9 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id) m_env->addActiveObject(playersao); /* Run scripts */ - if(newplayer) + if (newplayer) { m_script->on_newplayer(playersao); + } return playersao; } |