#include "craftdef.h"
#include "emerge.h"
#include "mapgen.h"
-#include "biome.h"
+#include "mg_biome.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
this),
m_banmanager(NULL),
m_rollback(NULL),
- m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
m_emerge(NULL),
m_script(NULL),
throw ServerError("Failed to initialize world");
// Create ban manager
- std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
+ std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
m_banmanager = new BanManager(ban_path);
// Create rollback manager
- std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
- m_rollback = createRollbackManager(rollback_path, this);
+ m_rollback = new RollbackManager(m_path_world, this);
ModConfiguration modconf(m_path_world);
m_mods = modconf.getMods();
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
+ // Perform pending node name resolutions
+ m_nodedef->runNodeResolverCallbacks();
+
// Load the mapgen params from global settings now after any
// initial overrides have been set by the mods
m_emerge->loadMapgenParams();
// 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;
}
}
m_env->step(dtime);
}
- const float map_timer_and_unload_dtime = 2.92;
+ static const float map_timer_and_unload_dtime = 2.92;
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
{
JMutexAutoLock lock(m_env_mutex);
/*
Set the modified blocks unsent for all the clients
*/
- if(modified_blocks.size() > 0)
+ if(!modified_blocks.empty())
{
SetBlocksNotSent(modified_blocks);
}
{
float &counter = m_masterserver_timer;
if(!isSingleplayer() && (!counter || counter >= 300.0) &&
- g_settings->getBool("server_announce") == true)
+ g_settings->getBool("server_announce"))
{
- ServerList::sendAnnounce(!counter ? "start" : "update",
- m_clients.getPlayerNames(),
- m_uptime.get(),
- m_env->getGameTime(),
- m_lag,
- m_gamespec.id,
- m_mods);
+ ServerList::sendAnnounce(counter ? "update" : "start",
+ m_clients.getPlayerNames(),
+ m_uptime.get(),
+ m_env->getGameTime(),
+ m_lag,
+ m_gamespec.id,
+ m_emerge->params.mg_name,
+ m_mods);
counter = 0.01;
}
counter += dtime;
// Radius inside which objects are active
s16 radius = g_settings->getS16("active_object_send_range_blocks");
+ s16 player_radius = g_settings->getS16("player_transfer_distance");
+
+ if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
+ !g_settings->getBool("unlimited_player_transfer_distance"))
+ player_radius = radius;
+
radius *= MAP_BLOCKSIZE;
+ player_radius *= MAP_BLOCKSIZE;
for(std::map<u16, RemoteClient*>::iterator
i = clients.begin();
// If definitions and textures have not been sent, don't
// send objects either
- if (client->getState() < DefinitionsSent)
+ if (client->getState() < CS_DefinitionsSent)
continue;
Player *player = m_env->getPlayer(client->peer_id);
std::set<u16> removed_objects;
std::set<u16> added_objects;
- m_env->getRemovedActiveObjects(pos, radius,
+ m_env->getRemovedActiveObjects(pos, radius, player_radius,
client->m_known_objects, removed_objects);
- m_env->getAddedActiveObjects(pos, radius,
+ m_env->getAddedActiveObjects(pos, radius, player_radius,
client->m_known_objects, added_objects);
// Ignore if nothing happened
- if(removed_objects.size() == 0 && added_objects.size() == 0)
+ if(removed_objects.empty() && added_objects.empty())
{
//infostream<<"active objects: none changed"<<std::endl;
continue;
/*
Set blocks not sent to far players
*/
- if(far_players.size() > 0)
+ if(!far_players.empty())
{
// Convert list format to that wanted by SetBlocksNotSent
std::map<v3s16, MapBlock*> modified_blocks2;
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)
std::string playername = "";
PlayerSAO *playersao = NULL;
m_clients.Lock();
- RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
- if (client != NULL) {
- playername = client->getName();
- playersao = emergePlayer(playername.c_str(), peer_id);
+ try {
+ RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
+ if (client != NULL) {
+ playername = client->getName();
+ playersao = emergePlayer(playername.c_str(), peer_id);
+ }
+ } catch (std::exception &e) {
+ m_clients.Unlock();
+ throw;
}
m_clients.Unlock();
if(datasize < 2+1+PLAYERNAME_SIZE)
return;
- RemoteClient* client = getClient(peer_id,Created);
+ RemoteClient* client = getClient(peer_id, CS_Created);
// If net_proto_version is set, this client has already been handled
- if(client->getState() > Created)
+ if(client->getState() > CS_Created)
{
verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
<<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
/*
Set up player
*/
-
- // Get player name
char playername[PLAYERNAME_SIZE];
- for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
- {
- playername[i] = data[3+i];
+ unsigned int playername_length = 0;
+ for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
+ playername[playername_length] = data[3+playername_length];
+ if (data[3+playername_length] == 0)
+ break;
+ }
+
+ if (playername_length == PLAYERNAME_SIZE) {
+ actionstream<<"Server: Player with name exceeding max length "
+ <<"tried to connect from "<<addr_s<<std::endl;
+ DenyAccess(peer_id, L"Name too long");
+ return;
}
- playername[PLAYERNAME_SIZE-1] = 0;
+
if(playername[0]=='\0')
{
// Enforce user limit.
// Don't enforce for users that have some admin right
- if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
+ if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
!checkPriv(playername, "server") &&
!checkPriv(playername, "ban") &&
!checkPriv(playername, "privs") &&
// Send as reliable
m_clients.send(peer_id, 0, reply, true);
- m_clients.event(peer_id, Init);
+ m_clients.event(peer_id, CSE_Init);
}
return;
verbosestream<<"Server: Got TOSERVER_INIT2 from "
<<peer_id<<std::endl;
- m_clients.event(peer_id, GotInit2);
+ m_clients.event(peer_id, CSE_GotInit2);
u16 protocol_version = m_clients.getProtocolVersion(peer_id);
// Send node definitions
SendNodeDef(peer_id, m_nodedef, protocol_version);
- m_clients.event(peer_id, SetDefinitionsSent);
+ m_clients.event(peer_id, CSE_SetDefinitionsSent);
// Send media announcement
sendMediaAnnouncement(peer_id);
///// begin compatibility code
if (protocol_version <= 22) {
- m_clients.event(peer_id, SetClientReady);
+ m_clients.event(peer_id, CSE_SetClientReady);
m_script->on_joinplayer(playersao);
}
///// end compatibility code
return;
}
- u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
- u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
+ u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
+ u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
if(peer_ser_ver == SER_FMT_VER_INVALID)
{
if (playersao == NULL) {
errorstream
- << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
+ << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
<< peer_id << std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
- if(datasize < 2+8)
+ if(datasize < 2+8) {
+ errorstream
+ << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
+ << peer_id << std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
+ }
m_clients.setClientVersion(
peer_id,
data[2], data[3], data[4],
std::string((char*) &data[8],(u16) data[6]));
- m_clients.event(peer_id, SetClientReady);
+ m_clients.event(peer_id, CSE_SetClientReady);
m_script->on_joinplayer(playersao);
}
return;
}
- if (m_clients.getClientState(peer_id) < Active)
+ if (m_clients.getClientState(peer_id) < CS_Active)
{
if (command == TOSERVER_PLAYERPOS) return;
}
Player *player = m_env->getPlayer(peer_id);
- if(player == NULL){
+ if(player == NULL) {
errorstream<<"Server::ProcessData(): Cancelling: "
"No player for peer_id="<<peer_id
- <<std::endl;
+ << " disconnecting peer!" <<std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
PlayerSAO *playersao = player->getPlayerSAO();
- if(playersao == NULL){
+ if(playersao == NULL) {
errorstream<<"Server::ProcessData(): Cancelling: "
"No player object for peer_id="<<peer_id
- <<std::endl;
+ << " disconnecting peer!" <<std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
somebody is cheating, by checking the timing.
*/
MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- }
- catch(InvalidPositionException &e)
- {
+ bool pos_ok;
+ n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ if (pos_ok)
+ n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+
+ if (!pos_ok) {
infostream<<"Server: Not punching: Node not found."
<<" Adding block to emerge queue."
<<std::endl;
m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
}
+
if(n.getContent() != CONTENT_IGNORE)
m_script->node_on_punch(p_under, n, playersao, pointed);
// Cheat prevention
// Only digging of nodes
if(pointed.type == POINTEDTHING_NODE)
{
- MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not finishing digging: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
+ bool pos_ok;
+ MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ if (!pos_ok) {
+ infostream << "Server: Not finishing digging: Node not found."
+ << " Adding block to emerge queue."
+ << std::endl;
m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
}
if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
m_script->node_on_dig(p_under, n, playersao);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ RemoteClient *client = getClient(peer_id);
// Send unusual result (that is, node not being removed)
if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
{
// Re-send block to revert change on client-side
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
}
+ else {
+ client->ResendBlockIfOnWire(blockpos);
+ }
}
} // action == 2
// If item has node placement prediction, always send the
// blocks to make sure the client knows what exactly happened
- if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
+ v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
client->SetBlockNotSent(blockpos);
- v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
- if(blockpos2 != blockpos){
+ if(blockpos2 != blockpos) {
client->SetBlockNotSent(blockpos2);
}
}
+ else {
+ client->ResendBlockIfOnWire(blockpos);
+ if(blockpos2 != blockpos) {
+ client->ResendBlockIfOnWire(blockpos2);
+ }
+ }
} // action == 3
/*
}
} // action == 4
-
+
/*
Catch invalid actions
continue;
ServerPlayingSound &psound = i->second;
psound.clients.erase(peer_id);
- if(psound.clients.size() == 0)
+ if(psound.clients.empty())
m_playing_sounds.erase(i++);
}
}
verbosestream<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
- m_clients.event(peer->id,Disconnect);
+ m_clients.event(peer->id, CSE_Disconnect);
con::PeerChange c;
c.type = con::PEER_REMOVED;
c.peer_id = peer->id;
{
*state = m_clients.getClientState(peer_id);
m_clients.Lock();
- RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
+ RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
if (client == NULL) {
m_clients.Unlock();
return false;
- }
+ }
*uptime = client->uptime();
*ser_vers = client->serialization_version;
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
+
// Write command
writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
os.write((char*)buf, 2);
- os<<serializeLongString(formspec);
+ os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
os<<serializeString(formname);
// Make data buffer
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
- os<<serializeLongString(player->inventory_formspec);
+ os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
// Make data buffer
std::string s = os.str();
dst_clients.push_back(*i);
}
}
- if(dst_clients.size() == 0)
+ if(dst_clients.empty())
return -1;
// Create the sound
i = clients.begin();
i != clients.end(); ++i)
{
- RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
if (client == NULL)
- return;
+ continue;
total_sending += client->SendingCount();
client->GetNextBlocks(m_env,m_emerge, dtime, queue);
continue;
}
- RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
if(!client)
continue;
DSTACK(__FUNCTION_NAME);
SendAccessDenied(peer_id, reason);
- m_clients.event(peer_id,SetDenied);
+ m_clients.event(peer_id, CSE_SetDenied);
m_con.DisconnectPeer(peer_id);
}
{
ServerPlayingSound &psound = i->second;
psound.clients.erase(peer_id);
- if(psound.clients.size() == 0)
+ if(psound.clients.empty())
m_playing_sounds.erase(i++);
else
i++;
name = narrow_to_wide(player->getName());
// Add name to information string
if(!first)
- os<<L",";
+ os<<L", ";
else
first = false;
os<<name;
u32 Server::hudAdd(Player *player, HudElement *form) {
if (!player)
return -1;
-
+
u32 id = player->addHud(form);
SendHUDAdd(player->peer_id, id, form);
if (!todel)
return false;
-
+
delete todel;
SendHUDRemove(player->peer_id, id);
SendHUDSetFlags(player->peer_id, flags, mask);
player->hud_flags = flags;
- m_script->player_event(player->getPlayerSAO(),"hud_changed");
+ PlayerSAO* playersao = player->getPlayerSAO();
+
+ if (playersao == NULL)
+ return false;
+
+ m_script->player_event(playersao, "hud_changed");
return true;
}
{
infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
ServerMap *map = (ServerMap*)(&m_env->getMap());
- // Disable rollback report sink while reverting
- BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
// Fail if no actions to handle
if(actions.empty()){
{
return NULL;
}
+scene::ISceneManager* Server::getSceneManager()
+{
+ return NULL;
+}
+
u16 Server::allocateUnknownNodeId(const std::string &name)
{
return m_nodedef->allocateDummy(name);
{
return m_event;
}
-IRollbackReportSink* Server::getRollbackReportSink()
-{
- if(!m_enable_rollback_recording)
- return NULL;
- if(!m_rollback_sink_enabled)
- return NULL;
- return m_rollback;
-}
IWritableItemDefManager* Server::getWritableItemDefManager()
{
return NULL;
}
- /*
- Create a new player if it doesn't exist yet
- */
- if(player == NULL)
- {
- newplayer = true;
- player = new RemotePlayer(this);
- player->updateName(name);
+ // Load player if it isn't already loaded
+ if (!player) {
+ player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
+ }
- /* Set player position */
+ // Create player if it doesn't exist
+ if (!player) {
+ newplayer = true;
+ player = new RemotePlayer(this, name);
+ // Set player position
infostream<<"Server: Finding spawn place for player \""
<<name<<"\""<<std::endl;
v3f pos = findSpawnPos(m_env->getServerMap());
player->setPosition(pos);
- /* Add player to environment */
+ // Make sure the player is saved
+ player->setModified(true);
+
+ // Add player to environment
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;
}