{
m_player->setPlayerSAO(NULL);
m_player->peer_id = 0;
+ m_env->savePlayer(m_player->getName());
+ m_env->removePlayer(m_player->getName());
}
}
}
}
+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();
*/
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),
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);
}
}
-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);
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();
{
public:
ServerEnvironment(ServerMap *map, GameScripting *scriptIface,
- IGameDef *gamedef);
+ IGameDef *gamedef, const std::string &path_world);
~ServerEnvironment();
Map & getMap();
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
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
}
}
+
+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
*/
if(m_sao)
m_sao->setBasePosition(position);
}
+
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)
// 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);
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");
{
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;
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;
}
}
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();
}
}
}
"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)
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;
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());
m_env->addActiveObject(playersao);
/* Run scripts */
- if(newplayer)
+ if (newplayer) {
m_script->on_newplayer(playersao);
+ }
return playersao;
}