diff --git a/src/client/fm_far_container.cpp b/src/client/fm_far_container.cpp index 2bf9df40a..fa35fddd9 100644 --- a/src/client/fm_far_container.cpp +++ b/src/client/fm_far_container.cpp @@ -24,8 +24,7 @@ const MapNode &FarContainer::getNodeRefUnsafe(const v3pos_t &pos) const auto &storage = m_client->getEnv().getClientMap().far_blocks_storage[fmesh_step]; - if (const auto &it = storage.find(bpos_aligned); it != storage.end()) { - const auto &block = it->second; + if (const auto &block = storage.at_or(bpos_aligned)) { v3pos_t relpos = pos - bpos_aligned * MAP_BLOCKSIZE; const auto &relpos_shift = fmesh_step; // + 1; diff --git a/src/fm_map.cpp b/src/fm_map.cpp index 3473ad134..21d8f2b97 100644 --- a/src/fm_map.cpp +++ b/src/fm_map.cpp @@ -422,7 +422,7 @@ u32 Map::timerUpdate(float uptime, float unload_timeout, s32 max_loaded_blocks, auto m_blocks_size = m_blocks.size(); - for (auto ir : m_blocks) { + for (const auto &ir : m_blocks) { if (n++ < m_blocks_update_last) { continue; } else { @@ -1139,7 +1139,7 @@ const v3pos_t g_4dirs[4] = { }; bool ServerMap::propagateSunlight( - const v3pos_t &pos, std::set &light_sources, bool remove_light) + const v3bpos_t &pos, std::set &light_sources, bool remove_light) { MapBlock *block = getBlockNoCreateNoEx(pos); diff --git a/src/fm_server.cpp b/src/fm_server.cpp index a28865575..3c27e056e 100644 --- a/src/fm_server.cpp +++ b/src/fm_server.cpp @@ -585,14 +585,13 @@ MapDatabase *Server::GetFarDatabase(MapBlock::block_step_t step) return dbases[step].get(); }; -MapBlockP Server::loadBlockNoStore(MapDatabase *dbase, const v3bpos_t &pos) +MapBlockP Server::loadBlockNoStore(MapDatabase *dbase, const v3bpos_t &bpos) { auto *m_server = this; try { - auto block = - std::make_shared(nullptr, pos, m_server); // &m_server->getMap() + MapBlockP block{m_server->getEnv().getServerMap().createBlankBlockNoInsert(bpos)}; std::string blob; - dbase->loadBlock(pos, &blob); + dbase->loadBlock(bpos, &blob); if (!blob.length()) { return {}; } @@ -612,7 +611,7 @@ MapBlockP Server::loadBlockNoStore(MapDatabase *dbase, const v3bpos_t &pos) } return block; } catch (const std::exception &ex) { - errorstream << "Block load fail " << pos << " : " << ex.what() << "\n"; + errorstream << "Block load fail " << bpos << " : " << ex.what() << "\n"; } return {}; } diff --git a/src/fm_world_merge.cpp b/src/fm_world_merge.cpp index f460b3a9a..6ce0407fc 100644 --- a/src/fm_world_merge.cpp +++ b/src/fm_world_merge.cpp @@ -21,25 +21,22 @@ along with Freeminer. If not, see . #include #include +#include #include #include #include "constants.h" -#include "debug/iostream_debug_helpers.h" #include "database/database.h" #include "debug.h" #include "fm_server.h" #include "irr_v3d.h" #include "irrlichttypes.h" +#include "log.h" #include "mapblock.h" #include "mapnode.h" #include "profiler.h" #include "server.h" #include "settings.h" - -WorldMergeThread::WorldMergeThread(Server *server) : - thread_vector("WorldMerge", 20), m_server(server) -{ -} +#include "fm_world_merge.h" // https://stackoverflow.com/a/34937216 template @@ -62,7 +59,7 @@ static const auto load_block = [](Server *m_server, MapDatabase *dbase, return block; }; -void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up, +void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up, const v3bpos_t &bpos_aligned, MapBlock::block_step_t step) { const auto step_pow = 1; @@ -88,8 +85,16 @@ void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up if (!timestamp) timestamp = m_server->getEnv().getGameTime(); - MapBlockP block_new{m_server->getMap().createBlankBlockNoInsert(bpos_aligned)}; - block_new->setTimestampNoChangedFlag(timestamp); + MapBlockP block_up; + + if (partial) { + block_up = load_block(m_server, dbase_up, bpos_aligned); + } + if (!block_up) { + block_up.reset( + m_server->getEnv().getServerMap().createBlankBlockNoInsert(bpos_aligned)); + } + block_up->setTimestampNoChangedFlag(timestamp); size_t not_empty_nodes{}; { const auto block_size = MAP_BLOCKSIZE; @@ -120,7 +125,7 @@ void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up #else // Top content count - bool maybe_air = false; + bool maybe_air{}; MapNode air; for (const auto &dir : { v3pos_t{0, 1, 0}, @@ -162,7 +167,7 @@ void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up if (top_c.empty()) { if (maybe_air) { ++not_empty_nodes; - block_new->setNodeNoLock(npos, air); + block_up->setNodeNoLock(npos, air); } continue; } @@ -183,7 +188,7 @@ void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up // TODO better check ++not_empty_nodes; - block_new->setNodeNoLock(npos, n); + block_up->setNodeNoLock(npos, n); } } // TODO: skip full air; @@ -191,147 +196,227 @@ void merge_one_block(Server *m_server, MapDatabase *dbase, MapDatabase *dbase_up if (!not_empty_nodes) { return; } - block_new->setGenerated(true); - m_server->getEnv().getServerMap().saveBlock(block_new.get(), dbase_up, + block_up->setGenerated(true); + m_server->getEnv().getServerMap().saveBlock(block_up.get(), dbase_up, m_server->getEnv().getServerMap().m_map_compression_level); } -void *WorldMergeThread::run() +bool WorldMerger::merge_one_step( + MapBlock::block_step_t step, std::unordered_set &blocks_todo) { - BEGIN_DEBUG_EXCEPTION_HANDLER - { - u64 world_merge = 0; - g_settings->getU64NoEx("world_merge", world_merge); - if (!world_merge) - return nullptr; + auto *dbase = m_server->GetFarDatabase(step); + auto *dbase_up = m_server->GetFarDatabase(step + 1); + + if (world_merge_load_all && blocks_todo.empty()) { + actionstream << "World merge full load " << (short)step << '\n'; + std::vector loadable_blocks; + dbase->listAllLoadableBlocks(loadable_blocks); + for (const auto &bpos : loadable_blocks) { + blocks_todo.emplace(bpos); + } + } + + if (blocks_todo.empty()) { + infostream << "World merge step " << (short)step << " nothing to do " << '\n'; + return false; } - int16_t world_merge_load_all = -1; // -1 : auto; 0 : disable; 1 : force - g_settings->getS16NoEx("world_merge_load_all", world_merge_load_all); - u64 world_merge_throttle = m_server->isSingleplayer() ? 10 : 0; - g_settings->getU64NoEx("world_merge_throttle", world_merge_throttle); - u64 world_merge_max_clients = m_server->isSingleplayer() ? 1 : 0; - g_settings->getU64NoEx("world_merge_max_clients", world_merge_max_clients); - // u64 abm_world_max_blocks = m_server->isSingleplayer() ? 2000 : 10000; - // g_settings->getU64NoEx("abm_world_max_blocks", abm_world_max_blocks); - - //auto &world_merge_last = m_server->getEnv().world_merge_last; - const auto can_work = [&]() { - return (m_server->getEnv().getPlayerCount() <= world_merge_max_clients - //&& m_server->getMap().m_blocks.size() <= abm_world_max_blocks - ); + size_t cur_n = 0; + + const auto blocks_size = blocks_todo.size(); + infostream << "World merge " + //<< "run " << run + << " step " << (short)step << " blocks " + << blocks_size + //<< " per " << (porting::getTimeMs() - time_start) / 1000 << "s" + << " max_clients " << world_merge_max_clients << " throttle " + << world_merge_throttle << '\n'; + size_t processed = 0; + + const auto time_start = porting::getTimeMs(); + + const auto printstat = [&]() { + const auto time = porting::getTimeMs(); + + infostream << "World merge " + // << "run " << run + << " " << cur_n << "/" << blocks_size << " blocks loaded " + << m_server->getMap().m_blocks.size() << " processed " << processed + << " per " << (time - time_start) / 1000 << " speed " + << processed / (((time - time_start) / 1000) ?: 1) << '\n'; }; - int32_t run = 0; - //size_t pos_dir; // random start + std::unordered_set blocks_processed; - while (!stopRequested()) { - ++run; + cur_n = 0; + for (const auto &bpos : blocks_todo) { + if (stop()) { + return true; + } - if (!can_work()) { - tracestream << "Abm world wait" << '\n'; - sleep(10); + ++cur_n; + + const bpos_t shift = step + 1; + + v3bpos_t bpos_aligned((bpos.X >> shift) << shift, (bpos.Y >> shift) << shift, + (bpos.Z >> shift) << shift); + if (blocks_processed.contains(bpos_aligned)) { continue; } + blocks_processed.emplace(bpos_aligned); - auto time_start = porting::getTimeMs(); + ++processed; + g_profiler->add("Server: World merge blocks", 1); - for (MapBlock::block_step_t step = 0; step < FARMESH_STEP_MAX - 1; ++step) { - std::vector loadable_blocks; + try { - auto *dbase = m_server->GetFarDatabase(step); - auto *dbase_up = m_server->GetFarDatabase(step + 1); + merge_one_block(dbase, dbase_up, bpos_aligned, step); - if (world_merge_load_all && loadable_blocks.empty()) { - actionstream << "World merge full load " << (short)step << '\n'; - dbase->listAllLoadableBlocks(loadable_blocks); - } - if (loadable_blocks.empty()) { - break; + if (!(cur_n % 10000)) { + printstat(); } - size_t cur_n = 0; - - const auto loadable_blocks_size = loadable_blocks.size(); - infostream << "World merge run " << run << " step " << (short)step - << " blocks " << loadable_blocks_size << " per " - << (porting::getTimeMs() - time_start) / 1000 << "s" - << " max_clients " << world_merge_max_clients << " throttle " - << world_merge_throttle << '\n'; - size_t processed = 0; + if (throttle()) { + tracestream << "World merge throttle" << '\n'; - time_start = porting::getTimeMs(); - - const auto printstat = [&]() { - auto time = porting::getTimeMs(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } else if (world_merge_throttle) { + std::this_thread::sleep_for( + std::chrono::milliseconds(world_merge_throttle)); + } - infostream << "World merge run " << run << " " << cur_n << "/" - << loadable_blocks_size << " blocks loaded " - << m_server->getMap().m_blocks.size() << " processed " - << processed << " per " << (time - time_start) / 1000 - << " speed " << processed / (((time - time_start) / 1000) ?: 1) - << '\n'; - }; +#if !EXCEPTION_DEBUG + } catch (const std::exception &e) { + errorstream << "world merge" << ": exception: " << e.what() << "\n" + << stacktrace() << '\n'; + } catch (...) { + errorstream << "world merge" << ": Unknown unhandled exception at " + << __PRETTY_FUNCTION__ << ":" << __LINE__ << '\n' + << stacktrace() << '\n'; +#else + } catch (int) { // nothing +#endif + } + } + if (world_merge_load_all == 1) { + blocks_todo.clear(); + } else { + blocks_todo = blocks_processed; + } - std::unordered_set blocks_processed; + printstat(); - cur_n = 0; - for (const auto &bpos : loadable_blocks) { - if (stopRequested()) { - return nullptr; - } + return false; +} - ++cur_n; +bool WorldMerger::merge_list(std::unordered_set &blocks_todo) +{ + for (MapBlock::block_step_t step = 0; step < FARMESH_STEP_MAX - 1; ++step) { + if (merge_one_step(step, blocks_todo)) { + return true; + } + } + return false; +} - const bpos_t shift = step + 1; +bool WorldMerger::merge_all() +{ + std::unordered_set blocks_todo; + return merge_list(blocks_todo); +} - v3bpos_t bpos_aligned((bpos.X >> shift) << shift, - (bpos.Y >> shift) << shift, (bpos.Z >> shift) << shift); - if (blocks_processed.contains(bpos_aligned)) { - continue; - } - blocks_processed.emplace(bpos_aligned); +bool WorldMerger::merge_server_diff() +{ + std::unordered_set changed_blocks_for_merge; + { + const auto lock = m_server->getEnv() + .getServerMap() + .changed_blocks_for_merge.try_lock_unique_rec(); + changed_blocks_for_merge = + m_server->getEnv().getServerMap().changed_blocks_for_merge; + m_server->getEnv().getServerMap().changed_blocks_for_merge.clear(); + } - ++processed; - g_profiler->add("Server: World merge blocks", 1); + if (!changed_blocks_for_merge.empty()) { + return merge_list(changed_blocks_for_merge); + } - try { + return false; +} - merge_one_block(m_server, dbase, dbase_up, bpos_aligned, step); +WorldMergeThread::WorldMergeThread(Server *server) : + thread_vector("WorldMerge", 20), m_server(server) +{ +} - if (!(cur_n % 10000)) { - printstat(); - } +void *WorldMergeThread::run() +{ + BEGIN_DEBUG_EXCEPTION_HANDLER - if (!can_work()) { - tracestream << "World merge throttle" << '\n'; + u64 world_merge = 1; + g_settings->getU64NoEx("world_merge", world_merge); + if (!world_merge) { + return {}; + } - std::this_thread::sleep_for(std::chrono::seconds(1)); - } else if (world_merge_throttle) { - std::this_thread::sleep_for( - std::chrono::milliseconds(world_merge_throttle)); - } + std::this_thread::sleep_for(std::chrono::seconds(3)); -#if !EXCEPTION_DEBUG - } catch (const std::exception &e) { - errorstream << m_name << ": exception: " << e.what() << "\n" - << stacktrace() << '\n'; - } catch (...) { - errorstream << m_name << ": Unknown unhandled exception at " - << __PRETTY_FUNCTION__ << ":" << __LINE__ << '\n' - << stacktrace() << '\n'; -#else - } catch (int) { // nothing -#endif - } + WorldMerger merger{ + .m_server{m_server}, + .stop_func{[this]() { return stopRequested(); }}, + .throttle_func{[&]() { + return (m_server->getEnv().getPlayerCount() > + merger.world_merge_max_clients); + }}, + }; + { + g_settings->getU64NoEx("world_merge_throttle", merger.world_merge_throttle); + merger.world_merge_max_clients = m_server->isSingleplayer() ? 1 : 0; + g_settings->getU64NoEx("world_merge_max_clients", merger.world_merge_max_clients); + + { + merger.world_merge_load_all = -1; + g_settings->getS16NoEx("world_merge_load_all", merger.world_merge_load_all); + merger.world_merge_throttle = m_server->isSingleplayer() ? 10 : 0; + u64 world_merge_all = 0; + g_settings->getU64NoEx("world_merge_all", world_merge_all); + if (world_merge_all) { + merger.merge_all(); } - printstat(); + } + } + merger.world_merge_load_all = 0; + merger.partial = true; + + while (!stopRequested()) { + if (merger.throttle()) { + tracestream << "World merge wait" << '\n'; + sleep(10); + continue; + } + if (merger.merge_server_diff()) { + return {}; } sleep(60); - break; } - END_DEBUG_EXCEPTION_HANDLER - return nullptr; + + { + // unbreakable at max speed + merger.stop_func = {}; + merger.throttle_func = {}; + merger.world_merge_throttle = 0; + + if (!m_server->getEnv().getServerMap().changed_blocks_for_merge.empty()) { + actionstream + << "Merge last changed blocks " + << m_server->getEnv().getServerMap().changed_blocks_for_merge.size() + << "\n"; + } + merger.merge_server_diff(); + } + + END_DEBUG_EXCEPTION_HANDLER; + return {}; } diff --git a/src/fm_world_merge.h b/src/fm_world_merge.h new file mode 100644 index 000000000..af62ae51f --- /dev/null +++ b/src/fm_world_merge.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 2024 proller +*/ + +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#pragma once + +#include +#include "mapblock.h" + +class Server; +class MapDatabase; + +struct WorldMerger +{ + Server *m_server{}; + + std::function stop_func; + std::function throttle_func; + + bool stop() + { + if (stop_func) + return stop_func(); + return false; + } + + bool throttle() + { + if (throttle_func) + return throttle_func(); + return false; + } + + u64 world_merge_throttle{}; + u64 world_merge_max_clients{}; + int16_t world_merge_load_all{}; // -1 : auto; 0 : disable; 1 : force + bool partial{}; + + void merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up, + const v3bpos_t &bpos_aligned, MapBlock::block_step_t step); + + bool merge_one_step( + MapBlock::block_step_t step, std::unordered_set &blocks_todo); + bool merge_list(std::unordered_set &blocks_todo); + bool merge_all(); + bool merge_server_diff(); +}; diff --git a/src/key_value_storage.cpp b/src/key_value_storage.cpp index b5dcae644..4502aa606 100644 --- a/src/key_value_storage.cpp +++ b/src/key_value_storage.cpp @@ -18,23 +18,22 @@ #include #include "convert_json.h" -#include "exceptions.h" #include "filesys.h" #include "json/reader.h" #include "key_value_storage.h" #include "log.h" -#include "util/pointer.h" #include "util/string.h" KeyValueStorage::KeyValueStorage(const std::string &savedir, const std::string &name) : - db(nullptr), - db_name(name) { + db_name(name) +{ fullpath = savedir + DIR_DELIM + db_name + ".db"; open(); } #if USE_LEVELDB -bool KeyValueStorage::process_status(const leveldb::Status & status, bool reopen) { +bool KeyValueStorage::process_status(const leveldb::Status &status, bool reopen) +{ if (status.ok()) { return true; } @@ -43,25 +42,29 @@ bool KeyValueStorage::process_status(const leveldb::Status & status, bool reopen if (status.IsCorruption()) { if (++repairs > 2) return false; - errorstream << "Trying to repair database [" << db_name << "] try=" << repairs << " [" << error << "]" << std::endl; + errorstream << "Trying to repair database [" << db_name << "] try=" << repairs + << " [" << error << "]" << std::endl; leveldb::Options options; options.create_if_missing = true; leveldb::Status status_repair; try { status_repair = leveldb::RepairDB(fullpath, options); } catch (const std::exception &e) { - errorstream << "First repair [" << db_name << "] exception [" << e.what() << "]" << std::endl; + errorstream << "First repair [" << db_name << "] exception [" << e.what() + << "]" << std::endl; auto options_repair = options; options_repair.paranoid_checks = true; try { status_repair = leveldb::RepairDB(fullpath, options_repair); } catch (const std::exception &e) { - errorstream << "Second repair [" << db_name << "] exception [" << e.what() << "]" << std::endl; + errorstream << "Second repair [" << db_name << "] exception [" << e.what() + << "]" << std::endl; } } if (!status.ok()) { error = status.ToString(); - errorstream << "Repair [" << db_name << "] fail [" << error << "]" << std::endl; + errorstream << "Repair [" << db_name << "] fail [" << error << "]" + << std::endl; delete db; db = nullptr; return false; @@ -70,7 +73,8 @@ bool KeyValueStorage::process_status(const leveldb::Status & status, bool reopen auto status_open = leveldb::DB::Open(options, fullpath, &db); if (!status_open.ok()) { error = status_open.ToString(); - errorstream << "Trying to reopen database [" << db_name << "] fail [" << error << "]" << std::endl; + errorstream << "Trying to reopen database [" << db_name << "] fail [" + << error << "]" << std::endl; delete db; db = nullptr; return false; @@ -81,19 +85,23 @@ bool KeyValueStorage::process_status(const leveldb::Status & status, bool reopen } #endif -bool KeyValueStorage::open() { +bool KeyValueStorage::open() +{ #if USE_LEVELDB leveldb::Options options; options.create_if_missing = true; auto status = leveldb::DB::Open(options, fullpath, &db); - verbosestream << "KeyValueStorage::open() db_name=" << db_name << " status=" << status.ok() << " error=" << status.ToString() << std::endl; + verbosestream << "KeyValueStorage::open() db_name=" << db_name + << " status=" << status.ok() << " error=" << status.ToString() + << std::endl; return process_status(status, true); #else return true; #endif } -void KeyValueStorage::close() { +void KeyValueStorage::close() +{ repairs = 0; if (!db) return; @@ -101,12 +109,13 @@ void KeyValueStorage::close() { db = nullptr; } -KeyValueStorage::~KeyValueStorage() { - //errorstream<<"KeyValueStorage::~KeyValueStorage() "< lock(mutex); return error; } -bool KeyValueStorage::del(const std::string &key) { +bool KeyValueStorage::del(const std::string &key) +{ if (!db) return false; #if USE_LEVELDB @@ -173,7 +188,8 @@ bool KeyValueStorage::del(const std::string &key) { } #if USE_LEVELDB -leveldb::Iterator* KeyValueStorage::new_iterator() { +leveldb::Iterator *KeyValueStorage::new_iterator() +{ if (!db) return nullptr; return db->NewIterator(read_options); diff --git a/src/key_value_storage.h b/src/key_value_storage.h index 976a66469..d1d903130 100644 --- a/src/key_value_storage.h +++ b/src/key_value_storage.h @@ -15,8 +15,7 @@ along with Freeminer. If not, see . */ -#ifndef KEY_VALUE_STORAGE_H -#define KEY_VALUE_STORAGE_H +#pragma once #include @@ -28,32 +27,34 @@ #include "json/json.h" #include -class KeyValueStorage { +class KeyValueStorage +{ public: KeyValueStorage(const std::string &savedir, const std::string &name); ~KeyValueStorage(); bool open(); void close(); - bool put(const std::string & key, const std::string & data); - bool put(const std::string & key, const float & data); - bool put_json(const std::string & key, const Json::Value & data); - bool get(const std::string & key, std::string &data); - bool get(const std::string & key, float &data); - bool get_json(const std::string & key, Json::Value & data); - bool del(const std::string & key); + bool put(const std::string &key, const std::string &data); + bool put(const std::string &key, const float &data); + bool put_json(const std::string &key, const Json::Value &data); + bool get(const std::string &key, std::string &data); + bool get(const std::string &key, float &data); + bool get_json(const std::string &key, Json::Value &data); + bool del(const std::string &key); std::string get_error(); #if USE_LEVELDB - leveldb::Iterator* new_iterator(); - leveldb::DB *db; + leveldb::Iterator *new_iterator(); + leveldb::DB *db{}; leveldb::ReadOptions read_options; leveldb::WriteOptions write_options; - bool process_status(const leveldb::Status & status, bool reopen = false); + bool process_status(const leveldb::Status &status, bool reopen = false); #else char *db; #endif - unsigned int repairs = 0; + unsigned int repairs {}; std::string error; + private: const std::string db_name; std::string fullpath; @@ -62,5 +63,3 @@ class KeyValueStorage { Json::CharReaderBuilder json_char_reader_builder; std::mutex mutex; }; - -#endif diff --git a/src/map.cpp b/src/map.cpp index 6cb816f6b..dc0d6623e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1983,6 +1983,8 @@ void ServerMap::endSave() bool ServerMap::saveBlock(MapBlock *block) { + changed_blocks_for_merge.emplace(block->getPos()); + return saveBlock(block, dbase, m_map_compression_level); } diff --git a/src/map.h b/src/map.h index 325f3fc2b..b4682e92a 100644 --- a/src/map.h +++ b/src/map.h @@ -427,9 +427,14 @@ class Map : public NodeContainer class ServerMap : public Map { public: -//freeminer: - virtual s16 updateBlockHeat(ServerEnvironment *env, const v3pos_t &p, MapBlock *block = nullptr, unordered_map_v3pos *cache = nullptr, bool block_add = true); - virtual s16 updateBlockHumidity(ServerEnvironment *env, const v3pos_t & p, MapBlock *block = nullptr, unordered_map_v3pos *cache = nullptr, bool block_add = true); + + // freeminer: + virtual s16 updateBlockHeat(ServerEnvironment *env, const v3pos_t &p, + MapBlock *block = nullptr, unordered_map_v3pos *cache = nullptr, + bool block_add = true); + virtual s16 updateBlockHumidity(ServerEnvironment *env, const v3pos_t &p, + MapBlock *block = nullptr, unordered_map_v3pos *cache = nullptr, + bool block_add = true); size_t transforming_liquid_size(); v3pos_t transforming_liquid_pop(); @@ -442,8 +447,8 @@ class ServerMap : public Map // (due to limited data range of basepos.y this will always give a unique // return value as long as minetest is compiled at least on 32bit architecture) //int getSurface(v3s16 basepos, int searchup, bool walkable_only); - virtual int getSurface(const v3pos_t& basepos, int searchup, bool walkable_only); -/* + virtual int getSurface(const v3pos_t &basepos, int searchup, bool walkable_only); + /* { return basepos.Y - 1; } @@ -453,26 +458,28 @@ class ServerMap : public Map std::mutex m_transforming_liquid_mutex; typedef unordered_map_v3pos lighting_map_t; std::mutex m_lighting_modified_mutex; - std::map m_lighting_modified_blocks; + std::map m_lighting_modified_blocks; std::map m_lighting_modified_blocks_range; - void lighting_modified_add(const v3pos_t& pos, int range = 5); + void lighting_modified_add(const v3pos_t &pos, int range = 5); void unspreadLight(enum LightBank bank, std::map &from_nodes, - std::set &light_sources, std::map &modified_blocks); + std::set &light_sources, + std::map &modified_blocks); void spreadLight(enum LightBank bank, std::set &from_nodes, std::map &modified_blocks, uint64_t end_ms); - u32 updateLighting(concurrent_map &a_blocks, - std::map &modified_blocks, unsigned int max_cycle_ms); - u32 updateLighting(lighting_map_t & a_blocks, unordered_map_v3pos & processed, unsigned int max_cycle_ms = 0); - unsigned int updateLightingQueue(unsigned int max_cycle_ms, int & loopcount); - - bool propagateSunlight( - const v3pos_t& pos, std::set &light_sources, bool remove_light = false); + u32 updateLighting(concurrent_map &a_blocks, + std::map &modified_blocks, unsigned int max_cycle_ms); + u32 updateLighting(lighting_map_t &a_blocks, unordered_map_v3pos &processed, + unsigned int max_cycle_ms = 0); + unsigned int updateLightingQueue(unsigned int max_cycle_ms, int &loopcount); - MapBlockP loadBlockNoStore(const v3bpos_t & p3d); + bool propagateSunlight(const v3bpos_t &pos, std::set &light_sources, + bool remove_light = false); -//end of freeminer + MapBlockP loadBlockNoStore(const v3bpos_t &p3d); + concurrent_unordered_set changed_blocks_for_merge; + // == end of freeminer diff --git a/src/server/player_sao.h b/src/server/player_sao.h index 710f83b45..ba707632d 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -24,6 +24,7 @@ along with Freeminer. If not, see . #include #include #include "constants.h" +#include "irr_v3d.h" #include "metadata.h" #include "network/networkprotocol.h" #include "unit_sao.h" @@ -88,7 +89,7 @@ class PlayerSAO : public UnitSAO //fm: void addSpeed(v3f); std::atomic_uint m_ms_from_last_respawn {10000}; //more than ignore move time (1) - v3f m_last_stat_position {}; + v3opos_t m_last_stat_position {}; double last_time_online = 0; diff --git a/src/threading/concurrent_unordered_map.h b/src/threading/concurrent_unordered_map.h index a21b8316b..131198ac0 100644 --- a/src/threading/concurrent_unordered_map.h +++ b/src/threading/concurrent_unordered_map.h @@ -71,6 +71,15 @@ class concurrent_unordered_map_ : public std::unordered_map(args)...); } + const mapped_type &at_or(const key_type &k, const mapped_type ¬hing = {}) const + { + auto lock = LOCKER::lock_shared_rec(); + if (const auto it = full_type::find(k); it != full_type::end()) { + return it->second; + } + return nothing; + } + template decltype(auto) assign(Args &&...args) { diff --git a/src/threading/concurrent_unordered_set.h b/src/threading/concurrent_unordered_set.h index 2e94348e5..040f108ca 100644 --- a/src/threading/concurrent_unordered_set.h +++ b/src/threading/concurrent_unordered_set.h @@ -36,7 +36,7 @@ class concurrent_unordered_set_ : public std::unordered_set - Value &at_or(Args &&...args, const Value ¬hing = {}) + const Value &at_or(Args &&...args, const Value ¬hing = {}) const { auto lock = LOCKER::lock_shared_rec(); if (const auto it = full_type::find(std::forward(args)...);