67 changes: 67 additions & 0 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -292,3 +358,4 @@ void RemotePlayer::setPosition(const v3f &position)
if(m_sao)
m_sao->setBasePosition(position);
}

2 changes: 2 additions & 0 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ class RemotePlayer : public Player
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)
Expand Down
103 changes: 33 additions & 70 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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");
Expand All @@ -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;

Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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();
}
}
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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());
Expand All @@ -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;
}
Expand Down