summaryrefslogtreecommitdiff
path: root/src/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.cpp')
-rw-r--r--src/server.cpp566
1 files changed, 338 insertions, 228 deletions
diff --git a/src/server.cpp b/src/server.cpp
index 0a8288324..94a4787f8 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemdef.h"
#include "craftdef.h"
#include "mapgen.h"
+#include "biome.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
@@ -50,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound.h" // dummySoundManager
#include "event_manager.h"
#include "hex.h"
+#include "serverlist.h"
#include "util/string.h"
#include "util/pointedthing.h"
#include "util/mathconstants.h"
@@ -80,7 +82,7 @@ public:
*m_flag = false;
}
}
-
+
private:
bool *m_flag;
};
@@ -105,7 +107,7 @@ public:
*m_ignorevariable = VoxelArea();
}
}
-
+
private:
VoxelArea *m_ignorevariable;
};
@@ -129,7 +131,7 @@ void * ServerThread::Thread()
//TimeTaker timer("AsyncRunStep()");
m_server->AsyncRunStep();
}
-
+
//infostream<<"Running m_server->Receive()"<<std::endl;
m_server->Receive();
}
@@ -149,7 +151,7 @@ void * ServerThread::Thread()
m_server->setAsyncFatalError(e.what());
}
}
-
+
END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL;
@@ -168,7 +170,11 @@ void * EmergeThread::Thread()
bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
-
+
+ ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
+ EmergeManager *emerge = m_server->m_emerge;
+ Mapgen *mapgen = emerge->getMapgen();
+
/*
Get block info from queue, emerge them and send them
to clients.
@@ -180,12 +186,12 @@ void * EmergeThread::Thread()
QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
if(qptr == NULL)
break;
-
+
SharedPtr<QueuedBlockEmerge> q(qptr);
v3s16 &p = q->pos;
v2s16 p2d(p.X,p.Z);
-
+
last_tried_pos = p;
/*
@@ -193,18 +199,18 @@ void * EmergeThread::Thread()
*/
if(blockpos_over_limit(p))
continue;
-
+
//infostream<<"EmergeThread::Thread(): running"<<std::endl;
//TimeTaker timer("block emerge");
-
+
/*
Try to emerge it from somewhere.
If it is only wanted as optional, only loading from disk
will be allowed.
*/
-
+
/*
Check if any peer wants it as non-optional. In that case it
will be generated.
@@ -224,17 +230,17 @@ void * EmergeThread::Thread()
u8 flags = i.getNode()->getValue();
if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
only_from_disk = false;
-
+
}
}
-
+
if(enable_mapgen_debug_info)
infostream<<"EmergeThread: p="
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
<<"only_from_disk="<<only_from_disk<<std::endl;
-
- ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
-
+
+
+
MapBlock *block = NULL;
bool got_block = true;
core::map<v3s16, MapBlock*> modified_blocks;
@@ -243,17 +249,17 @@ void * EmergeThread::Thread()
Try to fetch block from memory or disk.
If not found and asked to generate, initialize generator.
*/
-
+
bool started_generate = false;
- mapgen::BlockMakeData data;
+ BlockMakeData data;
{
JMutexAutoLock envlock(m_server->m_env_mutex);
-
+
// Load sector if it isn't loaded
if(map.getSectorNoGenerateNoEx(p2d) == NULL)
map.loadSectorMeta(p2d);
-
+
// Attempt to load block
block = map.getBlockNoCreateNoEx(p);
if(!block || block->isDummy() || !block->isGenerated())
@@ -264,7 +270,7 @@ void * EmergeThread::Thread()
block = map.loadBlock(p);
}
-
+
// If could not load and allowed to generate, start generation
// inside this same envlock
if(only_from_disk == false &&
@@ -287,16 +293,17 @@ void * EmergeThread::Thread()
SPT_AVG);
TimeTaker t("mapgen::make_block()");
- mapgen::make_block(&data);
+ mapgen->makeChunk(&data);
+ //mapgen::make_block(&data);
if(enable_mapgen_debug_info == false)
t.stop(true); // Hide output
}
-
+
do{ // enable break
// Lock environment again to access the map
JMutexAutoLock envlock(m_server->m_env_mutex);
-
+
ScopeProfiler sp(g_profiler, "EmergeThread: after "
"mapgen::make_block (envlock)", SPT_AVG);
@@ -306,7 +313,7 @@ void * EmergeThread::Thread()
// Get central block
block = map.getBlockNoCreateNoEx(p);
-
+
// If block doesn't exist, don't try doing anything with it
// This happens if the block is not in generation boundaries
if(!block)
@@ -319,7 +326,7 @@ void * EmergeThread::Thread()
v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
-
+
/*
Ignore map edit events, they will not need to be
sent to anybody because the block hasn't been sent
@@ -332,11 +339,11 @@ void * EmergeThread::Thread()
{
TimeTaker timer("on_generated");
scriptapi_environment_on_generated(m_server->m_lua,
- minp, maxp, mapgen::get_blockseed(data.seed, minp));
+ minp, maxp, emerge->getBlockSeed(minp));
/*int t = timer.stop(true);
dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
}
-
+
if(enable_mapgen_debug_info)
infostream<<"EmergeThread: ended up with: "
<<analyze_block(block)<<std::endl;
@@ -348,11 +355,11 @@ void * EmergeThread::Thread()
if(block == NULL)
got_block = false;
-
+
/*
Set sent status of modified blocks on clients
*/
-
+
// NOTE: Server's clients are also behind the connection mutex
JMutexAutoLock lock(m_server->m_con_mutex);
@@ -363,17 +370,17 @@ void * EmergeThread::Thread()
{
modified_blocks.insert(p, block);
}
-
+
/*
Set the modified blocks unsent for all the clients
*/
-
+
for(core::map<u16, RemoteClient*>::Iterator
i = m_server->m_clients.getIterator();
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
-
+
if(modified_blocks.size() > 0)
{
// Remove block from sent history
@@ -434,14 +441,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
core::array<PrioritySortedBlockTransfer> &dest)
{
DSTACK(__FUNCTION_NAME);
-
+
/*u32 timer_result;
TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
-
+
// Increment timers
m_nothing_to_send_pause_timer -= dtime;
m_nearest_unsent_reset_timer += dtime;
-
+
if(m_nothing_to_send_pause_timer >= 0)
return;
@@ -459,7 +466,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
}
//TimeTaker timer("RemoteClient::GetNextBlocks");
-
+
v3f playerpos = player->getPosition();
v3f playerspeed = player->getSpeed();
v3f playerspeeddir(0,0,0);
@@ -471,7 +478,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
v3s16 center = getNodeBlockPos(center_nodepos);
-
+
// Camera position and direction
v3f camera_pos = player->getEyePosition();
v3f camera_dir = v3f(0,0,1);
@@ -484,7 +491,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*
Get the starting value of the block finder radius.
*/
-
+
if(m_last_center != center)
{
m_nearest_unsent_d = 0;
@@ -493,7 +500,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*infostream<<"m_nearest_unsent_reset_timer="
<<m_nearest_unsent_reset_timer<<std::endl;*/
-
+
// Reset periodically to workaround for some bugs or stuff
if(m_nearest_unsent_reset_timer > 20.0)
{
@@ -514,7 +521,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*
Check the time from last addNode/removeNode.
-
+
Decrease send rate if player is building stuff.
*/
m_time_from_building += dtime;
@@ -524,12 +531,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
max_simul_sends_usually
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
}
-
+
/*
Number of blocks sending + number of blocks selected for sending
*/
u32 num_blocks_selected = m_blocks_sending.size();
-
+
/*
next time d will be continued from the d from which the nearest
unsent block was found this time.
@@ -541,28 +548,28 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
s16 d_max = g_settings->getS16("max_block_send_distance");
s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
-
+
// Don't loop very much at a time
s16 max_d_increment_at_time = 2;
if(d_max > d_start + max_d_increment_at_time)
d_max = d_start + max_d_increment_at_time;
/*if(d_max_gen > d_start+2)
d_max_gen = d_start+2;*/
-
+
//infostream<<"Starting from "<<d_start<<std::endl;
s32 nearest_emerged_d = -1;
s32 nearest_emergefull_d = -1;
s32 nearest_sent_d = -1;
bool queue_is_full = false;
-
+
s16 d;
for(d = d_start; d <= d_max; d++)
{
/*errorstream<<"checking d="<<d<<" for "
<<server->getPlayerName(peer_id)<<std::endl;*/
//infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
-
+
/*
If m_nearest_unsent_d was changed by the EmergeThread
(it can change it to 0 through SetBlockNotSent),
@@ -581,12 +588,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
*/
core::list<v3s16> list;
getFacePositions(list, d);
-
+
core::list<v3s16>::Iterator li;
for(li=list.begin(); li!=list.end(); li++)
{
v3s16 p = *li + center;
-
+
/*
Send throttling
- Don't allow too many simultaneous transfers
@@ -594,10 +601,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
Also, don't send blocks that are already flying.
*/
-
+
// Start with the usual maximum
u16 max_simul_dynamic = max_simul_sends_usually;
-
+
// If block is very close, allow full maximum
if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
max_simul_dynamic = max_simul_sends_setting;
@@ -608,11 +615,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
queue_is_full = true;
goto queue_full_break;
}
-
+
// Don't send blocks that are currently being transferred
if(m_blocks_sending.find(p) != NULL)
continue;
-
+
/*
Do not go over-limit
*/
@@ -623,10 +630,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|| p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|| p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
continue;
-
+
// If this is true, inexistent block will be made from scratch
bool generate = d <= d_max_gen;
-
+
{
/*// Limit the generating area vertically to 2/3
if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
@@ -655,7 +662,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
v2s16 p2d_nodes_center(
MAP_BLOCKSIZE*p.X,
MAP_BLOCKSIZE*p.Z);
-
+
// Get ground height in nodes
s16 gh = server->m_env->getServerMap().findGroundLevel(
p2d_nodes_center);
@@ -697,7 +704,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
Check if map has this block
*/
MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
-
+
bool surely_not_found_on_disk = false;
bool block_is_invalid = false;
if(block != NULL)
@@ -711,13 +718,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
{
surely_not_found_on_disk = true;
}
-
+
// Block is valid if lighting is up-to-date and data exists
if(block->isValid() == false)
{
block_is_invalid = true;
}
-
+
/*if(block->isFullyGenerated() == false)
{
block_is_invalid = true;
@@ -775,13 +782,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
{
//infostream<<"Adding block to emerge queue"<<std::endl;
-
+
// Add it to the emerge queue and trigger the thread
-
+
u8 flags = 0;
if(generate == false)
flags |= BLOCK_EMERGE_FLAG_FROMDISK;
-
+
server->m_emerge_queue.addBlock(peer_id, p, flags);
server->m_emergethread.trigger();
@@ -790,8 +797,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
} else {
if(nearest_emergefull_d == -1)
nearest_emergefull_d = d;
+ goto queue_full_break;
}
-
+
// get next one.
continue;
}
@@ -816,7 +824,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
queue_full_break:
//infostream<<"Stopped at "<<d<<std::endl;
-
+
// If nothing was found for sending and nothing was queued for
// emerging, continue next time browsing from here
if(nearest_emerged_d != -1){
@@ -871,7 +879,7 @@ void RemoteClient::SentBlock(v3s16 p)
void RemoteClient::SetBlockNotSent(v3s16 p)
{
m_nearest_unsent_d = 0;
-
+
if(m_blocks_sending.find(p) != NULL)
m_blocks_sending.remove(p);
if(m_blocks_sent.find(p) != NULL)
@@ -881,7 +889,7 @@ void RemoteClient::SetBlockNotSent(v3s16 p)
void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
{
m_nearest_unsent_d = 0;
-
+
for(core::map<v3s16, MapBlock*>::Iterator
i = blocks.getIterator();
i.atEnd()==false; i++)
@@ -937,6 +945,8 @@ Server::Server(
m_rollback(NULL),
m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
+ m_emerge(NULL),
+ m_biomedef(NULL),
m_lua(NULL),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
@@ -952,10 +962,12 @@ Server::Server(
{
m_liquid_transform_timer = 0.0;
m_print_info_timer = 0.0;
+ m_masterserver_timer = 0.0;
m_objectdata_timer = 0.0;
m_emergethread_trigger_timer = 0.0;
m_savemap_timer = 0.0;
-
+ m_clients_number = 0;
+
m_env_mutex.Init();
m_con_mutex.Init();
m_step_dtime_mutex.Init();
@@ -963,10 +975,10 @@ Server::Server(
if(path_world == "")
throw ServerError("Supplied empty world path");
-
+
if(!gamespec.isValid())
throw ServerError("Supplied invalid gamespec");
-
+
infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
if(m_simple_singleplayer_mode)
infostream<<" in simple singleplayer mode"<<std::endl;
@@ -976,37 +988,78 @@ Server::Server(
infostream<<"- config: "<<m_path_config<<std::endl;
infostream<<"- game: "<<m_gamespec.path<<std::endl;
+ // Create biome definition manager
+ m_biomedef = new BiomeDefManager(this);
+
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
m_rollback = createRollbackManager(rollback_path, this);
- // Add world mod search path
- m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
- // Add addon mod search path
- for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
- i != m_gamespec.mods_paths.end(); i++)
- m_modspaths.push_front((*i));
+ // Create world if it doesn't exist
+ if(!initializeWorld(m_path_world, m_gamespec.id))
+ throw ServerError("Failed to initialize world");
- // Print out mod search paths
- for(core::list<std::string>::Iterator i = m_modspaths.begin();
- i != m_modspaths.end(); i++){
- std::string modspath = *i;
- infostream<<"- mods: "<<modspath<<std::endl;
+ ModConfiguration modconf(m_path_world);
+ m_mods = modconf.getMods();
+ std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
+ // complain about mods with unsatisfied dependencies
+ if(!modconf.isConsistent())
+ {
+ for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
+ it != unsatisfied_mods.end(); ++it)
+ {
+ ModSpec mod = *it;
+ errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
+ for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
+ dep_it != mod.unsatisfied_depends.end(); ++dep_it)
+ errorstream << " \"" << *dep_it << "\"";
+ errorstream << std::endl;
+ }
}
-
+
+ Settings worldmt_settings;
+ std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
+ worldmt_settings.readConfigFile(worldmt.c_str());
+ std::vector<std::string> names = worldmt_settings.getNames();
+ std::set<std::string> exclude_mod_names;
+ std::set<std::string> load_mod_names;
+ for(std::vector<std::string>::iterator it = names.begin();
+ it != names.end(); ++it)
+ {
+ std::string name = *it;
+ if (name.compare(0,9,"load_mod_")==0)
+ {
+ if(worldmt_settings.getBool(name))
+ load_mod_names.insert(name.substr(9));
+ else
+ exclude_mod_names.insert(name.substr(9));
+ }
+ }
+ // complain about mods declared to be loaded, but not found
+ for(std::vector<ModSpec>::iterator it = m_mods.begin();
+ it != m_mods.end(); ++it)
+ load_mod_names.erase((*it).name);
+ for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
+ it != unsatisfied_mods.end(); ++it)
+ load_mod_names.erase((*it).name);
+ if(!load_mod_names.empty())
+ {
+ errorstream << "The following mods could not be found:";
+ for(std::set<std::string>::iterator it = load_mod_names.begin();
+ it != load_mod_names.end(); ++it)
+ errorstream << " \"" << (*it) << "\"";
+ errorstream << std::endl;
+ }
+
// Path to builtin.lua
std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
- // Create world if it doesn't exist
- if(!initializeWorld(m_path_world, m_gamespec.id))
- throw ServerError("Failed to initialize world");
-
// Lock environment
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
// Initialize scripting
-
+
infostream<<"Server: Initializing Lua"<<std::endl;
m_lua = script_init();
assert(m_lua);
@@ -1021,18 +1074,16 @@ Server::Server(
<<builtinpath<<std::endl;
throw ModError("Failed to load and run "+builtinpath);
}
- // Find mods in mod search paths
- m_mods = getMods(m_modspaths);
// Print 'em
infostream<<"Server: Loading mods: ";
- for(core::list<ModSpec>::Iterator i = m_mods.begin();
+ for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
infostream<<mod.name<<" ";
}
infostream<<std::endl;
// Load and run "mod" scripts
- for(core::list<ModSpec>::Iterator i = m_mods.begin();
+ for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
@@ -1045,23 +1096,30 @@ Server::Server(
throw ModError("Failed to load and run "+scriptpath);
}
}
-
+
// Read Textures and calculate sha1 sums
fillMediaCache();
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
+ // Add default biomes after nodedef had its aliases added
+ m_biomedef->addDefaultBiomes();
+
+ // Create emerge manager
+ m_emerge = new EmergeManager(this, m_biomedef);
+
// Initialize Environment
+ ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
+ m_env = new ServerEnvironment(servermap, m_lua, this, this);
- m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
- this, this);
-
+ m_emerge->initMapgens(servermap->getMapgenParams());
+
// Give environment reference to scripting api
scriptapi_add_environment(m_lua, m_env);
-
+
// Register us to receive map edit events
- m_env->getMap().addEventReceiver(this);
+ servermap->addEventReceiver(this);
// If file exists, load environment metadata
if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
@@ -1089,7 +1147,7 @@ Server::~Server()
*/
{
JMutexAutoLock conlock(m_con_mutex);
-
+
std::wstring line = L"*** Server shutting down";
/*
@@ -1138,12 +1196,12 @@ Server::~Server()
infostream<<"Server: Saving environment metadata"<<std::endl;
m_env->saveMeta(m_path_world);
}
-
+
/*
Stop threads
*/
stop();
-
+
/*
Delete clients
*/
@@ -1154,19 +1212,21 @@ Server::~Server()
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
+
// Delete client
delete i.getNode()->getValue();
}
}
-
+
// Delete things in the reverse order of creation
delete m_env;
delete m_rollback;
+ delete m_emerge;
delete m_event;
delete m_itemdef;
delete m_nodedef;
delete m_craftdef;
-
+
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
script_deinit(m_lua);
@@ -1188,7 +1248,7 @@ void Server::start(unsigned short port)
// Stop thread if already running
m_thread.stop();
-
+
// Initialize connection
m_con.SetTimeoutMs(30);
m_con.Serve(port);
@@ -1196,7 +1256,7 @@ void Server::start(unsigned short port)
// Start thread
m_thread.setRun(true);
m_thread.Start();
-
+
// ASCII art for the win!
actionstream
<<" .__ __ __ "<<std::endl
@@ -1213,7 +1273,7 @@ void Server::start(unsigned short port)
void Server::stop()
{
DSTACK(__FUNCTION_NAME);
-
+
infostream<<"Server: Stopping and waiting threads"<<std::endl;
// Stop threads (set run=false first so both start stopping)
@@ -1221,7 +1281,7 @@ void Server::stop()
m_emergethread.setRun(false);
m_thread.stop();
m_emergethread.stop();
-
+
infostream<<"Server: Threads stopped"<<std::endl;
}
@@ -1245,28 +1305,28 @@ void Server::step(float dtime)
void Server::AsyncRunStep()
{
DSTACK(__FUNCTION_NAME);
-
+
g_profiler->add("Server::AsyncRunStep (num)", 1);
-
+
float dtime;
{
JMutexAutoLock lock1(m_step_dtime_mutex);
dtime = m_step_dtime;
}
-
+
{
// Send blocks to clients
SendBlocks(dtime);
}
-
+
if(dtime < 0.001)
return;
-
+
g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
//infostream<<"Server steps "<<dtime<<std::endl;
//infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
-
+
{
JMutexAutoLock lock1(m_step_dtime_mutex);
m_step_dtime -= dtime;
@@ -1278,14 +1338,14 @@ void Server::AsyncRunStep()
{
m_uptime.set(m_uptime.get() + dtime);
}
-
+
{
// Process connection's timeouts
JMutexAutoLock lock2(m_con_mutex);
ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
m_con.RunTimeouts(dtime);
}
-
+
{
// This has to be called so that the client list gets synced
// with the peer list of the connection
@@ -1332,7 +1392,7 @@ void Server::AsyncRunStep()
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
m_env->step(dtime);
}
-
+
const float map_timer_and_unload_dtime = 2.92;
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
{
@@ -1342,7 +1402,7 @@ void Server::AsyncRunStep()
m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
g_settings->getFloat("server_unload_unused_data_timeout"));
}
-
+
/*
Do background stuff
*/
@@ -1389,27 +1449,27 @@ void Server::AsyncRunStep()
}
}
}
-
+
/* Transform liquids */
m_liquid_transform_timer += dtime;
if(m_liquid_transform_timer >= 1.00)
{
m_liquid_transform_timer -= 1.00;
-
+
JMutexAutoLock lock(m_env_mutex);
ScopeProfiler sp(g_profiler, "Server: liquid transform");
core::map<v3s16, MapBlock*> modified_blocks;
m_env->getMap().transformLiquids(modified_blocks);
-#if 0
+#if 0
/*
Update lighting
*/
core::map<v3s16, MapBlock*> lighting_modified_blocks;
ServerMap &map = ((ServerMap&)m_env->getMap());
map.updateLighting(modified_blocks, lighting_modified_blocks);
-
+
// Add blocks modified by lighting to modified_blocks
for(core::map<v3s16, MapBlock*>::Iterator
i = lighting_modified_blocks.getIterator();
@@ -1422,7 +1482,7 @@ void Server::AsyncRunStep()
/*
Set the modified blocks unsent for all the clients
*/
-
+
JMutexAutoLock lock2(m_con_mutex);
for(core::map<u16, RemoteClient*>::Iterator
@@ -1430,7 +1490,7 @@ void Server::AsyncRunStep()
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
-
+
if(modified_blocks.size() > 0)
{
// Remove block from sent history
@@ -1448,7 +1508,7 @@ void Server::AsyncRunStep()
counter = 0.0;
JMutexAutoLock lock2(m_con_mutex);
-
+ m_clients_number = 0;
if(m_clients.size() != 0)
infostream<<"Players:"<<std::endl;
for(core::map<u16, RemoteClient*>::Iterator
@@ -1462,10 +1522,25 @@ void Server::AsyncRunStep()
continue;
infostream<<"* "<<player->getName()<<"\t";
client->PrintInfo(infostream);
+ ++m_clients_number;
}
}
}
+
+#if USE_CURL
+ // send masterserver announce
+ {
+ float &counter = m_masterserver_timer;
+ if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
+ {
+ ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
+ counter = 0.01;
+ }
+ counter += dtime;
+ }
+#endif
+
//if(g_settings->getBool("enable_experimental"))
{
@@ -1511,18 +1586,18 @@ void Server::AsyncRunStep()
client->m_known_objects, removed_objects);
m_env->getAddedActiveObjects(pos, radius,
client->m_known_objects, added_objects);
-
+
// Ignore if nothing happened
if(removed_objects.size() == 0 && added_objects.size() == 0)
{
//infostream<<"active objects: none changed"<<std::endl;
continue;
}
-
+
std::string data_buffer;
char buf[4];
-
+
// Handle removed objects
writeU16((u8*)buf, removed_objects.size());
data_buffer.append(buf, 2);
@@ -1537,7 +1612,7 @@ void Server::AsyncRunStep()
// Add to data buffer for sending
writeU16((u8*)buf, i.getNode()->getKey());
data_buffer.append(buf, 2);
-
+
// Remove from known objects
client->m_known_objects.remove(i.getNode()->getKey());
@@ -1555,7 +1630,7 @@ void Server::AsyncRunStep()
// Get object
u16 id = i.getNode()->getKey();
ServerActiveObject* obj = m_env->getActiveObject(id);
-
+
// Get object type
u8 type = ACTIVEOBJECT_TYPE_INVALID;
if(obj == NULL)
@@ -1569,7 +1644,7 @@ void Server::AsyncRunStep()
data_buffer.append(buf, 2);
writeU8((u8*)buf, type);
data_buffer.append(buf, 1);
-
+
if(obj)
data_buffer.append(serializeLongString(
obj->getClientInitializationData(client->net_proto_version)));
@@ -1619,7 +1694,7 @@ void Server::AsyncRunStep()
all_known_objects[id] = true;
}
}
-
+
m_env->setKnownActiveObjects(whatever);
#endif
@@ -1644,7 +1719,7 @@ void Server::AsyncRunStep()
ActiveObjectMessage aom = m_env->getActiveObjectMessage();
if(aom.id == 0)
break;
-
+
core::list<ActiveObjectMessage>* message_list = NULL;
core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
n = buffered_messages.find(aom.id);
@@ -1659,7 +1734,7 @@ void Server::AsyncRunStep()
}
message_list->push_back(aom);
}
-
+
// Route data to every client
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
@@ -1766,7 +1841,7 @@ void Server::AsyncRunStep()
while(m_unsent_map_edit_queue.size() != 0)
{
MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
-
+
// Players far away from the change are stored here.
// Instead of sending the changes, MapBlocks are set not sent
// for them.
@@ -1818,7 +1893,7 @@ void Server::AsyncRunStep()
infostream<<"WARNING: Server: Unknown MapEditEvent "
<<((u32)event->type)<<std::endl;
}
-
+
/*
Set blocks not sent to far players
*/
@@ -1862,7 +1937,7 @@ void Server::AsyncRunStep()
verbosestream<<"Server: MapEditEvents:"<<std::endl;
prof.print(verbosestream);
}
-
+
}
/*
@@ -1875,7 +1950,7 @@ void Server::AsyncRunStep()
if(counter >= 2.0)
{
counter = 0.0;
-
+
m_emergethread.trigger();
// Update m_enable_rollback_recording here too
@@ -1898,13 +1973,13 @@ void Server::AsyncRunStep()
//Ban stuff
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);
-
+
// Save environment metadata
m_env->saveMeta(m_path_world);
}
@@ -1938,7 +2013,7 @@ void Server::Receive()
catch(con::PeerNotFoundException &e)
{
//NOTE: This is not needed anymore
-
+
// The peer has been disconnected.
// Find the associated player and remove it.
@@ -1958,9 +2033,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Environment is locked first.
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
-
+
ScopeProfiler sp(g_profiler, "Server::ProcessData");
-
+
try{
Address address = m_con.GetPeerAddress(peer_id);
std::string addr_s = address.serializeString();
@@ -1984,7 +2059,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<peer_id<<" not found"<<std::endl;
return;
}
-
+
std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
u8 peer_ser_ver = getClient(peer_id)->serialization_version;
@@ -1996,7 +2071,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
ToServerCommand command = (ToServerCommand)readU16(&data[0]);
-
+
if(command == TOSERVER_INIT)
{
// [0] u16 TOSERVER_INIT
@@ -2022,7 +2097,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
//peer->serialization_version = deployed;
getClient(peer_id)->pending_serialization_version = deployed;
-
+
if(deployed == SER_FMT_VER_INVALID)
{
actionstream<<"Server: A mismatched client tried to connect from "
@@ -2037,7 +2112,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
);
return;
}
-
+
/*
Read and check network protocol version
*/
@@ -2093,7 +2168,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
);
return;
}
-
+
if(g_settings->getBool("strict_protocol_version_checking"))
{
if(net_proto_version != LATEST_PROTOCOL_VERSION)
@@ -2118,7 +2193,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Set up player
*/
-
+
// Get player name
char playername[PLAYERNAME_SIZE];
for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
@@ -2126,7 +2201,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
playername[i] = data[3+i];
}
playername[PLAYERNAME_SIZE-1] = 0;
-
+
if(playername[0]=='\0')
{
actionstream<<"Server: Player with an empty name "
@@ -2170,10 +2245,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendAccessDenied(m_con, peer_id, L"Invalid password hash");
return;
}
-
+
std::string checkpwd; // Password hash to check against
bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
-
+
// If no authentication info exists for user, create it
if(!has_auth){
if(!isSingleplayer() &&
@@ -2194,7 +2269,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
scriptapi_create_auth(m_lua, playername, initial_password);
}
-
+
has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
if(!has_auth){
@@ -2219,7 +2294,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
L"Running in simple singleplayer mode.");
return;
}
-
+
// Enforce user limit.
// Don't enforce for users that have some admin right
if(m_clients.size() >= g_settings->getU16("max_users") &&
@@ -2257,7 +2332,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
-
+
// Send as reliable
m_con.Send(peer_id, 0, reply, true);
}
@@ -2293,18 +2368,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"Server: Sending content to "
<<getPlayerName(peer_id)<<std::endl;
+ // Send player movement settings
+ SendMovement(m_con, peer_id);
+
// Send item definitions
SendItemDef(m_con, peer_id, m_itemdef);
-
+
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
-
+
// Send media announcement
sendMediaAnnouncement(peer_id);
-
+
// Send privileges
SendPlayerPrivileges(peer_id);
-
+
// Send inventory formspec
SendPlayerInventoryFormspec(peer_id);
@@ -2315,10 +2393,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send HP
if(g_settings->getBool("enable_damage"))
SendPlayerHP(peer_id);
-
+
// Send detached inventories
sendDetachedInventories(peer_id);
-
+
// Show death screen if necessary
if(player->hp == 0)
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
@@ -2329,20 +2407,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
m_con.Send(peer_id, 0, data, true);
}
-
+
// Note things in chat if not in simple singleplayer mode
if(!m_simple_singleplayer_mode)
{
// Send information about server to player in chat
SendChatMessage(peer_id, getStatusString());
-
+
// Send information about joining in chat
{
std::wstring name = L"unknown";
Player *player = m_env->getPlayer(peer_id);
if(player != NULL)
name = narrow_to_wide(player->getName());
-
+
std::wstring message;
message += L"*** ";
message += name;
@@ -2350,7 +2428,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
BroadcastChatMessage(message);
}
}
-
+
// Warnings about protocol version can be issued here
if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
{
@@ -2393,7 +2471,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
" Skipping incoming command="<<command<<std::endl;
return;
}
-
+
Player *player = m_env->getPlayer(peer_id);
if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
@@ -2414,7 +2492,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
if(datasize < 2+12+12+4+4)
return;
-
+
u32 start = 0;
v3s32 ps = readV3S32(&data[start+2]);
v3s32 ss = readV3S32(&data[start+2+12]);
@@ -2442,7 +2520,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
player->control.sneak = (bool)(keyPressed&64);
player->control.LMB = (bool)(keyPressed&128);
player->control.RMB = (bool)(keyPressed&256);
-
+
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
@@ -2451,7 +2529,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
if(datasize < 2+1)
return;
-
+
/*
[0] u16 command
[2] u8 count
@@ -2477,7 +2555,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
if(datasize < 2+1)
return;
-
+
/*
[0] u16 command
[2] u8 count
@@ -2658,7 +2736,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
}
}
-
+
// Do the action
a->apply(this, playersao, this);
// Eat the action
@@ -2674,11 +2752,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
u8 buf[6];
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
+
// Read stuff
is.read((char*)buf, 2);
u16 len = readU16(buf);
-
+
std::wstring message;
for(u16 i=0; i<len; i++)
{
@@ -2692,21 +2770,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Get player name of this client
std::wstring name = narrow_to_wide(player->getName());
-
+
// Run script hook
bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
wide_to_narrow(message));
// If script ate the message, don't proceed
if(ate)
return;
-
+
// Line to send to players
std::wstring line;
// Whether to send to the player that sent the line
bool send_to_sender = false;
// Whether to send to other players
bool send_to_others = false;
-
+
// Commands are implemented in Lua, so only catch invalid
// commands that were not "eaten" and send an error back
if(message[0] == L'/')
@@ -2731,7 +2809,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
send_to_sender = true;
}
}
-
+
if(line != L"")
{
if(send_to_others)
@@ -2858,9 +2936,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
if(player->hp != 0 || !g_settings->getBool("enable_damage"))
return;
-
+
RespawnPlayer(peer_id);
-
+
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
@@ -2870,7 +2948,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else if(command == TOSERVER_REQUEST_MEDIA) {
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
+
core::list<MediaRequest> tosend;
u16 numfiles = readU16(is);
@@ -3164,7 +3242,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
}
} // action == 2
-
+
/*
3: place block or right-click object
*/
@@ -3200,7 +3278,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Apply returned ItemStack
playersao->setWieldedItem(item);
}
-
+
// If item has node placement prediction, always send the above
// node to make sure the client knows what exactly happened
if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
@@ -3261,7 +3339,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
+
v3s16 p = readV3S16(is);
std::string formname = deSerializeString(is);
int num = readU16(is);
@@ -3294,7 +3372,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
+
std::string formname = deSerializeString(is);
int num = readU16(is);
std::map<std::string, std::string> fields;
@@ -3311,7 +3389,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"Server::ProcessData(): Ignoring "
"unknown command "<<command<<std::endl;
}
-
+
} //try
catch(SendFailedException &e)
{
@@ -3397,7 +3475,7 @@ void Server::setInventoryModified(const InventoryLocation &loc)
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block)
block->raiseModified(MOD_STATE_WRITE_NEEDED);
-
+
setBlockNotSent(blockpos);
}
break;
@@ -3416,11 +3494,11 @@ core::list<PlayerInfo> Server::getPlayerInfo()
DSTACK(__FUNCTION_NAME);
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
-
+
core::list<PlayerInfo> list;
core::list<Player*> players = m_env->getPlayers();
-
+
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
@@ -3458,7 +3536,7 @@ void Server::peerAdded(con::Peer *peer)
DSTACK(__FUNCTION_NAME);
verbosestream<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl;
-
+
PeerChange c;
c.type = PEER_ADDED;
c.peer_id = peer->id;
@@ -3471,7 +3549,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
DSTACK(__FUNCTION_NAME);
verbosestream<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
-
+
PeerChange c;
c.type = PEER_REMOVED;
c.peer_id = peer->id;
@@ -3483,6 +3561,32 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
Static send methods
*/
+void Server::SendMovement(con::Connection &con, u16 peer_id)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_MOVEMENT);
+ writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
+ writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
+ writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
+ writeF1000(os, g_settings->getFloat("movement_speed_walk"));
+ writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
+ writeF1000(os, g_settings->getFloat("movement_speed_fast"));
+ writeF1000(os, g_settings->getFloat("movement_speed_climb"));
+ writeF1000(os, g_settings->getFloat("movement_speed_jump"));
+ writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
+ writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
+ writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
+ writeF1000(os, g_settings->getFloat("movement_gravity"));
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ con.Send(peer_id, 0, data, true);
+}
+
void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
{
DSTACK(__FUNCTION_NAME);
@@ -3592,7 +3696,7 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
void Server::SendInventory(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
@@ -3606,11 +3710,11 @@ void Server::SendInventory(u16 peer_id)
playersao->getInventory()->serialize(os);
std::string s = os.str();
-
+
SharedBuffer<u8> data(s.size()+2);
writeU16(&data[0], TOCLIENT_INVENTORY);
memcpy(&data[2], s.c_str(), s.size());
-
+
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
@@ -3618,18 +3722,18 @@ void Server::SendInventory(u16 peer_id)
void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
{
DSTACK(__FUNCTION_NAME);
-
+
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
-
+
// Write command
writeU16(buf, TOCLIENT_CHAT_MESSAGE);
os.write((char*)buf, 2);
-
+
// Write length
writeU16(buf, message.size());
os.write((char*)buf, 2);
-
+
// Write string
for(u32 i=0; i<message.size(); i++)
{
@@ -3637,7 +3741,7 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
writeU16(buf, w);
os.write((char*)buf, 2);
}
-
+
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
@@ -3700,7 +3804,7 @@ void Server::SendMovePlayer(u16 peer_id)
writeV3F1000(os, player->getPosition());
writeF1000(os, player->getPitch());
writeF1000(os, player->getYaw());
-
+
{
v3f pos = player->getPosition();
f32 pitch = player->getPitch();
@@ -3728,7 +3832,7 @@ void Server::SendPlayerPrivileges(u16 peer_id)
std::set<std::string> privs;
scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
-
+
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PRIVILEGES);
writeU16(os, privs.size());
@@ -3890,7 +3994,7 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
// Don't send if it's the same one
if(client->peer_id == ignore_id)
continue;
-
+
if(far_players)
{
// Get player
@@ -3978,7 +4082,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
DSTACK(__FUNCTION_NAME);
v3s16 p = block->getPos();
-
+
#if 0
// Analyze it a bit
bool completely_air = true;
@@ -4003,7 +4107,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
/*
Create a packet with the block in the right format
*/
-
+
std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver, false);
std::string s = os.str();
@@ -4019,7 +4123,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
/*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<": \tpacket size: "<<replysize<<std::endl;*/
-
+
/*
Send packet
*/
@@ -4038,7 +4142,7 @@ void Server::SendBlocks(float dtime)
core::array<PrioritySortedBlockTransfer> queue;
s32 total_sending = 0;
-
+
{
ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
@@ -4055,10 +4159,10 @@ void Server::SendBlocks(float dtime)
continue;
total_sending += client->SendingCount();
-
+
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
-
+
client->GetNextBlocks(this, dtime, queue);
}
}
@@ -4074,7 +4178,7 @@ void Server::SendBlocks(float dtime)
if(total_sending >= g_settings->getS32
("max_simultaneous_block_sends_server_total"))
break;
-
+
PrioritySortedBlockTransfer q = queue[i];
MapBlock *block = NULL;
@@ -4102,10 +4206,10 @@ void Server::fillMediaCache()
DSTACK(__FUNCTION_NAME);
infostream<<"Server: Calculating media file checksums"<<std::endl;
-
+
// Collect all media file paths
std::list<std::string> paths;
- for(core::list<ModSpec>::Iterator i = m_mods.begin();
+ for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
paths.push_back(mod.path + DIR_DELIM + "textures");
@@ -4115,7 +4219,7 @@ void Server::fillMediaCache()
}
std::string path_all = "textures";
paths.push_back(path_all + DIR_DELIM + "all");
-
+
// Collect media file information from paths into cache
for(std::list<std::string>::iterator i = paths.begin();
i != paths.end(); i++)
@@ -4235,7 +4339,7 @@ void Server::sendMediaAnnouncement(u16 peer_id)
string sha1_digest
}
*/
-
+
writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
writeU16(os, file_announcements.size());
@@ -4436,7 +4540,7 @@ void Server::sendDetachedInventories(u16 peer_id)
void Server::DiePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
@@ -4476,7 +4580,7 @@ void Server::RespawnPlayer(u16 peer_id)
void Server::UpdateCrafting(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
-
+
Player* player = m_env->getPlayer(peer_id);
assert(player);
@@ -4672,7 +4776,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
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()){
log->push_back("Nothing to do.");
@@ -4681,7 +4785,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
int num_tried = 0;
int num_failed = 0;
-
+
for(std::list<RollbackAction>::const_iterator
i = actions.begin();
i != actions.end(); i++)
@@ -4704,7 +4808,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
log->push_back(os.str());
}
}
-
+
infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
<<" failed"<<std::endl;
@@ -4770,7 +4874,7 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager()
const ModSpec* Server::getModSpec(const std::string &modname)
{
- for(core::list<ModSpec>::Iterator i = m_mods.begin();
+ for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
if(mod.name == modname)
@@ -4780,7 +4884,7 @@ const ModSpec* Server::getModSpec(const std::string &modname)
}
void Server::getModNames(core::list<std::string> &modlist)
{
- for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
+ for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
{
modlist.push_back((*i).name);
}
@@ -4795,13 +4899,15 @@ v3f findSpawnPos(ServerMap &map)
//return v3f(50,50,50)*BS;
v3s16 nodepos;
-
+
#if 0
nodepos = v2s16(0,0);
groundheight = 20;
#endif
#if 1
+ s16 water_level = map.m_mgparams->water_level;
+
// Try to find a good place a few times
for(s32 i=0; i<1000; i++)
{
@@ -4813,18 +4919,18 @@ v3f findSpawnPos(ServerMap &map)
// Get ground height at point (fallbacks to heightmap function)
s16 groundheight = map.findGroundLevel(nodepos2d);
// Don't go underwater
- if(groundheight < WATER_LEVEL)
+ if(groundheight <= water_level)
{
//infostream<<"-> Underwater"<<std::endl;
continue;
}
// Don't go to high places
- if(groundheight > WATER_LEVEL + 4)
+ if(groundheight > water_level + 6)
{
//infostream<<"-> Underwater"<<std::endl;
continue;
}
-
+
nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
bool is_good = false;
s32 air_count = 0;
@@ -4849,7 +4955,7 @@ v3f findSpawnPos(ServerMap &map)
}
}
#endif
-
+
return intToFloat(nodepos, BS);
}
@@ -4922,7 +5028,7 @@ void Server::handlePeerChange(PeerChange &c)
{
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
-
+
if(c.type == PEER_ADDED)
{
/*
@@ -4952,7 +5058,7 @@ void Server::handlePeerChange(PeerChange &c)
n = m_clients.find(c.peer_id);
// The client should exist
assert(n != NULL);
-
+
/*
Mark objects to be not known by the client
*/
@@ -4965,7 +5071,7 @@ void Server::handlePeerChange(PeerChange &c)
// Get object
u16 id = i.getNode()->getKey();
ServerActiveObject* obj = m_env->getActiveObject(id);
-
+
if(obj && obj->m_known_by_count > 0)
obj->m_known_by_count--;
}
@@ -5000,7 +5106,7 @@ void Server::handlePeerChange(PeerChange &c)
message += L" (timed out)";
}
}
-
+
/* Run scripts and remove from environment */
{
if(player != NULL)
@@ -5043,18 +5149,18 @@ void Server::handlePeerChange(PeerChange &c)
<<os.str()<<std::endl;
}
}
-
+
// Delete client
delete m_clients[c.peer_id];
m_clients.remove(c.peer_id);
// Send player info to all remaining clients
//SendPlayerInfos();
-
+
// Send leave chat message to all remaining clients
if(message.length() != 0)
BroadcastChatMessage(message);
-
+
} // PEER_REMOVED
else
{
@@ -5079,7 +5185,7 @@ void Server::handlePeerChanges()
void dedicated_server_loop(Server &server, bool &kill)
{
DSTACK(__FUNCTION_NAME);
-
+
verbosestream<<"dedicated_server_loop()"<<std::endl;
IntervalLimiter m_profiler_interval;
@@ -5098,6 +5204,10 @@ void dedicated_server_loop(Server &server, bool &kill)
if(server.getShutdownRequested() || kill)
{
infostream<<"Dedicated server quitting"<<std::endl;
+#if USE_CURL
+ if(g_settings->getBool("server_announce") == true)
+ ServerList::sendAnnounce("delete");
+#endif
break;
}