emerge.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include "emerge.h"
  18. #include "server.h"
  19. #include <iostream>
  20. #include <queue>
  21. #include "jthread/jevent.h"
  22. #include "map.h"
  23. #include "environment.h"
  24. #include "util/container.h"
  25. #include "util/thread.h"
  26. #include "main.h"
  27. #include "constants.h"
  28. #include "voxel.h"
  29. #include "config.h"
  30. #include "mapblock.h"
  31. #include "serverobject.h"
  32. #include "settings.h"
  33. #include "scripting_game.h"
  34. #include "profiler.h"
  35. #include "log.h"
  36. #include "nodedef.h"
  37. #include "biome.h"
  38. #include "mapgen_v6.h"
  39. #include "mapgen_v7.h"
  40. #include "mapgen_singlenode.h"
  41. class EmergeThread : public JThread
  42. {
  43. public:
  44. Server *m_server;
  45. ServerMap *map;
  46. EmergeManager *emerge;
  47. Mapgen *mapgen;
  48. bool enable_mapgen_debug_info;
  49. int id;
  50. Event qevent;
  51. std::queue<v3s16> blockqueue;
  52. EmergeThread(Server *server, int ethreadid):
  53. JThread(),
  54. m_server(server),
  55. map(NULL),
  56. emerge(NULL),
  57. mapgen(NULL),
  58. enable_mapgen_debug_info(false),
  59. id(ethreadid)
  60. {
  61. }
  62. void *Thread();
  63. bool popBlockEmerge(v3s16 *pos, u8 *flags);
  64. bool getBlockOrStartGen(v3s16 p, MapBlock **b,
  65. BlockMakeData *data, bool allow_generate);
  66. };
  67. /////////////////////////////// Emerge Manager ////////////////////////////////
  68. EmergeManager::EmergeManager(IGameDef *gamedef) {
  69. //register built-in mapgens
  70. registerMapgen("v6", new MapgenFactoryV6());
  71. registerMapgen("v7", new MapgenFactoryV7());
  72. registerMapgen("singlenode", new MapgenFactorySinglenode());
  73. this->ndef = gamedef->getNodeDefManager();
  74. this->biomedef = new BiomeDefManager();
  75. this->gennotify = 0;
  76. // Note that accesses to this variable are not synchronized.
  77. // This is because the *only* thread ever starting or stopping
  78. // EmergeThreads should be the ServerThread.
  79. this->threads_active = false;
  80. mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
  81. // if unspecified, leave a proc for the main thread and one for
  82. // some other misc thread
  83. int nthreads = 0;
  84. if (!g_settings->getS16NoEx("num_emerge_threads", nthreads))
  85. nthreads = porting::getNumberOfProcessors() - 2;
  86. if (nthreads < 1)
  87. nthreads = 1;
  88. qlimit_total = g_settings->getU16("emergequeue_limit_total");
  89. if (!g_settings->getU16NoEx("emergequeue_limit_diskonly", qlimit_diskonly))
  90. qlimit_diskonly = nthreads * 5 + 1;
  91. if (!g_settings->getU16NoEx("emergequeue_limit_generate", qlimit_generate))
  92. qlimit_generate = nthreads + 1;
  93. // don't trust user input for something very important like this
  94. if (qlimit_total < 1)
  95. qlimit_total = 1;
  96. if (qlimit_diskonly < 1)
  97. qlimit_diskonly = 1;
  98. if (qlimit_generate < 1)
  99. qlimit_generate = 1;
  100. for (int i = 0; i != nthreads; i++)
  101. emergethread.push_back(new EmergeThread((Server *)gamedef, i));
  102. infostream << "EmergeManager: using " << nthreads << " threads" << std::endl;
  103. }
  104. EmergeManager::~EmergeManager() {
  105. for (unsigned int i = 0; i != emergethread.size(); i++) {
  106. if (threads_active) {
  107. emergethread[i]->Stop();
  108. emergethread[i]->qevent.signal();
  109. emergethread[i]->Wait();
  110. }
  111. delete emergethread[i];
  112. delete mapgen[i];
  113. }
  114. emergethread.clear();
  115. mapgen.clear();
  116. for (unsigned int i = 0; i < ores.size(); i++)
  117. delete ores[i];
  118. ores.clear();
  119. for (unsigned int i = 0; i < decorations.size(); i++)
  120. delete decorations[i];
  121. decorations.clear();
  122. for (std::map<std::string, MapgenFactory *>::iterator iter = mglist.begin();
  123. iter != mglist.end(); iter ++) {
  124. delete iter->second;
  125. }
  126. mglist.clear();
  127. delete biomedef;
  128. if (params.sparams) {
  129. delete params.sparams;
  130. params.sparams = NULL;
  131. }
  132. }
  133. void EmergeManager::loadMapgenParams() {
  134. loadParamsFromSettings(g_settings);
  135. if (g_settings->get("fixed_map_seed").empty()) {
  136. params.seed = (((u64)(myrand() & 0xffff) << 0)
  137. | ((u64)(myrand() & 0xffff) << 16)
  138. | ((u64)(myrand() & 0xffff) << 32)
  139. | ((u64)(myrand() & 0xffff) << 48));
  140. }
  141. }
  142. void EmergeManager::initMapgens() {
  143. if (mapgen.size())
  144. return;
  145. // Resolve names of nodes for things that were registered
  146. // (at this point, the registration period is over)
  147. biomedef->resolveNodeNames(ndef);
  148. for (size_t i = 0; i != ores.size(); i++)
  149. ores[i]->resolveNodeNames(ndef);
  150. for (size_t i = 0; i != decorations.size(); i++)
  151. decorations[i]->resolveNodeNames(ndef);
  152. if (!params.sparams) {
  153. params.sparams = createMapgenParams(params.mg_name);
  154. if (!params.sparams) {
  155. params.mg_name = DEFAULT_MAPGEN;
  156. params.sparams = createMapgenParams(params.mg_name);
  157. assert(params.sparams);
  158. }
  159. params.sparams->readParams(g_settings);
  160. }
  161. // Create the mapgens
  162. for (size_t i = 0; i != emergethread.size(); i++) {
  163. Mapgen *mg = createMapgen(params.mg_name, i, &params);
  164. assert(mg);
  165. mapgen.push_back(mg);
  166. }
  167. }
  168. Mapgen *EmergeManager::getCurrentMapgen() {
  169. for (unsigned int i = 0; i != emergethread.size(); i++) {
  170. if (emergethread[i]->IsSameThread())
  171. return emergethread[i]->mapgen;
  172. }
  173. return NULL;
  174. }
  175. void EmergeManager::startThreads() {
  176. if (threads_active)
  177. return;
  178. for (unsigned int i = 0; i != emergethread.size(); i++)
  179. emergethread[i]->Start();
  180. threads_active = true;
  181. }
  182. void EmergeManager::stopThreads() {
  183. if (!threads_active)
  184. return;
  185. // Request thread stop in parallel
  186. for (unsigned int i = 0; i != emergethread.size(); i++) {
  187. emergethread[i]->Stop();
  188. emergethread[i]->qevent.signal();
  189. }
  190. // Then do the waiting for each
  191. for (unsigned int i = 0; i != emergethread.size(); i++)
  192. emergethread[i]->Wait();
  193. threads_active = false;
  194. }
  195. bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate) {
  196. std::map<v3s16, BlockEmergeData *>::const_iterator iter;
  197. BlockEmergeData *bedata;
  198. u16 count;
  199. u8 flags = 0;
  200. int idx = 0;
  201. if (allow_generate)
  202. flags |= BLOCK_EMERGE_ALLOWGEN;
  203. {
  204. JMutexAutoLock queuelock(queuemutex);
  205. count = blocks_enqueued.size();
  206. if (count >= qlimit_total)
  207. return false;
  208. count = peer_queue_count[peer_id];
  209. u16 qlimit_peer = allow_generate ? qlimit_generate : qlimit_diskonly;
  210. if (count >= qlimit_peer)
  211. return false;
  212. iter = blocks_enqueued.find(p);
  213. if (iter != blocks_enqueued.end()) {
  214. bedata = iter->second;
  215. bedata->flags |= flags;
  216. return true;
  217. }
  218. bedata = new BlockEmergeData;
  219. bedata->flags = flags;
  220. bedata->peer_requested = peer_id;
  221. blocks_enqueued.insert(std::make_pair(p, bedata));
  222. peer_queue_count[peer_id] = count + 1;
  223. // insert into the EmergeThread queue with the least items
  224. int lowestitems = emergethread[0]->blockqueue.size();
  225. for (unsigned int i = 1; i != emergethread.size(); i++) {
  226. int nitems = emergethread[i]->blockqueue.size();
  227. if (nitems < lowestitems) {
  228. idx = i;
  229. lowestitems = nitems;
  230. }
  231. }
  232. emergethread[idx]->blockqueue.push(p);
  233. }
  234. emergethread[idx]->qevent.signal();
  235. return true;
  236. }
  237. int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
  238. if (mapgen.size() == 0 || !mapgen[0]) {
  239. errorstream << "EmergeManager: getGroundLevelAtPoint() called"
  240. " before mapgen initialized" << std::endl;
  241. return 0;
  242. }
  243. return mapgen[0]->getGroundLevelAtPoint(p);
  244. }
  245. bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
  246. /*
  247. v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
  248. (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
  249. int ground_level = getGroundLevelAtPoint(p);
  250. return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
  251. */
  252. //yuck, but then again, should i bother being accurate?
  253. //the height of the nodes in a single block is quite variable
  254. return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level;
  255. }
  256. u32 EmergeManager::getBlockSeed(v3s16 p) {
  257. return (u32)(params.seed & 0xFFFFFFFF) +
  258. p.Z * 38134234 +
  259. p.Y * 42123 +
  260. p.X * 23;
  261. }
  262. Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
  263. MapgenParams *mgparams) {
  264. std::map<std::string, MapgenFactory *>::const_iterator iter;
  265. iter = mglist.find(mgname);
  266. if (iter == mglist.end()) {
  267. errorstream << "EmergeManager; mapgen " << mgname <<
  268. " not registered" << std::endl;
  269. return NULL;
  270. }
  271. MapgenFactory *mgfactory = iter->second;
  272. return mgfactory->createMapgen(mgid, mgparams, this);
  273. }
  274. MapgenSpecificParams *EmergeManager::createMapgenParams(std::string mgname) {
  275. std::map<std::string, MapgenFactory *>::const_iterator iter;
  276. iter = mglist.find(mgname);
  277. if (iter == mglist.end()) {
  278. errorstream << "EmergeManager: mapgen " << mgname <<
  279. " not registered" << std::endl;
  280. return NULL;
  281. }
  282. MapgenFactory *mgfactory = iter->second;
  283. return mgfactory->createMapgenParams();
  284. }
  285. void EmergeManager::loadParamsFromSettings(Settings *settings) {
  286. std::string seed_str;
  287. const char *setname = (settings == g_settings) ? "fixed_map_seed" : "seed";
  288. if (settings->getNoEx(setname, seed_str))
  289. params.seed = read_seed(seed_str.c_str());
  290. settings->getNoEx("mg_name", params.mg_name);
  291. settings->getS16NoEx("water_level", params.water_level);
  292. settings->getS16NoEx("chunksize", params.chunksize);
  293. settings->getFlagStrNoEx("mg_flags", params.flags, flagdesc_mapgen);
  294. delete params.sparams;
  295. params.sparams = createMapgenParams(params.mg_name);
  296. if (params.sparams)
  297. params.sparams->readParams(settings);
  298. }
  299. void EmergeManager::saveParamsToSettings(Settings *settings) {
  300. settings->set("mg_name", params.mg_name);
  301. settings->setU64("seed", params.seed);
  302. settings->setS16("water_level", params.water_level);
  303. settings->setS16("chunksize", params.chunksize);
  304. settings->setFlagStr("mg_flags", params.flags, flagdesc_mapgen, (u32)-1);
  305. if (params.sparams)
  306. params.sparams->writeParams(settings);
  307. }
  308. void EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) {
  309. mglist.insert(std::make_pair(mgname, mgfactory));
  310. infostream << "EmergeManager: registered mapgen " << mgname << std::endl;
  311. }
  312. ////////////////////////////// Emerge Thread //////////////////////////////////
  313. bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags) {
  314. std::map<v3s16, BlockEmergeData *>::iterator iter;
  315. JMutexAutoLock queuelock(emerge->queuemutex);
  316. if (blockqueue.empty())
  317. return false;
  318. v3s16 p = blockqueue.front();
  319. blockqueue.pop();
  320. *pos = p;
  321. iter = emerge->blocks_enqueued.find(p);
  322. if (iter == emerge->blocks_enqueued.end())
  323. return false; //uh oh, queue and map out of sync!!
  324. BlockEmergeData *bedata = iter->second;
  325. *flags = bedata->flags;
  326. emerge->peer_queue_count[bedata->peer_requested]--;
  327. delete bedata;
  328. emerge->blocks_enqueued.erase(iter);
  329. return true;
  330. }
  331. bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b,
  332. BlockMakeData *data, bool allow_gen) {
  333. v2s16 p2d(p.X, p.Z);
  334. //envlock: usually takes <=1ms, sometimes 90ms or ~400ms to acquire
  335. JMutexAutoLock envlock(m_server->m_env_mutex);
  336. // Load sector if it isn't loaded
  337. if (map->getSectorNoGenerateNoEx(p2d) == NULL)
  338. map->loadSectorMeta(p2d);
  339. // Attempt to load block
  340. MapBlock *block = map->getBlockNoCreateNoEx(p);
  341. if (!block || block->isDummy() || !block->isGenerated()) {
  342. EMERGE_DBG_OUT("not in memory, attempting to load from disk");
  343. block = map->loadBlock(p);
  344. if (block && block->isGenerated())
  345. map->prepareBlock(block);
  346. }
  347. // If could not load and allowed to generate,
  348. // start generation inside this same envlock
  349. if (allow_gen && (block == NULL || !block->isGenerated())) {
  350. EMERGE_DBG_OUT("generating");
  351. *b = block;
  352. return map->initBlockMake(data, p);
  353. }
  354. *b = block;
  355. return false;
  356. }
  357. void *EmergeThread::Thread() {
  358. ThreadStarted();
  359. log_register_thread("EmergeThread" + itos(id));
  360. DSTACK(__FUNCTION_NAME);
  361. BEGIN_DEBUG_EXCEPTION_HANDLER
  362. v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
  363. v3s16 p;
  364. u8 flags = 0;
  365. map = (ServerMap *)&(m_server->m_env->getMap());
  366. emerge = m_server->m_emerge;
  367. mapgen = emerge->mapgen[id];
  368. enable_mapgen_debug_info = emerge->mapgen_debug_info;
  369. porting::setThreadName("EmergeThread");
  370. while (!StopRequested())
  371. try {
  372. if (!popBlockEmerge(&p, &flags)) {
  373. qevent.wait();
  374. continue;
  375. }
  376. last_tried_pos = p;
  377. if (blockpos_over_limit(p))
  378. continue;
  379. bool allow_generate = flags & BLOCK_EMERGE_ALLOWGEN;
  380. EMERGE_DBG_OUT("p=" PP(p) " allow_generate=" << allow_generate);
  381. /*
  382. Try to fetch block from memory or disk.
  383. If not found and asked to generate, initialize generator.
  384. */
  385. BlockMakeData data;
  386. MapBlock *block = NULL;
  387. std::map<v3s16, MapBlock *> modified_blocks;
  388. if (getBlockOrStartGen(p, &block, &data, allow_generate) && mapgen) {
  389. {
  390. ScopeProfiler sp(g_profiler, "EmergeThread: Mapgen::makeChunk", SPT_AVG);
  391. TimeTaker t("mapgen::make_block()");
  392. mapgen->makeChunk(&data);
  393. if (enable_mapgen_debug_info == false)
  394. t.stop(true); // Hide output
  395. }
  396. {
  397. //envlock: usually 0ms, but can take either 30 or 400ms to acquire
  398. JMutexAutoLock envlock(m_server->m_env_mutex);
  399. ScopeProfiler sp(g_profiler, "EmergeThread: after "
  400. "Mapgen::makeChunk (envlock)", SPT_AVG);
  401. map->finishBlockMake(&data, modified_blocks);
  402. block = map->getBlockNoCreateNoEx(p);
  403. if (block) {
  404. /*
  405. Do some post-generate stuff
  406. */
  407. v3s16 minp = data.blockpos_min * MAP_BLOCKSIZE;
  408. v3s16 maxp = data.blockpos_max * MAP_BLOCKSIZE +
  409. v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
  410. // Ignore map edit events, they will not need to be sent
  411. // to anybody because the block hasn't been sent to anybody
  412. MapEditEventAreaIgnorer
  413. ign(&m_server->m_ignore_map_edit_events_area,
  414. VoxelArea(minp, maxp));
  415. try { // takes about 90ms with -O1 on an e3-1230v2
  416. m_server->getScriptIface()->environment_OnGenerated(
  417. minp, maxp, emerge->getBlockSeed(minp));
  418. } catch(LuaError &e) {
  419. m_server->setAsyncFatalError(e.what());
  420. }
  421. EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
  422. m_server->m_env->activateBlock(block, 0);
  423. }
  424. }
  425. }
  426. /*
  427. Set sent status of modified blocks on clients
  428. */
  429. // Add the originally fetched block to the modified list
  430. if (block)
  431. modified_blocks[p] = block;
  432. if (modified_blocks.size() > 0) {
  433. m_server->SetBlocksNotSent(modified_blocks);
  434. }
  435. }
  436. catch (VersionMismatchException &e) {
  437. std::ostringstream err;
  438. err << "World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
  439. err << "----"<<std::endl;
  440. err << "\""<<e.what()<<"\""<<std::endl;
  441. err << "See debug.txt."<<std::endl;
  442. err << "World probably saved by a newer version of Minetest."<<std::endl;
  443. m_server->setAsyncFatalError(err.str());
  444. }
  445. catch (SerializationError &e) {
  446. std::ostringstream err;
  447. err << "Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
  448. err << "----"<<std::endl;
  449. err << "\""<<e.what()<<"\""<<std::endl;
  450. err << "See debug.txt."<<std::endl;
  451. err << "You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
  452. m_server->setAsyncFatalError(err.str());
  453. }
  454. END_DEBUG_EXCEPTION_HANDLER(errorstream)
  455. log_deregister_thread();
  456. return NULL;
  457. }