diff options
Diffstat (limited to 'src/server.cpp')
-rw-r--r-- | src/server.cpp | 432 |
1 files changed, 93 insertions, 339 deletions
diff --git a/src/server.cpp b/src/server.cpp index a8640ad10..41a7a4289 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,6 +1,6 @@ /* -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com> +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "itemdef.h" #include "craftdef.h" +#include "emerge.h" #include "mapgen.h" #include "biome.h" #include "content_mapnode.h" @@ -51,66 +52,13 @@ 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" #include "rollback.h" #include "util/serialize.h" -#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" - -#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) - -class MapEditEventIgnorer -{ -public: - MapEditEventIgnorer(bool *flag): - m_flag(flag) - { - if(*m_flag == false) - *m_flag = true; - else - m_flag = NULL; - } - - ~MapEditEventIgnorer() - { - if(m_flag) - { - assert(*m_flag); - *m_flag = false; - } - } - -private: - bool *m_flag; -}; - -class MapEditEventAreaIgnorer -{ -public: - MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a): - m_ignorevariable(ignorevariable) - { - if(m_ignorevariable->getVolume() == 0) - *m_ignorevariable = a; - else - m_ignorevariable = NULL; - } - - ~MapEditEventAreaIgnorer() - { - if(m_ignorevariable) - { - assert(m_ignorevariable->getVolume() != 0); - *m_ignorevariable = VoxelArea(); - } - } - -private: - VoxelArea *m_ignorevariable; -}; - void * ServerThread::Thread() { ThreadStarted(); @@ -156,265 +104,6 @@ void * ServerThread::Thread() return NULL; } -void * EmergeThread::Thread() -{ - ThreadStarted(); - - log_register_thread("EmergeThread"); - - DSTACK(__FUNCTION_NAME); - - BEGIN_DEBUG_EXCEPTION_HANDLER - - 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. - - After queue is empty, exit. - */ - while(getRun()) - try{ - 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; - - /* - Do not generate over-limit - */ - 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. - - Also decrement the emerge queue count in clients. - */ - - bool only_from_disk = true; - - { - core::map<u16, u8>::Iterator i; - for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++) - { - //u16 peer_id = i.getNode()->getKey(); - - // Check flags - 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; - - - - MapBlock *block = NULL; - bool got_block = true; - core::map<v3s16, MapBlock*> modified_blocks; - - /* - Try to fetch block from memory or disk. - If not found and asked to generate, initialize generator. - */ - - bool started_generate = false; - 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()) - { - if(enable_mapgen_debug_info) - infostream<<"EmergeThread: not in memory, " - <<"attempting to load from disk"<<std::endl; - - block = map.loadBlock(p); - } - - // If could not load and allowed to generate, start generation - // inside this same envlock - if(only_from_disk == false && - (block == NULL || block->isGenerated() == false)){ - if(enable_mapgen_debug_info) - infostream<<"EmergeThread: generating"<<std::endl; - started_generate = true; - - map.initBlockMake(&data, p); - } - } - - /* - If generator was initialized, generate now when envlock is free. - */ - if(started_generate) - { - { - ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block", - SPT_AVG); - TimeTaker t("mapgen::make_block()"); - - 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); - - // Blit data back on map, update lighting, add mobs and - // whatever this does - map.finishBlockMake(&data, modified_blocks); - - // 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) - break; - - /* - Do some post-generate stuff - */ - - 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 - to anybody - */ - //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events); - MapEditEventAreaIgnorer ign( - &m_server->m_ignore_map_edit_events_area, - VoxelArea(minp, maxp)); - { - TimeTaker timer("on_generated"); - scriptapi_environment_on_generated(m_server->m_lua, - 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; - - // Activate objects and stuff - m_server->m_env->activateBlock(block, 0); - }while(false); - } - - 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); - - /* - Add the originally fetched block to the modified list - */ - if(got_block) - { - 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 - client->SetBlocksNotSent(modified_blocks); - } - } - } - catch(VersionMismatchException &e) - { - std::ostringstream err; - err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl; - err<<"----"<<std::endl; - err<<"\""<<e.what()<<"\""<<std::endl; - err<<"See debug.txt."<<std::endl; - err<<"World probably saved by a newer version of Minetest."<<std::endl; - m_server->setAsyncFatalError(err.str()); - } - catch(SerializationError &e) - { - std::ostringstream err; - err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl; - err<<"----"<<std::endl; - err<<"\""<<e.what()<<"\""<<std::endl; - err<<"See debug.txt."<<std::endl; - err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl; - m_server->setAsyncFatalError(err.str()); - } - - END_DEBUG_EXCEPTION_HANDLER(errorstream) - - log_deregister_thread(); - - return NULL; -} - v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const { if(pos_exists) *pos_exists = false; @@ -769,7 +458,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, */ if(block == NULL || surely_not_found_on_disk || block_is_invalid) { - //TODO: Get value from somewhere + /* //TODO: Get value from somewhere // Allow only one block in emerge queue //if(server->m_emerge_queue.peerItemCount(peer_id) < 1) // Allow two blocks in queue per client @@ -798,7 +487,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, nearest_emergefull_d = d; goto queue_full_break; } + */ + if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) { + if (nearest_emerged_d == -1) + nearest_emerged_d = d; + } else { + if (nearest_emergefull_d == -1) + nearest_emergefull_d = d; + goto queue_full_break; + } + // get next one. continue; } @@ -952,7 +651,7 @@ Server::Server( m_craftdef(createCraftDefManager()), m_event(new EventManager()), m_thread(this), - m_emergethread(this), + //m_emergethread(this), m_time_of_day_send_timer(0), m_uptime(0), m_shutdown_requested(false), @@ -960,10 +659,13 @@ Server::Server( m_ignore_map_edit_events_peer_id(0) { m_liquid_transform_timer = 0.0; + m_liquid_transform_every = 1.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(); @@ -998,17 +700,20 @@ Server::Server( 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()) { - errorstream << "The following mods have unsatisfied dependencies: "; - std::list<ModSpec> modlist = modconf.getUnsatisfiedMods(); - for(std::list<ModSpec>::iterator it = modlist.begin(); - it != modlist.end(); ++it) + for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin(); + it != unsatisfied_mods.end(); ++it) { - errorstream << (*it).name << " "; + 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; } - errorstream << std::endl; } Settings worldmt_settings; @@ -1033,12 +738,15 @@ Server::Server( 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: "; + 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 << " \"" << (*it) << "\""; errorstream << std::endl; } @@ -1127,6 +835,8 @@ Server::Server( Add some test ActiveBlockModifiers to environment */ add_legacy_abms(m_env, m_nodedef); + + m_liquid_transform_every = g_settings->getFloat("liquid_update"); } Server::~Server() @@ -1269,9 +979,9 @@ void Server::stop() // Stop threads (set run=false first so both start stopping) m_thread.setRun(false); - m_emergethread.setRun(false); + //m_emergethread.setRun(false); m_thread.stop(); - m_emergethread.stop(); + //m_emergethread.stop(); infostream<<"Server: Threads stopped"<<std::endl; } @@ -1443,9 +1153,9 @@ void Server::AsyncRunStep() /* Transform liquids */ m_liquid_transform_timer += dtime; - if(m_liquid_transform_timer >= 1.00) + if(m_liquid_transform_timer >= m_liquid_transform_every) { - m_liquid_transform_timer -= 1.00; + m_liquid_transform_timer -= m_liquid_transform_every; JMutexAutoLock lock(m_env_mutex); @@ -1499,7 +1209,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 @@ -1513,10 +1223,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")) { @@ -1927,7 +1652,8 @@ void Server::AsyncRunStep() { counter = 0.0; - m_emergethread.trigger(); + for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++) + m_emerge->emergethread[i]->trigger(); // Update m_enable_rollback_recording here too m_enable_rollback_recording = @@ -2344,6 +2070,9 @@ 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); @@ -3088,8 +2817,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"Server: Not punching: Node not found." <<" Adding block to emerge queue." <<std::endl; - m_emerge_queue.addBlock(peer_id, - getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK); + m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false); } if(n.getContent() != CONTENT_IGNORE) scriptapi_node_on_punch(m_lua, p_under, n, playersao); @@ -3145,8 +2873,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"Server: Not finishing digging: Node not found." <<" Adding block to emerge queue." <<std::endl; - m_emerge_queue.addBlock(peer_id, - getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK); + m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false); } /* Cheat prevention */ @@ -3534,6 +3261,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); @@ -4675,10 +4428,7 @@ void Server::notifyPlayers(const std::wstring msg) void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate) { - u8 flags = 0; - if(!allow_generate) - flags |= BLOCK_EMERGE_FLAG_FROMDISK; - m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags); + m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate); } Inventory* Server::createDetachedInventory(const std::string &name) @@ -5151,6 +4901,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; } |