Merge branch 'wip5.13.0' into wip5.14.0

This commit is contained in:
proller committed 2025-11-15 21:40:34 +01:00
commit af784e500e
50 files changed
+1423 -456

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@
url = https://github.com/msgpack/msgpack-c.git
[submodule "src/external/websocketpp"]
path = src/external/websocketpp
url = https://github.com/zaphoyd/websocketpp.git
url = https://github.com/hanyeol/websocketpp.git
[submodule "src/external/leveldb"]
path = src/external/leveldb
url = https://github.com/google/leveldb
+13 -11
View File
@@ -119,34 +119,36 @@ if(NOT MSVC)
if("${CMAKE_GENERATOR}" STREQUAL "Ninja" )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(OTHER_FLAGS "${OTHER_FLAGS} -fdiagnostics-color")
add_compile_options(-fdiagnostics-color)
elseif ( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8 )
set(OTHER_FLAGS "${OTHER_FLAGS} -fdiagnostics-color=always")
add_compile_options(-fdiagnostics-color=always)
endif ()
endif ()
if(SANITIZE_ADDRESS)
message(STATUS "Build with sanitize=address")
set(OTHER_FLAGS "${OTHER_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(ENABLE_SYSTEM_JSONCPP 0)
add_compile_options(-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
add_link_options(-fsanitize=address)
set(ENABLE_SYSTEM_JSONCPP 0)
endif()
if(SANITIZE_THREAD)
message(STATUS "Build with sanitize=thread")
set(OTHER_FLAGS "${OTHER_FLAGS} -fsanitize=thread -fPIE -fno-omit-frame-pointer -fno-optimize-sibling-calls")
add_compile_options(-fsanitize=thread -fPIE -fno-omit-frame-pointer -fno-optimize-sibling-calls)
add_link_options(-fsanitize=thread -fPIE)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(OTHER_FLAGS "${OTHER_FLAGS} -pie")
add_compile_options(-pie)
endif()
set(ENABLE_SYSTEM_JSONCPP 0)
endif()
if(SANITIZE_MEMORY)
message(STATUS "Build with sanitize=memory")
set(OTHER_FLAGS "${OTHER_FLAGS} -fsanitize=memory -fPIE -fno-omit-frame-pointer -fno-optimize-sibling-calls")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
add_compile_options(-fsanitize=memory -fPIE -fno-omit-frame-pointer -fno-optimize-sibling-calls)
add_link_options(-fsanitize=memory -pie)
set(ENABLE_SYSTEM_JSONCPP 0)
endif()
if(SANITIZE_UNDEFINED)
message(STATUS "Build with sanitize=undefined ")
set(OTHER_FLAGS "${OTHER_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls")
add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls)
add_link_options(-fsanitize=undefined)
set(ENABLE_SYSTEM_JSONCPP 0)
endif()
@@ -182,7 +184,7 @@ if(NOT MSVC)
if (TCMALLOC_LIBRARY)
set(PLATFORM_LIBS ${PLATFORM_LIBS} ${TCMALLOC_LIBRARY})
set(OTHER_FLAGS "${OTHER_FLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free")
add_compile_options(-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free)
endif()
message(STATUS "Build with tcmalloc ${TCMALLOC_LIBRARY} ${PROFILER_LIBRARY}")
+23 -2
View File
@@ -175,8 +175,7 @@ if (USE_DEBUG_DUMP)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDUMP_STREAM=actionstream)
else()
#add_definitions(-DDUMP_STREAM=verbosestream)
add_definitions(-DDUMP_STREAM=actionstream)
add_definitions(-DDUMP_STREAM=verbosestream)
endif()
endif ()
@@ -200,4 +199,26 @@ set(FMcommon_SRCS ${FMcommon_SRCS}
fm_clientiface.cpp
fm_serverenvironment.cpp
)
set(FREEMINER_CLIENT_LIBRARIES
${MSGPACK_LIBRARY}
${ENET_LIBRARY}
${SCTP_LIBRARY}
${WEBSOCKETPP_LIBRARY}
${TIFF_LIRARY}
${OSMIUM_LIRARY}
)
find_package(PNG REQUIRED)
set(FREEMINER_SERVER_LIBRARIES
${MSGPACK_LIBRARY}
${ENET_LIBRARY}
${SCTP_LIBRARY}
${WEBSOCKETPP_LIBRARY}
${TIFF_LIRARY}
${OSMIUM_LIRARY}
${PNG_LIBRARY}
)
# == end freeminer:
+3 -12
View File
@@ -607,6 +607,7 @@ include_directories(SYSTEM
#freeminer includes:
include_directories(
${MSGPACK_INCLUDE_DIR}
${PNG_INCLUDE_DIR}
)
if(USE_GETTEXT)
@@ -732,12 +733,7 @@ if(BUILD_CLIENT)
${GMP_LIBRARY}
${JSON_LIBRARY}
${MSGPACK_LIBRARY}
${ENET_LIBRARY}
${SCTP_LIBRARY}
${WEBSOCKETPP_LIBRARY}
${TIFF_LIRARY}
${OSMIUM_LIRARY}
${FREEMINER_CLIENT_LIBRARIES}
${LUA_BIT_LIBRARY}
sha256
@@ -835,12 +831,7 @@ if(BUILD_SERVER)
${ZSTD_LIBRARY}
${JSON_LIBRARY}
${MSGPACK_LIBRARY}
${ENET_LIBRARY}
${SCTP_LIBRARY}
${WEBSOCKETPP_LIBRARY}
${TIFF_LIRARY}
${OSMIUM_LIRARY}
${FREEMINER_SERVER_LIBRARIES}
${LUA_LIBRARY}
${LUA_BIT_LIBRARY}
+5
View File
@@ -368,6 +368,7 @@ void Client::Stop()
// TODO: correct order:
mesh_thread_pool.wait_until_empty();
farmesh_async.wait();
mesh_thread_pool.wait_until_nothing_in_flight();
mesh_thread_pool.wait_until_empty();
farmesh.reset();
farmesh_async.wait();
@@ -396,6 +397,7 @@ Client::~Client()
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
mesh_thread_pool.wait_until_nothing_in_flight();
mesh_thread_pool.wait_until_empty(); // before ~ClientMap()
deleteAuthData();
@@ -407,6 +409,9 @@ Client::~Client()
updateDrawList_async.wait();
update_shadows_async.wait();
mesh_thread_pool.wait_until_nothing_in_flight();
mesh_thread_pool.wait_until_empty(); // before ~ClientMap()
/*
MeshUpdateResult r;
while (m_mesh_update_manager->getNextResult(r)) {
+4 -1
View File
@@ -1388,11 +1388,14 @@ static u32 transformBuffersToDrawOrder(
new_buffer = true;
else if (tmp->getVertexCount() + buf->getVertexCount() > U16_MAX)
new_buffer = true;
else if (tmp->getPrimitiveType() != buf->getPrimitiveType())
new_buffer = true;
if (new_buffer) {
finish_buf();
tmp = new scene::SMeshBuffer();
tmp->setPrimitiveType(buf->getPrimitiveType());
put_buffers.buf.push_back(tmp);
assert(tmp->getPrimitiveType() == buf->getPrimitiveType());
//assert(tmp->getPrimitiveType() == buf->getPrimitiveType());
tmp->Material = buf->getMaterial();
// preallocate approximately
tmp->Vertices->Data.reserve(MYMIN(U16_MAX, total_vtx));
+48 -35
View File
@@ -3,22 +3,26 @@
#include <future>
#include <memory>
#include "client.h"
#include "fm_far_calc.h"
#include "client/mapblock_mesh.h"
#include "clientmap.h"
#include "emerge.h"
#include "filesys.h"
#include "fm_far_calc.h"
#include "fm_weather.h"
#include "fm_world_merge.h"
#include "irr_v3d.h"
#include "log.h"
#include "mapblock.h"
#include "network/fm_networkprotocol.h"
#include "server.h"
#include "filesys.h"
#include "map.h"
#include "mapblock.h"
#include "mapgen/mapgen.h"
#include "network/fm_networkprotocol.h"
#include "network/networkpacket.h"
#include "server.h"
#include "threading/lock.h"
#include "util/directiontables.h"
#include <atomic>
#include <exception>
#include <memory>
void Client::updateMeshTimestampWithEdge(const v3bpos_t &blockpos)
{
@@ -135,6 +139,11 @@ void Client::MakeEmerge(const Settings &settings, const MapgenType &mgtype)
try {
m_localserver = std::make_unique<Server>(
"farmesh", findSubgame(game), false, Address{}, true);
// auto m_env = new ServerEnvironment({}, //std::move(startup_server_map),
// m_localserver.get(), &m_metrics_backend // m_metrics_backend.get()
// );
// m_localserver->m_env = m_env;
break;
} catch (const std::exception &ex) {
errorstream << "Failed to make local mapgen server with game " << game
@@ -151,6 +160,7 @@ void Client::MakeEmerge(const Settings &settings, const MapgenType &mgtype)
g_settings->set("num_emerge_threads", "1");
m_emerge = std::make_unique<EmergeManager>(
m_localserver.get(), m_localserver->m_metrics_backend.get());
// m_emerge->env = &m_localserver->getEnv();
m_emerge->initMapgens(m_mapgen_params.get());
g_settings->set("num_emerge_threads", num_emerge_threads);
}
@@ -203,39 +213,42 @@ void Client::handleCommand_BlockDataFm(NetworkPacket *pkt)
if (!block)
block = m_env.getMap().createBlankBlock(bpos);
}
const auto lock = block->lock_unique_rec();
block->far_step = step;
content_t content_only{};
packet.convert_safe(TOCLIENT_BLOCKDATA_CONTENT_ONLY, content_only);
block->content_only = content_only;
packet.convert_safe(
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM1, block->content_only_param1);
packet.convert_safe(
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM2, block->content_only_param2);
{
const auto lock = block->lock_unique_rec();
block->far_step = step;
content_t content_only{};
packet.convert_safe(TOCLIENT_BLOCKDATA_CONTENT_ONLY, content_only);
block->content_only = content_only;
packet.convert_safe(
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM1, block->content_only_param1);
packet.convert_safe(
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM2, block->content_only_param2);
if (block->content_only == CONTENT_IGNORE) {
try {
block->deSerialize(istr, m_server_ser_ver, false);
} catch (const std::exception &ex) {
errorstream << "fm block deSerialize fail " << bpos << " " << block->far_step
<< " : " << ex.what() << " : " << pkt->getSize() << " "
<< packet.size() << " v=" << (short)m_server_ser_ver << "\n";
if (block->content_only == CONTENT_IGNORE) {
try {
block->deSerialize(istr, m_server_ser_ver, false);
} catch (const std::exception &ex) {
errorstream << "fm block deSerialize fail " << bpos << " "
<< block->far_step << " : " << ex.what() << " : "
<< pkt->getSize() << " " << packet.size()
<< " v=" << (short)m_server_ser_ver << "\n";
#if !NDEBUG
errorstream << "bad data " << istr.str().size() << " : " << istr.str()
<< "\n";
errorstream << "bad data " << istr.str().size() << " : " << istr.str()
<< "\n";
#endif
return;
return;
}
} else {
block->fill({block->content_only, block->content_only_param1,
block->content_only_param2});
}
} else {
block->fill({block->content_only, block->content_only_param1,
block->content_only_param2});
weather::heat_t heat = 0; // for convert to atomic
packet[TOCLIENT_BLOCKDATA_HEAT].convert(heat);
block->heat = heat;
weather::humidity_t humidity = 0;
packet[TOCLIENT_BLOCKDATA_HUMIDITY].convert(humidity);
block->humidity = humidity;
}
s32 h = 0; // for convert to atomic
packet[TOCLIENT_BLOCKDATA_HEAT].convert(h);
block->heat = h;
h = 0;
packet[TOCLIENT_BLOCKDATA_HUMIDITY].convert(h);
block->humidity = h;
if (m_localdb && !is_simple_singleplayer_game) {
if (const auto db = GetFarDatabase({}, far_dbases, m_world_path, step); db) {
@@ -253,7 +266,7 @@ void Client::handleCommand_BlockDataFm(NetworkPacket *pkt)
block->content_only != CONTENT_AIR) {
if (getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS))
.getDistanceFrom(bpos) <= 1)
addUpdateMeshTaskWithEdge(bpos);
addUpdateMeshTaskWithEdge(bpos);
}
} else {
static thread_local const auto settings_farmesh_server =
@@ -290,7 +303,7 @@ void Client::handleCommand_BlockDataFm(NetworkPacket *pkt)
}
createFarMesh(block);
auto &far_blocks = client_map.m_far_blocks;
const auto lock = far_blocks.lock_unique_rec();
if (const auto &it = far_blocks.find(bpos); it != far_blocks.end()) {
if (it->second->far_step != block->far_step) {
+1 -1
View File
@@ -934,7 +934,7 @@ void Hud::drawBlockBounds()
u16 mesh_chunk_size = std::max<u16>(1, g_settings->getU16("client_mesh_chunk"));
v3s16 pos = player->getStandingNodePos();
// 3s16 pos = player->getStandingNodePos();
if (m_block_bounds_mode == BLOCK_BOUNDS_FAR_DRAWN) {
const auto offset = intToFloat(client->getCamera()->getOffset(), BS);
+53 -2
View File
@@ -4,6 +4,7 @@
#include "mapblock_mesh.h"
#include "CMeshBuffer.h"
#include "EPrimitiveTypes.h"
#include "client.h"
#include "client/clientmap.h"
#include "mapblock.h"
@@ -32,7 +33,8 @@
MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
u16 side_length, MeshGrid mesh_grid
, int lod_step, int far_step,
, int lod_step
, int far_step,
NodeContainer *nodecontainer) :
m_side_length(side_length >> lod_step),
m_mesh_grid(mesh_grid),
@@ -42,7 +44,7 @@ MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
side_length_data{side_length},
lod_step{lod_step},
far_step{far_step},
fscale(1<<(far_step + lod_step))
fscale(1 << (far_step + lod_step))
{
assert(m_side_length > 0);
}
@@ -742,6 +744,55 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
buf->drop();
}
if (static const auto farlights = g_settings->getBool("farlights"); farlights && far_step) {
scene::SMeshBuffer *buffer = new scene::SMeshBuffer();
buffer->PrimitiveType = scene::EPT_POINTS;
buffer->Material.PointCloud = true;
buffer->Material.BackfaceCulling = false;
buffer->Material.FogEnable = true;
v3bpos_t ofs;
const auto &storage =
client->getEnv().getClientMap().far_blocks_storage[far_step];
int index_i = 0;
for (ofs.Z = 0; ofs.Z < mesh_grid.cell_size; ofs.Z++) {
for (ofs.Y = 0; ofs.Y < mesh_grid.cell_size; ofs.Y++) {
for (ofs.X = 0; ofs.X < mesh_grid.cell_size; ofs.X++) {
v3bpos_t p = (bp + ofs); // * MAP_BLOCKSIZE;
const auto block = storage.get(p).block;
if (!block)
continue;
if (block->m_light_points.empty())
continue;
const auto bpos_rel = block->getPosRelative();
for (const auto &lp : block->m_light_points) {
if (++index_i > 16000)
break;
float r{200};
float g{230};
float b{static_cast<float>(16 * lp.second)};
const auto color_far_scale = far_step / 3.0f;
if (!color_far_scale) {
continue;
}
r /= color_far_scale;
g /= color_far_scale;
b /= color_far_scale;
const video::SColor c(0 / fscale, r, g, b);
const auto lpos_rel = lp.first - bpos_rel;
const auto coord = posToFloat(lpos_rel, BS);
video::S3DVertex v(coord.X, coord.Y, coord.Z, 0.0f, 0.0f,
1.0f, c, 0.0f, 0.0f);
buffer->Vertices->Data.emplace_back(v);
buffer->Indices->Data.emplace_back(index_i);
}
}
}
}
mesh->addMeshBuffer(buffer);
buffer->drop();
}
if (mesh) {
// Use VBO for mesh (this just would set this for every buffer)
mesh->setHardwareMappingHint(scene::EHM_STATIC);
+1 -2
View File
@@ -252,8 +252,7 @@ public:
m_animation_force_timer--;
}
// fm:
// fm:
/*u32 getUsageTimer() {
return m_usage_timer;
}
+2 -2
View File
@@ -36,7 +36,7 @@ void FpsControl::reset()
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime)
{
const float fps_limit = device->isWindowFocused()
static thread_local const float fps_limit = device->isWindowFocused()
? g_settings->getFloat("fps_max")
: g_settings->getFloat("fps_max_unfocused");
const u64 frametime_min = 1000000.0f / std::max(fps_limit, 1.0f);
@@ -312,7 +312,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
driver->setFog(RenderingEngine::MENU_SKY_COLOR);
driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR);
if (g_settings->getBool("menu_clouds")) {
if (static thread_local const auto menu_clouds = g_settings->getBool("menu_clouds"); menu_clouds) {
g_menuclouds->step(dtime * 3);
g_menucloudsmgr->drawAll();
}
+1 -1
View File
@@ -23,7 +23,7 @@
#define PEER_MINETEST_MIN 2
#define PEER_MINETEST_MAX 9999
#define PEER_WS_MIN 10002
#define PEER_WS_MAX 19999
#define PEER_WS_MAX 0x3fff-1 // MAX_UDP_PEERS
#define PEER_ENET_MIN 20002
#define PEER_ENET_MAX 29999
#define PEER_SCTP_MIN 30002
+2 -1
View File
@@ -158,6 +158,7 @@ void fm_set_default_settings(Settings *settings) {
settings->setDefault("farmesh_stable", "0");
settings->setDefault("farmesh_server", "1");
settings->setDefault("farmesh_all_changed", slow ? "1000" : "10000");
settings->setDefault("farlights", "1");
settings->setDefault("headless_optimize", "false");
//settings->setDefault("node_highlighting", "halo");
@@ -245,7 +246,7 @@ void fm_set_default_settings(Settings *settings) {
settings->setDefault("emergequeue_limit_diskonly", ""); // autodetect from number of cpus
settings->setDefault("emergequeue_limit_generate", ""); // autodetect from number of cpus
settings->setDefault("emergequeue_limit_total", ""); // autodetect from number of cpus
// settings->setDefault("num_emerge_threads", ""); // "1" // Fix and enable auto
settings->setDefault("num_emerge_threads", ""); // "1" // Fix and enable auto
settings->setDefault("server_map_save_interval", "300"); // "5.3"
settings->setDefault("sqlite_synchronous", "1"); // "2"
settings->setDefault("save_generated_block", "true");
+3 -3
View File
@@ -642,7 +642,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
m_map->finishBlockMake(bmdata, modified_blocks,
m_server->m_env->getGameTime());
MapBlock *block = m_map->getBlockNoCreateNoEx(pos, false, true);
MapBlockPtr block = m_map->getBlock(pos, false, true);
if (!block) {
errorstream << "EmergeThread::finishGen: Couldn't grab block we "
"just generated: " << pos << std::endl;
@@ -671,7 +671,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
m_server->setAsyncFatalError(e);
}
EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
EMERGE_DBG_OUT("ended up with: " << analyze_block(block.get()));
/*
Clear mapgen state
@@ -680,7 +680,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
m_mapgen->gennotify.clearEvents();
// m_mapgen->vm = nullptr;
return block;
return block.get();
}
+7 -4
View File
@@ -21,6 +21,7 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#include "fm_far_calc.h"
#include <cstdint>
#include <optional>
#include "client/clientmap.h"
#include "irr_v3d.h"
@@ -45,7 +46,7 @@ block_step_t getLodStep(const MapDrawControl &draw_control,
// return i;
// }
/*
/*
if (range >= cells + draw_control.lodmesh * 64) // cell_size = 4
return 8;
if (range >= cells + draw_control.lodmesh * 32)
@@ -255,9 +256,10 @@ block_step_t getFarStep(const MapDrawControl &draw_control, const v3bpos_t &ppos
}
v3bpos_t getFarActual(const v3bpos_t &blockpos, const v3bpos_t &ppos, block_step_t step,
const MapDrawControl &draw_control)
const MapDrawControl &draw_control, const std::optional<uint8_t> &cell_size_pow)
{
const auto blockpos_aligned_cell = align_shift(blockpos, draw_control.cell_size_pow);
const auto blockpos_aligned_cell =
align_shift(blockpos, cell_size_pow.value_or(draw_control.cell_size_pow));
const auto start =
child_t{.pos = v3tpos_t((((tpos_t)ppos.X >> tree_align) << tree_align) -
(tree_align_size >> 1),
@@ -268,7 +270,8 @@ v3bpos_t getFarActual(const v3bpos_t &blockpos, const v3bpos_t &ppos, block_step
.size = tree_size};
const auto res = find(
{blockpos_aligned_cell.X, blockpos_aligned_cell.Y, blockpos_aligned_cell.Z},
{ppos.X, ppos.Y, ppos.Z}, start, draw_control.cell_size_pow,
{ppos.X, ppos.Y, ppos.Z}, start,
cell_size_pow.value_or(draw_control.cell_size_pow),
draw_control.farmesh_quality);
if (res) {
+5 -4
View File
@@ -21,6 +21,7 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <optional>
#include "irr_v3d.h"
#include "irrlichttypes.h"
@@ -52,9 +53,9 @@ block_step_t getFarStepBad(const MapDrawControl &draw_control,
bool inFarGrid(const v3bpos_t &blockpos, const v3bpos_t &playerblockpos,
block_step_t step, const MapDrawControl &draw_control);
v3bpos_t getFarActual(const v3bpos_t &blockpos, const v3bpos_t &playerblockpos,
block_step_t step, const MapDrawControl &draw_control);
block_step_t step, const MapDrawControl &draw_control,
const std::optional<uint8_t> &cell_size_pow = {});
v3bpos_t playerBlockAlign(
const MapDrawControl &draw_control, const v3bpos_t &playerblockpos);
void runFarAll(const v3bpos_t &ppos,
uint8_t cell_size_pow, uint8_t farmesh_quality, pos_t two_d,
const std::function<bool(const v3bpos_t &, const bpos_t &)> &func);
void runFarAll(const v3bpos_t &ppos, uint8_t cell_size_pow, uint8_t farmesh_quality,
pos_t two_d, const std::function<bool(const v3bpos_t &, const bpos_t &)> &func);
+26 -18
View File
@@ -47,7 +47,7 @@ thread_local v3bpos_t block_cache_p;
}
#endif
std::atomic_uint ServerMap::time_life {};
std::atomic_uint ServerMap::time_life{};
// TODO: REMOVE THIS func and use Map::getBlock
MapBlockPtr Map::getBlock(v3bpos_t p, bool trylock, bool nocache)
@@ -77,7 +77,8 @@ MapBlockPtr Map::getBlock(v3bpos_t p, bool trylock, bool nocache)
MapBlockPtr block;
{
const auto lock = trylock ? m_blocks.try_lock_shared_rec() : m_blocks.lock_shared_rec();
const auto lock =
trylock ? m_blocks.try_lock_shared_rec() : m_blocks.lock_shared_rec();
if (!lock->owns_lock())
return nullptr;
const auto &n = m_blocks.find(p);
@@ -238,7 +239,7 @@ MapNode Map::getNodeNoLock(v3POS p) //dont use
}
*/
s16 Map::getHeat(const v3pos_t &p, bool no_random)
s16 Map::getHeat(const v3bpos_t &p, bool no_random)
{
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if (block != NULL) {
@@ -249,7 +250,7 @@ s16 Map::getHeat(const v3pos_t &p, bool no_random)
return 0;
}
s16 Map::getHumidity(const v3pos_t &p, bool no_random)
s16 Map::getHumidity(const v3bpos_t &p, bool no_random)
{
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
if (block != NULL) {
@@ -260,8 +261,8 @@ s16 Map::getHumidity(const v3pos_t &p, bool no_random)
return 0;
}
ServerMap::heat_t ServerMap::updateBlockHeat(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block, unordered_map_v3pos<ServerMap::heat_t> *cache, bool block_add)
weather::heat_t ServerMap::updateBlockHeat(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block, unordered_map_v3bpos<weather::heat_t> *cache, bool block_add)
{
const auto bp = getNodeBlockPos(p);
const auto gametime = env->getGameTime();
@@ -274,8 +275,10 @@ ServerMap::heat_t ServerMap::updateBlockHeat(ServerEnvironment *env, const v3pos
if (cache && cache->contains(bp)) {
return cache->at(bp); // + myrand_range(0, 1);
}
auto value = m_emerge->biomemgr->calcBlockHeat(p, getSeed(), env->getTimeOfDayF(),
gametime * env->m_time_of_day_speed, env->m_use_weather);
auto value =
m_emerge->getFirstMapgen()->calcBlockHeat(p, getSeed(), env->getTimeOfDayF(),
gametime * env->m_time_of_day_speed, env->m_use_weather);
//auto value = m_emerge->biomemgr->calcBlockHeat(p, getSeed(), env->getTimeOfDayF(), gametime * env->m_time_of_day_speed, env->m_use_weather);
if (!block) {
block = getBlockNoCreateNoEx(bp); //, true);
@@ -283,7 +286,7 @@ ServerMap::heat_t ServerMap::updateBlockHeat(ServerEnvironment *env, const v3pos
{
int8_t blocks_around = 0;
heat_t sum = 0;
weather::heat_t sum = 0;
for (const auto &dir : g_6dirs) {
if (auto nblock = getBlockNoCreateNoEx(bp + dir, true)) {
sum += nblock->humidity;
@@ -313,9 +316,9 @@ ServerMap::heat_t ServerMap::updateBlockHeat(ServerEnvironment *env, const v3pos
return value; // + myrand_range(0, 1);
}
ServerMap::humidity_t ServerMap::updateBlockHumidity(ServerEnvironment *env,
weather::humidity_t ServerMap::updateBlockHumidity(ServerEnvironment *env,
const v3pos_t &p, MapBlock *block,
unordered_map_v3pos<ServerMap::humidity_t> *cache, bool block_add)
unordered_map_v3bpos<weather::humidity_t> *cache, bool block_add)
{
const auto bp = getNodeBlockPos(p);
const auto gametime = env->getGameTime();
@@ -328,8 +331,11 @@ ServerMap::humidity_t ServerMap::updateBlockHumidity(ServerEnvironment *env,
if (cache && cache->count(bp)) {
return cache->at(bp) + myrand_range(0, 1);
}
auto value = m_emerge->biomemgr->calcBlockHumidity(p, getSeed(), env->getTimeOfDayF(),
gametime * env->m_time_of_day_speed, env->m_use_weather);
auto value =
m_emerge->getFirstMapgen()->calcBlockHumidity(p, getSeed(), env->getTimeOfDayF(),
gametime * env->m_time_of_day_speed, env->m_use_weather);
//auto value = m_emerge->biomemgr->calcBlockHumidity(p, getSeed(), env->getTimeOfDayF(),gametime * env->m_time_of_day_speed, env->m_use_weather);
if (!block) {
block = getBlockNoCreateNoEx(bp); //, true);
@@ -337,7 +343,7 @@ ServerMap::humidity_t ServerMap::updateBlockHumidity(ServerEnvironment *env,
{
int8_t blocks_around = 0;
humidity_t sum = 0;
weather::humidity_t sum = 0;
for (const auto &dir : g_6dirs) {
if (auto nblock = getBlockNoCreateNoEx(bp + dir, true)) {
sum += nblock->humidity;
@@ -369,7 +375,7 @@ ServerMap::humidity_t ServerMap::updateBlockHumidity(ServerEnvironment *env,
int ServerMap::getSurface(const v3pos_t &basepos, int searchup, bool walkable_only)
{
s16 max = MYMIN(searchup + basepos.Y, 0x7FFF);
pos_t max = MYMIN(searchup + basepos.Y, 0x7FFF);
MapNode last_node = getNode(basepos);
MapNode node = last_node;
@@ -507,6 +513,8 @@ u32 Map::timerUpdate(float uptime, float unload_timeout, s32 max_loaded_blocks,
}
if (block->getUsageTimer() > unload_timeout) { // block->refGet() <= 0 &&
const v3bpos_t p = block->getPos();
changed_blocks_for_merge.emplace(p);
// infostream<<" deleting block p="<<p<<"
// ustimer="<<block->getUsageTimer() <<" to="<< unload_timeout<<"
// inc="<<(uptime - block->m_uptime_timer_last)<<"
@@ -1323,7 +1331,7 @@ bool ServerMap::propagateSunlight(
}
//#endif
void ServerMap::lighting_modified_add(const v3pos_t &pos, int range)
void ServerMap::lighting_modified_add(const v3bpos_t &pos, int range)
{
MutexAutoLock lock(m_lighting_modified_mutex);
if (m_lighting_modified_blocks.contains(pos)) {
@@ -1408,7 +1416,7 @@ MapNode Map::getNodeNoEx(v3pos_t p) {
* Get the ground level by searching for a non CONTENT_AIR node in a column from top to
* bottom
*/
s16 ServerMap::findGroundLevel(v2pos_t p2d, bool cacheBlocks)
pos_t ServerMap::findGroundLevel(v2pos_t p2d, bool cacheBlocks)
{
pos_t level;
@@ -1640,7 +1648,7 @@ s32 ServerMap::save(ModifiedState save_level, float dedicated_server_step, bool
//modprofiler.add(block->getModifiedReasonString(), 1);
const auto lock = breakable ? block->try_lock_unique_rec()
: block->lock_unique_rec();
: block->lock_unique_rec();
if (!lock->owns_lock())
continue;
+5 -3
View File
@@ -30,6 +30,7 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#include "database/database.h"
#include "emerge.h"
#include "filesys.h"
#include "fm_weather.h"
#include "irrlichttypes.h"
#include "porting.h"
#include "fm_world_merge.h"
@@ -698,8 +699,8 @@ void Server::SendBlockFm(session_t peer_id, MapBlockPtr block, u8 ver,
block->serializeNetworkSpecific(os);
PACK(TOCLIENT_BLOCKDATA_DATA, os.str());
PACK(TOCLIENT_BLOCKDATA_HEAT, (s16)(block->heat + block->heat_add));
PACK(TOCLIENT_BLOCKDATA_HUMIDITY, (s16)(block->humidity + block->humidity_add));
PACK(TOCLIENT_BLOCKDATA_HEAT, (weather::heat_t)(block->heat + block->heat_add));
PACK(TOCLIENT_BLOCKDATA_HUMIDITY, (weather::humidity_t)(block->humidity + block->humidity_add));
PACK(TOCLIENT_BLOCKDATA_STEP, block->far_step);
PACK(TOCLIENT_BLOCKDATA_CONTENT_ONLY,
block->content_only.load(std::memory_order_relaxed));
@@ -755,7 +756,7 @@ void *WorldMergeThread::run()
.ndef{m_server->getNodeDefManager()},
.smap{m_server->getEnv().m_map.get()},
.far_dbases{m_server->far_dbases},
.dbase{m_server->getEnv().m_map->m_db.dbase, [](MapDatabase*){}},
.dbase{m_server->getEnv().m_map->m_db.dbase, [](MapDatabase *) {}},
.save_dir{m_server->getEnv().m_map->m_savedir},
};
@@ -764,6 +765,7 @@ void *WorldMergeThread::run()
merger.world_merge_max_clients = m_server->isSingleplayer() ? 1 : 0;
g_settings->getU32NoEx("world_merge_max_clients", merger.world_merge_max_clients);
g_settings->getU32NoEx("world_merge_lazy_up", merger.lazy_up);
g_settings->getBoolNoEx("farlights", merger.farlights);
{
merger.world_merge_load_all = -1;
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <cstdint>
namespace weather
{
using humidity_t = int16_t;
using heat_t = int16_t;
}
+69 -17
View File
@@ -66,8 +66,8 @@ WorldMerger::~WorldMerger()
merge_changed();
}
void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
const v3bpos_t &bpos_aligned, block_step_t step)
WorldMerger::one_block_stat_t WorldMerger::merge_one_block(MapDatabase *dbase,
MapDatabase *dbase_up, const v3bpos_t &bpos_aligned, block_step_t step)
{
const auto step_pow = 1;
const auto step_size = 1 << step_pow;
@@ -80,9 +80,18 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
const v3pos_t rpos(x, y, z);
const v3bpos_t nbpos(bpos_aligned.X + (x << step),
bpos_aligned.Y + (y << step), bpos_aligned.Z + (z << step));
auto nblock = load_block(smap, dbase, nbpos);
MapBlockPtr nblock;
if (!step) {
const auto block = smap->getBlock(nbpos);
if (block && block->isGenerated()) {
nblock = block;
}
}
if (!nblock) {
continue;
nblock = load_block(smap, dbase, nbpos);
if (!nblock || !nblock->isGenerated()) {
continue;
}
}
if (const auto ts = nblock->getActualTimestamp(); ts > timestamp)
timestamp = ts;
@@ -102,7 +111,7 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
// actionstream << "s=" << step <<" at=" << block_up->getActualTimestamp() << " t=" << block_up->getTimestamp() << " myts=" << timestamp << "\n";
const auto up_ts = block_up->getActualTimestamp();
if (timestamp < up_ts + lazy_up) {
return;
return {};
}
}
}
@@ -136,7 +145,7 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
std::vector<uint8_t> top_light_night;
std::unordered_map<content_t, MapNode> nodes;
// TODO: tune block selector
// TODO: tune block selector
#if 0
// Simple grid aligned
@@ -156,7 +165,8 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
v3pos_t{1, 0, 1},
v3pos_t{1, 1, 1},
}) {
const auto &n = block->getNodeNoLock(lpos + dir);
const auto p = lpos + dir;
const auto &n = block->getNodeNoLock(p);
const auto c = n.getContent();
if (c == CONTENT_IGNORE) {
continue;
@@ -174,11 +184,20 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
top_c[c] += 4;
}
if (const auto light_night = n.getLightRaw(
LIGHTBANK_NIGHT, ndef->getLightingFlags(n));
const auto &lf = ndef->getLightingFlags(c);
const auto &cf = ndef->get(c);
if (const auto light_night = n.getLightRaw(LIGHTBANK_NIGHT, lf);
light_night) {
top_light_night.emplace_back(light_night);
}
// TODO: whats with lava?
if (farlights && !step && (lf.light_source) && !cf.isLiquid()) {
const auto plpos =
block->getPosRelative() + p; //pos_in_block;
const auto &[i, r] = block->m_light_points.try_emplace(
plpos, lf.light_source);
}
nodes[c] = n;
}
@@ -210,12 +229,42 @@ void WorldMerger::merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
}
}
// TODO: skip full air;
if (!not_empty_nodes) {
return;
one_block_stat_t one_step_stat;
if (farlights) {
constexpr auto some_magick_thinner_const = 1; // more -> less far ligts
constexpr auto min_no_skip_ligts =
2; // do not skip this amount lights on block << farstep
for (const auto &[bpos, block] : blocks) {
if (!block) {
continue;
}
size_t lights_in_block = 0;
// TODO: apply some smart? filtering here
// block_up->m_light_points.insert(block->m_light_points.begin(), block->m_light_points.end());
const auto size = block->m_light_points.size();
if (!size)
continue;
const auto coef = 16.0 / size;
for (const auto &lp : block->m_light_points) {
++one_step_stat.lights_count;
++lights_in_block;
const auto mod = int(coef * some_magick_thinner_const * (16 - lp.second));
if (mod && (step > 1 || lights_in_block > (min_no_skip_ligts << step)) &&
(one_step_stat.lights_count % mod)) {
continue;
}
++one_step_stat.lights_used;
block_up->m_light_points.emplace(lp);
}
}
}
block_up->setGenerated(true);
ServerMap::saveBlock(block_up.get(), dbase_up, m_map_compression_level);
if (not_empty_nodes) {
block_up->setGenerated(true);
ServerMap::saveBlock(block_up.get(), dbase_up, m_map_compression_level);
}
return one_step_stat;
}
bool WorldMerger::merge_one_step(
@@ -254,7 +303,7 @@ bool WorldMerger::merge_one_step(
size_t processed = 0;
const auto time_start = porting::getTimeMs();
WorldMerger::one_block_stat_t stat_step;
const auto printstat = [&]() {
const auto time = porting::getTimeMs();
@@ -264,6 +313,7 @@ bool WorldMerger::merge_one_step(
<< blocks_size
//<< " blocks loaded " << m_server->getMap().m_blocks.size()
<< " processed " << processed << " per " << (time - time_start) / 1000
<< " lights " << stat_step.lights_used << "/" << stat_step.lights_count
<< " speed " << processed / (((time - time_start) / 1000) ?: 1)
<< '\n';
};
@@ -291,8 +341,10 @@ bool WorldMerger::merge_one_step(
g_profiler->add("Server: World merge blocks", 1);
try {
merge_one_block(dbase_current, dbase_up, bpos_aligned, step);
const auto stat_block =
merge_one_block(dbase_current, dbase_up, bpos_aligned, step);
stat_step.lights_count += stat_block.lights_count;
stat_step.lights_used += stat_block.lights_used;
if (!(cur_n % 10000)) {
printstat();
+8 -2
View File
@@ -40,6 +40,7 @@ public:
uint32_t world_merge_throttle{};
uint32_t world_merge_max_clients{};
int16_t world_merge_load_all{}; // -1 : auto; 0 : disable; 1 : force
bool farlights{true};
bool partial{};
uint32_t lazy_up{};
const NodeDefManager *const ndef{};
@@ -55,9 +56,14 @@ public:
bool stop();
bool throttle();
void merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
const v3bpos_t &bpos_aligned, block_step_t step);
struct one_block_stat_t
{
size_t lights_count{};
size_t lights_used{};
};
one_block_stat_t merge_one_block(MapDatabase *dbase, MapDatabase *dbase_up,
const v3bpos_t &bpos_aligned, block_step_t step);
bool merge_one_step(block_step_t step, std::unordered_set<v3bpos_t> &blocks_todo);
bool merge_list(std::unordered_set<v3bpos_t> &blocks_todo);
bool merge_all();
+34
View File
@@ -19,6 +19,7 @@
#include "content_mapnode.h" // For legacy name-id mapping
#include "content_nodemeta.h" // For legacy deserialization
#include "serialization.h"
#include "util/msgpack_serialize.h"
#if CHECK_CLIENT_BUILD()
#include "client/mapblock_mesh.h"
#endif
@@ -248,6 +249,12 @@ MapNode MapBlock::getNodeTry(const v3pos_t &p)
return getNodeNoLock(p);
}
constexpr auto MAPBLOCK_DATA{0};
enum
{
MAPBLOCK_LIGHT_POINTS
};
// ==
/*
@@ -622,7 +629,12 @@ void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int
infostream<<" serialize not generated block"<<std::endl;
}
// freeminer
if(!m_light_points.empty()) {
flags |= (1 << 7);
}
const auto lock = lock_shared_rec();
// =========
writeU8(os, flags);
if (version >= 27) {
@@ -710,6 +722,14 @@ void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int
}
}
// freeminer
if (flags & (1 << 7)) {
MSGPACK_PACKET_INIT((int)MAPBLOCK_DATA, 1);
PACK(MAPBLOCK_LIGHT_POINTS, m_light_points);
os_raw << serializeString32(std::string_view{buffer.data(), buffer.size()});
}
// =========
if (version >= 29) {
// now compress the whole thing
compress(os_raw.str(), os_compressed, version, compression_level);
@@ -893,6 +913,20 @@ bool MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
analyzeContent();
}
if (flags & (1 << 7)) {
std::string data = deSerializeString32(is);
if (!data.empty()) {
msgpack::unpacked msg;
msgpack::unpack(msg, data.data(), data.size());
auto &obj = msg.get();
auto packet = obj.as<MsgpackPacket>();
const auto it = packet.find(MAPBLOCK_LIGHT_POINTS);
if (it != packet.end()) {
it->second.convert(m_light_points);
}
}
}
TRACESTREAM(<<"MapBlock::deSerialize "<<getPos()
<<": Done."<<std::endl);
return true;
+4
View File
@@ -7,6 +7,8 @@
#include "config.h"
#include <atomic>
#include <cstdint>
#include <unordered_map>
#include <vector>
#include "fm_nodecontainer.h"
#include "irr_v3d.h"
@@ -520,6 +522,8 @@ public:
std::mutex abm_triggers_mutex;
size_t abmTriggersRun(ServerEnvironment *m_env, u32 time, uint8_t activate = 0);
uint32_t m_abm_timestamp{};
using light_t = uint8_t;
std::unordered_map<v3pos_t, light_t> m_light_points;
u32 getActualTimestamp()
{
+1
View File
@@ -6,4 +6,5 @@ XZ::operator XZPoint()
{
return XZPoint{X, Y};
}
const std::vector<ProcessedNode> ProcessedElement::dummy_nodes;
}
+18 -15
View File
@@ -172,10 +172,12 @@ public:
}
}
const static std::vector<ProcessedNode> dummy_nodes;
const std::vector<ProcessedNode> &nodes() const
{
if (is_way())
return as_way().nodes;
return dummy_nodes;
}
static ProcessedElement FromNode(const ProcessedNode &n)
@@ -260,7 +262,11 @@ struct Ground
// Return ground level for a single XZ point
int level(const XZPoint &pos) const
{
++mg->stat.level;
const auto h = mg->get_height(pos.X, pos.Y);
if (h < 1) {
return 1;
}
return h;
}
};
@@ -287,16 +293,8 @@ struct WorldEditor
{
// Implementation for adding a block to the world
const auto yg = ground->level({x, z});
const v3pos_t pos{
static_cast<pos_t>(x), static_cast<pos_t>(yg + y), static_cast<pos_t>(z)};
if (!mg || !mg->vm) {
DUMP("broken mg");
return;
}
if (mg->vm->exists(pos)) {
mg->vm->setNode(pos, block);
}
return set_block_absolute(block, x, yg + y, z, replace_with, avoid);
}
void set_block(const Block &block, int x, int y, int z,
@@ -343,6 +341,9 @@ struct WorldEditor
}
if (mg->vm->exists(pos)) {
mg->vm->setNode(pos, block);
++mg->stat.set;
} else {
++mg->stat.miss;
}
}
@@ -362,6 +363,8 @@ struct WorldEditor
const v3pos_t pos{
static_cast<pos_t>(x), static_cast<pos_t>(y), static_cast<pos_t>(z)};
++mg->stat.check;
if (!mg->vm->exists(pos))
return false;
@@ -372,9 +375,11 @@ struct WorldEditor
//inline auto node_to_xz(const osmium::NodeRef &node)
inline auto node_to_xz(const auto &node)
{
const auto pos2 = mg->ll_to_pos({static_cast<ll_t>(node.y()) /
osmium::detail::coordinate_precision,
static_cast<ll_t>(node.x()) / osmium::detail::coordinate_precision});
const auto pos2 = mg->ll_to_pos(
{static_cast<ll_t>(node.y()) /
static_cast<ll_t>(osmium::detail::coordinate_precision),
static_cast<ll_t>(node.x()) /
static_cast<ll_t>(osmium::detail::coordinate_precision)});
// TODO: scale y
return std::make_pair(pos2.X, pos2.Y);
}
@@ -398,7 +403,6 @@ struct WorldEditor
auto [min_x, max_x] = std::minmax(x1, x2);
auto [min_y, max_y] = std::minmax(y1, y2);
auto [min_z, max_z] = std::minmax(z1, z2);
for (std::int32_t x = min_x; x <= max_x; ++x) {
for (std::int32_t y = min_y; y <= max_y; ++y) {
for (std::int32_t z = min_z; z <= max_z; ++z) {
@@ -407,6 +411,7 @@ struct WorldEditor
}
}
}
++mg->stat.fill;
}
void fill_blocks(const Block &block, std::int32_t x1, std::int32_t y1,
@@ -444,13 +449,11 @@ struct WorldEditor
}
using namespace world_editor;
}
#include "arnis-cpp/src/block_definitions.h"
namespace arnis
{
void init(MapgenEarth *mg);
+9 -53
View File
@@ -213,7 +213,7 @@ void init(MapgenEarth *mg)
ANDESITE = def;
BIRCH_LEAVES = g("default:leaves");
BIRCH_LOG = g("default:tree");
BLACK_CONCRETE = def;
BLACK_CONCRETE = g("default:obsidian");
BLACKSTONE = def;
BLUE_FLOWER = g("flowers:geranium");
BLUE_TERRACOTTA = def;
@@ -239,13 +239,13 @@ void init(MapgenEarth *mg)
GRASS_BLOCK = g("default:grass_5");
GRASS = g("default:grass_3");
GRAVEL = g("default:gravel");
GRAY_CONCRETE = def;
GRAY_CONCRETE = g("default:stone"); // TODO
GRAY_TERRACOTTA = def;
GREEN_STAINED_HARDENED_CLAY = def;
GREEN_WOOL = g("wool:green");
HAY_BALE = def;
IRON_BARS = g("default:stone_with_iron");
IRON_BLOCK = g("default:stone_with_iron");
IRON_BLOCK = g("default:steelblock"); // TODO
JUNGLE_PLANKS = g("default:wood");
LADDER = g("default:ladder_wood");
LIGHT_BLUE_CONCRETE = def;
@@ -285,18 +285,18 @@ void init(MapgenEarth *mg)
SMOOTH_QUARTZ = def;
SMOOTH_RED_SANDSTONE = def;
SMOOTH_SANDSTONE = def;
SMOOTH_STONE = def;
SMOOTH_STONE = g("default:stone");
SPONGE = g("sponge:sponge");
SPRUCE_LOG = def;
SPRUCE_PLANKS = g("default:wood");
STONE_BLOCK_SLAB = def;
STONE_BRICK_SLAB = def;
STONE_BLOCK_SLAB = g("default:stone");
STONE_BRICK_SLAB = g("default:cobble");
STONE_BRICKS = def;
STONE = def;
STONE = g("default:stone");
TERRACOTTA = def;
WARPED_PLANKS = def;
WATER = g("default:water_source");
WHITE_CONCRETE = def;
WHITE_CONCRETE = g("default:stone"); // TODO
WHITE_FLOWER = g("flowers:dandelion_white");
WHITE_STAINED_GLASS = GLASS;
WHITE_TERRACOTTA = def;
@@ -340,7 +340,7 @@ void init(MapgenEarth *mg)
GOLD_ORE = g("default:stone_with_gold");
COPPER_ORE = g("default:stone_with_copper");
CLAY = g("default:clay");
DIRT_PATH = g("default:dirt");
DIRT_PATH = g("default:dirt_with_grass_footsteps");
ICE = g("default:ice");
PACKED_ICE = g("default:ice");
MUD = g("default:dirt");
@@ -386,50 +386,6 @@ void init(MapgenEarth *mg)
QUARTZ_STAIRS = STONE_BRICK_STAIRS;
POLISHED_ANDESITE_STAIRS = STONE_BRICK_STAIRS;
NETHER_BRICK_STAIRS = STONE_BRICK_STAIRS;
// TODO: find better in mods
AIR = g("air");
BLACK_CONCRETE = g("default:obsidian"); // ?
BRICK = g("default:brick");
COBBLESTONE = g("default:cobble");
COBBLESTONE_WALL = g("default:cobble");
DIRT = g("default:dirt");
DIRT_PATH = g("default:dry_dirt");
GLASS = g("default:glass");
GLOWSTONE = g("default:stone");
GRASS_BLOCK = g("default:dirt_with_grass");
GRAVEL = g("default:gravel");
GRAY_CONCRETE = g("default:stone"); // TODO
//GREEN_WOOL = g("wool:green");
IRON_BLOCK = g("default:steelblock"); // TODO
LIGHT_GRAY_CONCRETE = g("default:cobble"); // TODO
OAK_FENCE = g("default:wood");
//OAK_FENCE_GATE = g("default:wood");
//OAK_LEAVES = g("default:leaves");
OAK_LOG = g("default:tree"); // TODO
OAK_PLANKS = g("default:wood");
//RAIL_EAST_WEST = g("default:rail");
//RAIL_NORTH_EAST = g("default:rail");
//RAIL_NORTH_SOUTH = g("default:rail");
//RAIL_NORTH_WEST = g("default:rail");
//RAIL_SOUTH_EAST = g("default:rail");
//RAIL_SOUTH_WEST = g("default:rail");
//RED_WOOL = g("wool:red");
SAND = g("default:sand");
SANDSTONE = g("default:sandstone");
SMOOTH_STONE = g("default:stone");
SMOOTH_STONE_BLOCK = g("default:stone"); //TODO
SNOW_LAYER = g("default:snow");
STONE = g("default:stone");
STONE_BLOCK_SLAB = g("default:stone");
STONE_BRICK_SLAB = g("default:cobble");
STONE_BRICKS = g("default:cobble");
WHITE_CONCRETE = g("default:stone"); // TODO
WHITE_STAINED_GLASS = g("default:glass"); // ?
//WHITE_WOOL = g("wool:white");
//YELLOW_WOOL = g("wool:yellow");
//WATER = g("default:water");
}
}
+21 -19
View File
@@ -65,16 +65,18 @@ height::height_t hgts::get(height_hgt::ll_t lat, height_hgt::ll_t lon)
const auto lat1 = height::lat_start(lat); // + 90 % 180;
const auto lon1 = height::lon_start(lon);
{
const auto &map1_lat1 = map1[lat1];
if (const auto it = map1_lat1.find(lon1); it != map1_lat1.end()) {
prev_layer_height = it->second->get(lat, lon);
if (map1[lat1].contains(lon1)) {
prev_layer_height = map1[lat1][lon1]->get(lat, lon);
if constexpr (layers) {
if (prev_layer_height) {
if constexpr (layers) {
if (prev_layer_height) {
return prev_layer_height;
}
} else {
return prev_layer_height;
}
} else {
return prev_layer_height;
}
}
@@ -90,8 +92,11 @@ height::height_t hgts::get(height_hgt::ll_t lat, height_hgt::ll_t lon)
//DUMP((long)this, "notfound, will load", lat, lon, lat1, lon1, lat90, lon90, map1[lat1].contains(lon1), prev_layer_height);
const auto lock = std::unique_lock(mutex);
if (map1[lat1].contains(lon1)) {
prev_layer_height = map1[lat1][lon1]->get(lat, lon);
const auto &map1_lat1 = map1[lat1];
if (const auto it = map1_lat1.find(lon1); it != map1_lat1.end()) {
prev_layer_height = it->second->get(lat, lon);
if constexpr (layers) {
if (prev_layer_height) {
return prev_layer_height;
@@ -123,15 +128,15 @@ height::height_t hgts::get(height_hgt::ll_t lat, height_hgt::ll_t lon)
};
if (lat <= 90 && lat >= -90 && lon <= 180 && lon >= -180) {
// DUMP("insert", (long)this, lat, lon, folder, map1.size(), map1[lat1].size());
if (!map1[lat1].contains(lon1)) {
// DUMP("insert", (long)this, lat, lon, folder, map1.size(), map1_lat1.size());
if (!map1_lat1.contains(lon1)) {
auto hgt = std::make_shared<height_hgt>(folder, lat, lon);
const int lat_dec = hgt->lat_start(lat);
const int lon_dec = hgt->lon_start(lon);
if (hgt->load(lat, lon)) {
map1[lat_dec][lon_dec] = std::move(hgt);
prev_layer_height = map1[lat_dec][lon_dec]->get(lat, lon);
DUMP("hgt ok", lat, lon, lat_dec, lon_dec, prev_layer_height);
//DUMP("hgt ok", lat, lon, lat_dec, lon_dec, prev_layer_height);
if constexpr (layers) {
if (prev_layer_height) {
@@ -181,7 +186,7 @@ height::height_t hgts::get(height_hgt::ll_t lat, height_hgt::ll_t lon)
}
}
if (!map90[lat90].contains(lon90)) {
place_dummy90(lat90, lon90);
return place_dummy90(lat90, lon90);
}
return map90[lat90][lon90]->get(lat, lon);
}
@@ -259,8 +264,7 @@ bool height_hgt::load(ll_t lat, ll_t lon)
//DUMP(lat_dec, lon_dec);
return false;
}
DUMP((long long)this, lat_dec, lon_dec, lat_loading, lon_loading, lat_loaded,
lon_loaded);
//DUMP((long long)this, lat_dec, lon_dec, lat_loading, lon_loading, lat_loaded, lon_loaded);
TimeTaker timer("hgt load");
lat_loading = lat_dec;
@@ -459,9 +463,7 @@ bool height_hgt::load(ll_t lat, ll_t lon)
}
lat_loaded = lat_dec;
lon_loaded = lon_dec;
DUMP("loadok", (long long)this, heights.size(), lat_loaded, lon_loaded, filesize,
zipname, filename, seconds_per_px_x, get(lat_dec, lon_dec), heights[0],
heights.back(), heights[side_length_x]);
//DUMP("loadok", (long long)this, heights.size(), lat_loaded, lon_loaded, filesize, zipname, filename, seconds_per_px_x, get(lat_dec, lon_dec), heights[0], heights.back(), heights[side_length_x]);
return true;
}
@@ -968,7 +970,7 @@ height::height_t height::get(ll_t lat, ll_t lon)
//lat_seconds, lon_seconds,
seconds_per_px_x, seconds_per_px_y, lat, lon, lat_loaded, lon_loaded,
(lat - lat_loaded), pixel_per_deg_x, (lon - lon_loaded), pixel_per_deg_y);
//return height[2]; // debug not interpolated
//return height[2]; // debug not interpolated
#endif
// ratio where X lays
+26 -7
View File
@@ -4,6 +4,7 @@
#include <thread>
#include <fstream>
#include "debug/dump.h"
#include "filesys.h"
#include "httpfetch.h"
#include "log.h"
#include "settings.h"
@@ -50,12 +51,16 @@ size_t http_to_file(const std::string &url, const std::string &path)
return std::filesystem::file_size(path);
};
size_t multi_http_to_file(const std::string &name,
const std::vector<std::string> &links, const std::string &path)
size_t multi_http_to_file(
const std::string &name, const std::vector<std::string> &links, std::string path)
{
if (path.empty()) {
path = porting::path_cache + DIR_DELIM + "earth" + "/" + name;
}
static concurrent_set<std::string> http_failed;
if (http_failed.contains(name)) {
return std::filesystem::file_size(path);
return std::filesystem::exists(path) ? std::filesystem::file_size(path) : 0;
}
if (std::filesystem::exists(path)) {
@@ -70,7 +75,7 @@ size_t multi_http_to_file(const std::string &name,
http_failed.insert(name);
errorstream
infostream
<< "Not found " << name << "\n"
<< "try to download manually: \n"
<< "curl -o " << path << " "
@@ -83,8 +88,21 @@ size_t multi_http_to_file(const std::string &name,
return std::filesystem::file_size(path);
};
size_t multi_http_to_file(
const std::vector<std::string> &links, const std::string &path)
size_t multi_http_to_file_cdn(
const std::string &name, std::vector<std::string> links, const std::string &path)
{
links.insert(links.begin(),
#if defined(__EMSCRIPTEN__)
"/"
#else
"http://cdn.freeminer.org/"
#endif
"earth/" +
name);
return multi_http_to_file(name, links, path);
}
size_t multi_http_to_file(const std::vector<std::string> &links, const std::string &path)
{
static concurrent_set<std::string> http_failed;
if (http_failed.contains(path)) {
@@ -103,7 +121,7 @@ size_t multi_http_to_file(
http_failed.emplace(path);
errorstream
infostream
<< "Not found " << path << "\n"
<< "try to download manually: \n"
<< "curl -o " << path << " "
@@ -116,6 +134,7 @@ size_t multi_http_to_file(
return std::filesystem::file_size(path);
};
std::string exec_to_string(const std::string &cmd)
{
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
+3 -1
View File
@@ -5,8 +5,10 @@
size_t http_to_file(const std::string &url, const std::string &zipfull);
size_t multi_http_to_file(const std::string &zipfile,
const std::vector<std::string> &links, const std::string &zipfull);
const std::vector<std::string> &links, std::string zipfull = {});
size_t multi_http_to_file(
const std::vector<std::string> &links, const std::string &zipfull);
size_t multi_http_to_file_cdn(const std::string &name, std::vector<std::string> links,
const std::string &path = {});
std::string exec_to_string(const std::string &cmd);
+48 -44
View File
@@ -1,5 +1,6 @@
#include <cstddef>
#include <cstdlib>
#include <exception>
#include <vector>
#include "irr_v3d.h"
#include "irrlichttypes.h"
@@ -183,49 +184,56 @@ public:
class MyHandler : public osmium::handler::Handler
{
MapgenEarth *mg;
const bool todo{false};
public:
MyHandler(MapgenEarth *mg) : mg{mg} {}
MapgenEarth *mg{};
void way(const osmium::Way &way)
{
arnis::Ground ground;
ground.mg = mg;
arnis::WorldEditor editor;
editor.mg = mg;
editor.ground = &ground;
std::vector<arnis::ProcessedElement> v;
arnis::ProcessedWay w;
for (const auto &t : way.tags()) {
w.tags.emplace(t.key(), t.value());
try {
arnis::Ground ground;
ground.mg = mg;
arnis::WorldEditor editor;
editor.mg = mg;
editor.ground = &ground;
std::vector<arnis::ProcessedElement> v;
arnis::ProcessedWay w;
for (const auto &t : way.tags()) {
w.tags.emplace(t.key(), t.value());
}
for (const auto &n : way.nodes()) {
arnis::ProcessedNode pn;
pn.tags = w.tags;
const auto [x, y] = editor.node_to_xz(n);
pn.x = x;
pn.z = y;
pn.id = w.id;
w.nodes.emplace_back(pn);
}
v.emplace_back(w);
arnis::generate_world(editor, v);
} catch (const std::exception &ex) {
DUMP(ex.what());
}
for (const auto &n : way.nodes()) {
arnis::ProcessedNode pn;
pn.tags = w.tags;
const auto [x, y] = editor.node_to_xz(n);
pn.x = x;
pn.z = y;
pn.id = w.id;
w.nodes.emplace_back(pn);
}
v.emplace_back(w);
arnis::generate_world(editor, v);
}
void relation(const osmium::Relation &relation)
{
arnis::Ground ground;
ground.mg = mg;
arnis::WorldEditor editor;
editor.mg = mg;
editor.ground = &ground;
std::vector<arnis::ProcessedElement> v;
for (const auto &r : relation) {
try {
arnis::Ground ground;
ground.mg = mg;
arnis::WorldEditor editor;
editor.mg = mg;
editor.ground = &ground;
std::vector<arnis::ProcessedElement> v;
for (const auto &r : relation) {
}
for (const auto &sn : relation.subitems<osmium::Way>()) {
way(sn);
}
arnis::generate_world(editor, v);
} catch (const std::exception &ex) {
DUMP(ex.what());
}
arnis::generate_world(editor, v);
}
};
class hdl : public handler_i
@@ -234,20 +242,14 @@ class hdl : public handler_i
osmium::Location>;
using cache_t = osmium::handler::NodeLocationsForWays<index_t>;
MapgenEarth *mg{};
const std::string path_name;
MyHandler handler;
public:
hdl(MapgenEarth *mg, const std::string &path_name) :
mg{mg}, path_name{path_name}, handler{mg}
{
}
hdl(MapgenEarth *mg, const std::string &path_name) : path_name{path_name} {}
~hdl() = default;
void apply() override
void apply(MapgenEarth *mg) override
{
osmium::area::Assembler::config_type assembler_config;
assembler_config.create_empty_areas = false;
@@ -260,7 +262,6 @@ public:
{
const auto llmin = mg->pos_to_ll(mg->node_min.X, mg->node_min.Z);
const auto llmax = mg->pos_to_ll(mg->node_max.X, mg->node_max.Z);
}
osmium::io::File file{path_name, "pbf"};
osmium::relations::read_relations(file, mp_manager);
@@ -272,9 +273,12 @@ public:
}
arnis::init(mg);
MyHandler handler;
handler.mg = mg;
osmium::apply(reader, cache, handler,
mp_manager.handler([&handler = this->handler](
const osmium::memory::Buffer &area_buffer) {
mp_manager.handler([&handler](const osmium::memory::Buffer &area_buffer) {
osmium::apply(area_buffer, handler);
}));
}
+181
View File
@@ -0,0 +1,181 @@
#pragma once
#include <png.h>
#include <cstdio>
#include <string>
#include <vector>
#include <stdexcept>
#include <optional>
#include <cstdint>
//#include <iostream>
#include "SColor.h"
//struct RGBA {uint8_t r, g, b, a;};
using RGBA = video::SColor;
class PngImage {
public:
// open and read PNG, convert to 8-bit RGBA
explicit PngImage(const std::string& filename) {
fp_ = std::fopen(filename.c_str(), "rb");
if (!fp_) throw std::runtime_error("Failed to open file: " + filename);
png_ptr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr_) {
std::fclose(fp_);
fp_ = nullptr;
throw std::runtime_error("png_create_read_struct failed");
}
info_ptr_ = png_create_info_struct(png_ptr_);
if (!info_ptr_) {
png_destroy_read_struct(&png_ptr_, nullptr, nullptr);
std::fclose(fp_);
fp_ = nullptr;
throw std::runtime_error("png_create_info_struct failed");
}
if (setjmp(png_jmpbuf(png_ptr_))) {
// libpng error
cleanup();
throw std::runtime_error("libpng error during init/read");
}
png_init_io(png_ptr_, fp_);
png_read_info(png_ptr_, info_ptr_);
png_uint_32 w, h;
int bit_depth, color_type, interlace_type, compression_type, filter_method;
png_get_IHDR(png_ptr_, info_ptr_, &w, &h, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_method);
width_ = static_cast<int>(w);
height_ = static_cast<int>(h);
// Transformations to 8-bit RGBA:
// Expand palette, grayscale < 8, and tRNS to RGB(A)
png_set_expand(png_ptr_);
// Convert 16-bit to 8-bit
if (bit_depth == 16) png_set_strip_16(png_ptr_);
// Convert gray/gray+alpha to RGB(A)
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr_);
// Ensure we have alpha: if image has no alpha, add an opaque alpha channel
if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
// Put alpha after RGB (i.e., RGBA)
png_set_filler(png_ptr_, 0xFF, PNG_FILLER_AFTER);
}
// Handle interlace
png_set_interlace_handling(png_ptr_);
// Update info after transformations
png_read_update_info(png_ptr_, info_ptr_);
// Get bytes per row (after transforms)
png_uint_32 rowbytes = png_get_rowbytes(png_ptr_, info_ptr_);
if (rowbytes == 0) {
cleanup();
throw std::runtime_error("Invalid rowbytes");
}
rowbytes_ = static_cast<size_t>(rowbytes);
// allocate one contiguous buffer for all image data
image_data_.resize(rowbytes_ * static_cast<size_t>(height_));
row_pointers_.resize(height_);
for (int i = 0; i < height_; ++i) {
row_pointers_[i] = image_data_.data() + (size_t)i * rowbytes_;
}
// Read the image into our buffer
png_read_image(png_ptr_, row_pointers_.data());
// After read, we expect 4 bytes per pixel (RGBA)
// But verify: rowbytes must be width * 4 (or at least enough)
if (rowbytes_ < static_cast<size_t>(width_) * 4) {
cleanup();
throw std::runtime_error("Unexpected row size after transformation");
}
}
// Disable copy
PngImage(const PngImage&) = delete;
PngImage& operator=(const PngImage&) = delete;
// Enable move
PngImage(PngImage&& other) noexcept {
steal_from(std::move(other));
}
PngImage& operator=(PngImage&& other) noexcept {
if (this != &other) {
cleanup();
steal_from(std::move(other));
}
return *this;
}
~PngImage() {
cleanup();
}
int width() const noexcept { return width_; }
int height() const noexcept { return height_; }
// Return RGBA for given coords, or std::nullopt if out of bounds.
std::optional<RGBA> get_pixel(int x, int y) const noexcept {
if (x < 0 || y < 0 || x >= width_ || y >= height_) return std::nullopt;
const uint8_t* row = row_pointers_[y];
const uint8_t* px = row + static_cast<size_t>(x) * 4; // 4 bytes per pixel (R,G,B,A)
RGBA c{ px[3], px[0], px[1], px[2] };
return c;
}
private:
png_structp png_ptr_ = nullptr;
png_infop info_ptr_ = nullptr;
FILE* fp_ = nullptr;
int width_ = 0;
int height_ = 0;
size_t rowbytes_ = 0;
std::vector<uint8_t> image_data_;
std::vector<png_bytep> row_pointers_;
void cleanup() noexcept {
if (png_ptr_ || info_ptr_) {
// png_destroy_read_struct frees info_ptr_ as well
png_destroy_read_struct(&png_ptr_, &info_ptr_, nullptr);
png_ptr_ = nullptr;
info_ptr_ = nullptr;
}
if (fp_) {
std::fclose(fp_);
fp_ = nullptr;
}
image_data_.clear();
row_pointers_.clear();
}
void steal_from(PngImage&& other) noexcept {
png_ptr_ = other.png_ptr_;
info_ptr_ = other.info_ptr_;
fp_ = other.fp_;
width_ = other.width_;
height_ = other.height_;
rowbytes_ = other.rowbytes_;
image_data_ = std::move(other.image_data_);
row_pointers_ = std::move(other.row_pointers_);
other.png_ptr_ = nullptr;
other.info_ptr_ = nullptr;
other.fp_ = nullptr;
other.width_ = other.height_ = 0;
other.rowbytes_ = 0;
}
};
+116
View File
@@ -0,0 +1,116 @@
// write function on c++ : params color in rgb encoding temperature from blue to red and returns temperature in celsius
/*
I'm considering how to solve for inverse mapping by finding the parameter \( t \) that minimizes error. A brute-force search over the range [0, 1] with small steps or Newton's method could work, but implementing a numerical search sounds more robust. I can sample 1,000 points and refine via binary search for better matching. I’ll provide both a straightforward linear method and a more intricate jet inverse approach using C++17 with relevant examples. I’ll format everything in markdown!**Coding RGB to Temperature Conversion**
I’m writing code that includes the `cmath` and `algorithm` libraries. First, I’ll define a function, `rgbToTemperatureLinear`, that converts RGB values to a temperature range based on given minimum and maximum temperatures. I’ll also implement `rgbToTemperatureJet`, which uses formulas to calculate values for red, green, and blue based on a temperature parameter \( t \). Next, I’ll execute a coarse search with 2,000 samples to find the best \( t \), and refine that with smaller steps to minimize the squared error.**Refining the Temperature Mapping**
Next, I plan to refine the search around the best \( t \) value found earlier by using either the golden-section method or a simpler approach with a loop from 0 to 5. I’ll search within the range defined by \( t_{\text{best}} \) plus and minus a small delta, using a finer step of \( K = 200 \) to compute any necessary updates. As I decrease the delta for convergence, I'll ensure the final result is clear: returning the calculated temperature.
I'll also include usage examples and note important considerations like potential ambiguities in mapping and the presence of noise.</div>Below are two C++ functions you can use to convert an RGB color (assumed to encode a temperature on a blue→red scale) back to a temperature in Celsius.
- The first function (rgbToCelsiusLinear) assumes a simple linear gradient from pure blue (0,0,255) at the cold end to pure red (255,0,0) at the hot end. It is cheap and analytic.
- The second function (rgbToCelsiusJet) handles a common “rainbow/jet-like” thermal map (blue→cyan→green→yellow→red) by numerically inverting the forward jet colormap. This is a more realistic thermal palette but requires sampling/search so it’s a bit heavier.
Both functions take r,g,b in 0..255 and minTemp/maxTemp in Celsius (defaults given) and return a double temperature in Celsius.
Code (C++17):
*/
#pragma once
#include <cmath>
#include <algorithm>
#include <array>
#include <limits>
// clamp helper
static inline double clamp01(double x) {
return std::max(0.0, std::min(1.0, x));
}
// 1) Simple linear blue->red gradient inversion
// Maps: blue (0,0,255) -> t=0 ; red (255,0,0) -> t=1
// r,g,b are 0..255, returns temperature in Celsius between minTemp and maxTemp.
double rgbToCelsiusLinear(int r, int g, int b, double minTemp = -30.0, double maxTemp = 50.0) {
double rn = clamp01(r / 255.0);
double bn = clamp01(b / 255.0);
// projection onto the R<-B gradient: t = (r_norm - b_norm + 1) / 2
double t = (rn - bn + 1.0) / 2.0;
t = clamp01(t);
return minTemp + t * (maxTemp - minTemp);
}
// 2) Invert a typical "jet" / rainbow colormap numerically.
// Forward jet mapping (t in [0,1]) used here:
// r = clamp(1.5 - |4t - 3|)
// g = clamp(1.5 - |4t - 2|)
// b = clamp(1.5 - |4t - 1|)
static inline std::array<double,3> jetColor(double t) {
t = clamp01(t);
double r = clamp01(1.5 - std::fabs(4.0 * t - 3.0));
double g = clamp01(1.5 - std::fabs(4.0 * t - 2.0));
double b = clamp01(1.5 - std::fabs(4.0 * t - 1.0));
return {r, g, b};
}
// invert jet colormap by coarse-to-fine search
double rgbToCelsiusJet(int r, int g, int b, double minTemp = -30.0, double maxTemp = 50.0) {
const double rn = clamp01(r / 255.0);
const double gn = clamp01(g / 255.0);
const double bn = clamp01(b / 255.0);
// coarse sampling to get initial guess
int coarseN = 800; // coarse samples (adjust for speed/precision)
double bestT = 0.0;
double bestErr = std::numeric_limits<double>::infinity();
for (int i = 0; i < coarseN; ++i) {
double t = double(i) / double(coarseN - 1);
auto c = jetColor(t);
double err = (c[0] - rn)*(c[0] - rn) + (c[1] - gn)*(c[1] - gn) + (c[2] - bn)*(c[2] - bn);
if (err < bestErr) {
bestErr = err;
bestT = t;
}
}
// refine around bestT with a few finer searches
double delta = 1.0 / double(coarseN - 1);
for (int pass = 0; pass < 4; ++pass) {
double start = clamp01(bestT - delta);
double end = clamp01(bestT + delta);
int fineN = 200;
double localBestT = bestT;
double localBestErr = bestErr;
for (int i = 0; i < fineN; ++i) {
double t = start + (end - start) * double(i) / double(fineN - 1);
auto c = jetColor(t);
double err = (c[0] - rn)*(c[0] - rn) + (c[1] - gn)*(c[1] - gn) + (c[2] - bn)*(c[2] - bn);
if (err < localBestErr) {
localBestErr = err;
localBestT = t;
}
}
bestT = localBestT;
bestErr = localBestErr;
delta *= 0.25; // shrink search radius
}
double temp = minTemp + bestT * (maxTemp - minTemp);
return temp;
}
/*
Usage examples:
- If your color map is exactly linear blue->red use rgbToCelsiusLinear.
- If your color map is a rainbow/thermal (blue→cyan→green→yellow→red) use rgbToCelsiusJet.
Notes and caveats:
- The mapping from color to temperature is not unique without knowing the exact colormap and the numeric temperature range. You must supply the min and max temperatures that correspond to the cold and hot ends of the colormap.
- Real images may contain noise, gamma correction or encoding differences; you may need to pre-correct for gamma or color-space conversions if colors appear non-linear.
- If your colormap is different, provide its forward mapping and invert it similarly (analytic or numeric search).
- If you expect many conversions, precompute a lookup table (LUT) from colors to temperatures for speed.
If you tell me which exact colormap and numeric temperature range you use (and whether input is linear RGB or sRGB), I can tailor the function exactly to that mapping.
*/
+11
View File
@@ -7,6 +7,7 @@
#include <cmath>
#include "irr_v3d.h"
#include "mapgen.h"
#include "servermap.h"
#include "voxel.h"
#include "noise.h"
#include "gamedef.h"
@@ -1262,3 +1263,13 @@ const MapNode &Mapgen::visible_content(const v3pos_t &p, bool use_weather)
: heat < 40 ? (humidity < 20 ? visible_surface_dry : visible_surface_green)
: visible_surface_hot;
}
weather::heat_t Mapgen::calcBlockHeat(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather)
{
return m_emerge->biomemgr->calcBlockHeat(p, seed, timeofday, totaltime, use_weather);
}
weather::humidity_t Mapgen::calcBlockHumidity(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather)
{
return m_emerge->biomemgr->calcBlockHumidity(p, seed, timeofday, totaltime, use_weather);
}
+10 -5
View File
@@ -6,6 +6,7 @@
#pragma once
#include "fm_weather.h"
#include "noise.h"
#include "nodedef.h"
#include "util/string.h"
@@ -98,10 +99,11 @@ private:
// Order must match the order of 'static MapgenDesc g_reg_mapgens[]' in mapgen.cpp
enum MapgenType {
// freeminer:
MAPGEN_EARTH,
MAPGEN_INDEV,
MAPGEN_MATH,
MAPGEN_INDEV,
// ==========
MAPGEN_V7,
MAPGEN_VALLEYS,
@@ -235,10 +237,10 @@ public:
virtual int getGroundLevelAtPoint(v2s16 p) { return 0; }
// freeminer:
ServerEnvironment *env = nullptr;
ServerEnvironment *env {};
s16 liquid_pressure = 0;
unordered_map_v3pos<s16> heat_cache;
unordered_map_v3pos<s16> humidity_cache;
unordered_map_v3bpos<weather::heat_t> heat_cache;
unordered_map_v3bpos<weather::humidity_t> humidity_cache;
MapNode visible_surface;
MapNode visible_surface_green;
@@ -253,6 +255,9 @@ public:
virtual bool visible_water_level(const v3pos_t &p);
virtual const MapNode &visible_content(const v3pos_t &p, bool use_weather);
virtual bool surface_2d() { return true; };
virtual weather::heat_t calcBlockHeat(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather);
virtual weather::humidity_t calcBlockHumidity(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather);
// ===
// getSpawnLevelAtPoint() is a function within each mapgen that returns a
// suitable y co-ordinate for player spawn ('suitable' usually meaning
+232 -101
View File
@@ -21,35 +21,46 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#include <cmath>
#include <cstdlib>
#include <exception>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <system_error>
#include <tuple>
#include "constants.h"
#include "debug/dump.h"
#include "emerge.h"
#include "mapgen/earth/png_holder.h"
#include "mapgen/earth/rgb_temp.h"
#include "server.h"
#include "filesys.h"
#include "irr_v2d.h"
#include "irr_v3d.h"
#include "irrlichttypes.h"
#include "log_types.h"
#include "log.h"
#include "map.h"
#include "mapblock.h"
#include "mapgen_earth.h"
#include "mapgen/earth/hgt.h"
#include "mapgen/earth/http.h"
#include "mapgen_earth.h"
#include "voxel.h"
#include "mapblock.h"
#include "mapnode.h"
#include "map.h"
#include "nodedef.h"
#include "voxelalgorithms.h"
#include "settings.h"
#include "emerge.h"
#include "serverenvironment.h"
#include "mg_biome.h"
#include "log_types.h"
#include "nodedef.h"
#include "serverenvironment.h"
#include "settings.h"
#include "util/timetaker.h"
#include "voxel.h"
#include "voxelalgorithms.h"
#if USE_OSMIUM
#include "earth/osmium-inl.h"
#include <filesystem>
#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_manager.hpp>
#include <osmium/dynamic_handler.hpp>
#include <osmium/geom/tile.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/io/file.hpp>
@@ -58,10 +69,8 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#include <osmium/osm/node.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/tags/tags_filter.hpp>
#include "earth/osmium-inl.h"
#endif
std::unique_ptr<maps_holder_t> MapgenEarth::maps_holder;
void MapgenEarthParams::setDefaultSettings(Settings *settings)
@@ -135,7 +144,7 @@ MapgenEarth::MapgenEarth(MapgenEarthParams *params_, EmergeParams *emerge) :
// mg_params = (MapgenEarthParams *)params_->sparams;
mg_params = params_;
Json::Value &params = mg_params->params;
const Json::Value &params = mg_params->params;
flags = 0;
if (params.get("light", 0).asBool())
@@ -203,6 +212,23 @@ MapgenEarth::MapgenEarth(MapgenEarthParams *params_, EmergeParams *emerge) :
if (!maps_holder) {
maps_holder = std::make_unique<maps_holder_t>();
}
{
const auto heat_img = maps_holder->data_root + "/earth_heat.png";
if (!std::filesystem::exists(heat_img)) {
const auto lock = std::lock_guard(maps_holder->download_lock);
if (!std::filesystem::exists(heat_img)) {
multi_http_to_file_cdn("earth_heat.png", {});
}
}
if (std::filesystem::exists(heat_img)) {
const auto lock = std::lock_guard(maps_holder->download_lock);
if (!maps_holder->heat_image) {
maps_holder->heat_image = std::make_unique<PngImage>(heat_img);
}
}
}
}
MapgenEarth::~MapgenEarth()
@@ -213,8 +239,9 @@ MapgenEarth::~MapgenEarth()
MapNode MapgenEarth::layers_get(float value, float max)
{
auto layer_index = rangelim((unsigned int)myround((value / max) * layers_node_size),
0, layers_node_size - 1);
const auto layer_index =
rangelim((unsigned int)myround((value / max) * layers_node_size), 0,
layers_node_size - 1);
return layers_node[layer_index];
}
@@ -256,6 +283,10 @@ ll MapgenEarth::pos_to_ll(const pos_t x, const pos_t z)
return {89.9999, 0};
}
}
ll MapgenEarth::pos_to_ll(const v3pos_t &p)
{
return pos_to_ll(p.X, p.Z);
}
v2pos_t MapgenEarth::ll_to_pos(const ll &l)
{
@@ -266,7 +297,7 @@ v2pos_t MapgenEarth::ll_to_pos(const ll &l)
pos_t MapgenEarth::get_height(pos_t x, pos_t z)
{
const auto tc = pos_to_ll(x, z);
auto y = maps_holder->hgt_reader.get(tc.lat, tc.lon);
const auto y = maps_holder->hgt_reader.get(tc.lat, tc.lon);
return ceil(y / scale.Y) - center.Y;
}
@@ -282,18 +313,18 @@ int MapgenEarth::getGroundLevelAtPoint(v2pos_t p)
int MapgenEarth::generateTerrain()
{
MapNode n_ice(c_ice);
const MapNode n_ice(c_ice);
u32 index = 0;
auto em = vm->m_area.getExtent();
const auto em = vm->m_area.getExtent();
for (pos_t z = node_min.Z; z <= node_max.Z; z++) {
for (pos_t x = node_min.X; x <= node_max.X; x++, index++) {
s16 heat =
const auto heat =
m_emerge->env->m_use_weather
? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env,
v3pos_t(x, node_max.Y, z), nullptr, &heat_cache)
: 0;
auto height = get_height(x, z);
const auto height = get_height(x, z);
u32 i = vm->m_area.index(x, node_min.Y, z);
for (pos_t y = node_min.Y; y <= node_max.Y; y++) {
bool underground = height >= y;
@@ -349,105 +380,205 @@ const auto floor01 = [](const auto &v, const float &div) { return floor(v * div)
//const auto ceil01 = [](const auto &v, const float &div) { return ceil(v * div) / div; };
const auto make_bbox = [](auto tc, auto div) {
const auto lat_dec01 = floor01(tc.lat, div);
const auto lon_dec01 = floor01(tc.lon, div);
const auto lat_end_dec01 = floor01(tc.lat + (1.0 / div), div);
const auto lon_end_dec01 = floor01(tc.lon + (1.0 / div), div);
auto bbox_to_string(const auto &start, const auto &end)
{
std::stringstream bboxs;
bboxs << lon_dec01 << "," << lat_dec01 << "," << lon_end_dec01 << ","
<< lat_end_dec01;
auto bbox = bboxs.str();
return bbox;
bboxs << start.lon << "," << start.lat << "," << end.lon << "," << end.lat;
return bboxs.str();
}
auto make_bbox(const auto &tc, auto div)
{
const ll start{floor01(tc.lat, div), floor01(tc.lon, div)};
const ll end{floor01(tc.lat + (1.0 / div), div), floor01(tc.lon + (1.0 / div), div)};
const auto bbox = bbox_to_string(start, end);
return std::make_tuple(bbox, start, end);
};
void MapgenEarth::generateBuildings()
{
#if USE_OSMIUM
TimeTaker timer("earth buildings", {}, PRECISION_MILLI);
std::string use_file;
try {
//#define FILE_INCLUDED 1
//#include "earth/osmium-inl.h"
const auto tc = pos_to_ll(node_min.X, node_min.Z);
const auto tc_max = pos_to_ll(node_max.X, node_max.Z);
static const auto folder = porting::path_cache + DIR_DELIM + "earth";
const auto lat_dec = lat_start(tc.lat);
const auto lon_dec = lon_start(tc.lon);
//#define FILE_INCLUDED 1
//#include "earth/osmium-inl.h"
const auto tc = pos_to_ll(node_min.X, node_min.Z);
const auto tc_max = pos_to_ll(node_max.X, node_max.Z);
static const auto folder = maps_holder->data_root;
const auto lat_dec = lat_start(tc.lat);
const auto lon_dec = lon_start(tc.lon);
static const auto timestamp = []() {
// const std::string ts = "202509040800";
std::string ts = "latest";
g_settings->getNoEx("earth_movisda_timestamp", ts);
return ts;
}();
char buff[100];
std::snprintf(buff, sizeof(buff), "%c%02d%c%03d-%s.osm.pbf", lat_dec >= 0 ? 'N' : 'S',
abs(lat_dec), lon_dec >= 0 ? 'W' : 'E', abs(lon_dec), timestamp.c_str());
std::string filename = buff;
const auto base_full_name = folder + DIR_DELIM + filename;
if (!std::filesystem::exists(base_full_name)) {
const auto lock = std::lock_guard(maps_holder->osm_http_lock);
static const auto timestamp = []() {
std::string ts = "latest";
g_settings->getNoEx("earth_movisda_timestamp", ts);
return ts;
}();
char buff[100];
std::snprintf(buff, sizeof(buff), "%c%02d%c%03d-%s.osm.pbf",
lat_dec >= 0 ? 'N' : 'S', abs(lat_dec), lon_dec > 0 ? 'W' : 'E',
abs(lon_dec), timestamp.c_str());
const std::string filename = buff;
const auto base_full_name = folder + DIR_DELIM + filename;
if (!std::filesystem::exists(base_full_name)) {
const auto url = "https://osm.download.movisda.io/grid/" + filename;
multi_http_to_file({url}, base_full_name);
const auto lock = std::lock_guard(maps_holder->osm_http_lock);
if (!std::filesystem::exists(base_full_name)) {
const auto url = "https://osm.download.movisda.io/grid/" + filename;
multi_http_to_file({url}, base_full_name);
}
}
}
std::string use_file = base_full_name;
std::string bbox;
{
const auto try_extract = [](const auto &path_name, const auto &bbox,
const auto &filename) {
if (std::filesystem::exists(filename)) {
return true;
}
const auto lock = std::lock_guard(maps_holder->osm_extract_lock);
if (std::filesystem::exists(filename)) {
return true;
}
use_file = base_full_name;
std::string bbox;
{
const auto try_extract = [](const auto &path_name, const auto &bbox,
const auto &filename) {
if (std::filesystem::exists(filename)) {
return true;
}
const auto lock = std::lock_guard(maps_holder->osm_extract_lock);
if (std::filesystem::exists(filename)) {
return true;
}
std::stringstream cmd;
// TODO: use osmium tool as lib
cmd << "osmium extract --output-format pbf --strategy smart " << "--bbox "
<< bbox << " --output " << filename << ".tmp" << " " << path_name;
exec_to_string(cmd.str());
if (!std::filesystem::exists(filename + ".tmp")) {
return false;
}
std::stringstream cmd;
// TODO: use osmium tool as lib
// --option types=multipolygon,route
cmd << "osmium extract --output-format pbf --strategy smart --option types=any "
<< "--bbox " << bbox << " --output " << filename << ".tmp" << " "
<< path_name;
exec_to_string(cmd.str());
if (!std::filesystem::exists(filename + ".tmp")) {
return false;
}
std::error_code error_code;
std::filesystem::rename(filename + ".tmp", filename, error_code);
return !error_code.value();
};
for (auto div = 10; div <= 1000; div *= 10) {
std::error_code ec;
const auto size = std::filesystem::file_size(use_file, ec);
if (ec || size < 40000) {
break;
std::error_code error_code;
std::filesystem::rename(filename + ".tmp", filename, error_code);
return !error_code.value();
};
const auto bbox_next = make_bbox(tc, div);
auto filename_next = folder + DIR_DELIM + "extract." + std::to_string(div) +
"." + bbox_next + ".osm.pbf";
if (!try_extract(use_file, bbox_next, filename_next)) {
break;
for (auto div = 10; div <= 10000; div *= 10) {
std::error_code ec;
const auto size = std::filesystem::file_size(use_file, ec);
if (ec) {
break;
};
auto [bbox_next, bb_start, bb_end] = make_bbox(tc, div);
const auto bbox_to_filename = [](const auto &bbox_next, const auto div) {
auto filename_next = folder + DIR_DELIM + "extract." +
std::to_string(div) + "." + bbox_next +
".osm.pbf";
return filename_next;
};
auto filename_next = bbox_to_filename(bbox_next, div);
if (!(bb_start.lat <= tc.lat && bb_start.lon <= tc.lon &&
bb_end.lat >= tc_max.lat && bb_end.lon >= tc_max.lon)) {
const auto bbox_exact = bbox_to_string(tc, tc_max);
const auto filename_exact = bbox_to_filename(bbox_exact, 100000);
filename_next = filename_exact;
bbox_next = bbox_exact;
}
if (!try_extract(use_file, bbox_next, filename_next)) {
break;
}
if (div >= 1000) {
maps_holder->files_to_delete.emplace_back(filename_next);
}
use_file = filename_next;
bbox = bbox_next;
}
use_file = filename_next;
bbox = bbox_next;
}
if (std::filesystem::exists(use_file) && std::filesystem::file_size(use_file)) {
const auto lock = std::lock_guard{maps_holder->osm_bbox_lock};
if (!maps_holder->osm_bbox.contains(bbox)) {
const auto osm = std::make_shared<hdl>(this, use_file);
//const auto lock = maps_holder->osm_bbox.lock_unique_rec();
if (!maps_holder->osm_bbox.contains(bbox)) {
maps_holder->osm_bbox.emplace(bbox, osm);
}
}
}
{
const auto lock = std::lock_guard{maps_holder->osm_bbox_lock};
if (const auto &hdlr = maps_holder->osm_bbox.get(bbox)) {
hdlr.value()->apply(this);
}
}
} catch (const std::exception &ex) {
warningstream << node_min << " : " << ex.what() << " file=" << use_file << "\n";
}
if (std::filesystem::exists(use_file)) {
const auto osm = std::make_shared<hdl>(this, use_file);
const auto lock = maps_holder->osm_bbox.lock_unique_rec();
if (!maps_holder->osm_bbox.contains(bbox)) {
maps_holder->osm_bbox.emplace(bbox, osm);
}
}
if (const auto &hdlr = maps_holder->osm_bbox.get(bbox)) {
hdlr->apply();
}
verbosestream << "Buildings stat: " << node_min << " .. " << node_max << " "
<< " set=" << stat.set << " miss=" << stat.miss
<< " level=" << stat.level << " check=" << stat.check
<< " fill=" << stat.fill << " per=" << timer.getTimerTime()
<< " mh=" << maps_holder->osm_bbox.size() << "\n";
stat.clean();
#endif
}
/*
Heat data:
https://search.earthdata.nasa.gov/search/granules?p=C1276812859-GES_DISC&pg[0][v]=f&pg[0][gsk]=-start_date&g=G3503129918-GES_DISC&ff=Map%20Imagery&tl=1038183927.842!5!!&fsm0=Clouds&fst0=Atmosphere&long=2.3696682464454994&zoom=2.8910241901494977
https://gibs-a.earthdata.nasa.gov/wmts/epsg4326/best/wmts.cgi?TIME=2025-03-01&layer=MERRA2_2m_Air_Temperature_Monthly&style=default&tilematrixset=2km&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fpng&TileMatrix=0&TileCol=0&TileRow=0
Snow data:
https://cmr.earthdata.nasa.gov/search/concepts/C3050353608-NSIDC_CPRD.html
https://gibs-a.earthdata.nasa.gov/wmts/epsg4326/best/wmts.cgi?TIME=2025-03-01&layer=MODIS_Terra_L3_Snow_Cover_Monthly_Average_Pct&style=default&tilematrixset=2km&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fpng&TileMatrix=0&TileCol=0&TileRow=0
*/
weather::heat_t MapgenEarth::calcBlockHeat(const v3pos_t &p, uint64_t seed,
float timeofday, float totaltime, bool use_weather)
{
#if USE_OSMIUM
const auto ll = pos_to_ll(p);
if (maps_holder->heat_image) {
const auto x = maps_holder->heat_image->width() *
((int(45 + ll.lon + 180) % 360) / 360.0);
const auto y = (std::min<int>(maps_holder->heat_image->height(),
maps_holder->heat_image->width() / 1.6)) *
((90 - ll.lat) / 180);
const auto pixel = maps_holder->heat_image->get_pixel(x, y);
auto heat = rgbToCelsiusJet(pixel->getRed(), pixel->getGreen(), pixel->getBlue());
heat += m_emerge->biomemgr->weather_heat_daily *
(sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-64..0..34
heat += p.Y / m_emerge->biomemgr->weather_heat_height;
if (m_emerge->biomemgr->weather_hot_core &&
p.Y < -(WEATHER_LIMIT - m_emerge->biomemgr->weather_hot_core))
heat += 6000 *
(1.0 - ((float)(p.Y - -WEATHER_LIMIT) /
m_emerge->biomemgr
->weather_hot_core)); //hot core, later via realms
return heat;
}
#endif
return m_emerge->biomemgr->calcBlockHeat(p, seed, timeofday, totaltime, use_weather);
}
// TODO: use cloud data
weather::humidity_t MapgenEarth::calcBlockHumidity(const v3pos_t &p, uint64_t seed,
float timeofday, float totaltime, bool use_weather)
{
return m_emerge->biomemgr->calcBlockHumidity(
p, seed, timeofday, totaltime, use_weather);
}
maps_holder_t::~maps_holder_t()
{
for (const auto &file : files_to_delete) {
#if NDEBUG
std::error_code ec;
std::filesystem::remove(file, ec);
#endif
}
};
+30 -7
View File
@@ -21,6 +21,7 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
@@ -30,6 +31,10 @@ along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
#include "porting.h"
#include "filesys.h"
#include "threading/concurrent_map.h"
#include "threading/concurrent_vector.h"
#include "util/lrucache.hpp"
class PngImage;
typedef core::vector2d<double> v2d;
@@ -64,17 +69,22 @@ class MapgenEarth;
class handler_i
{
public:
virtual void apply() = 0;
virtual void apply(MapgenEarth *) = 0;
};
struct maps_holder_t
{
hgts hgt_reader{porting::path_cache + DIR_DELIM + "earth"};
const std::string data_root {porting::path_cache + DIR_DELIM + "earth"};
hgts hgt_reader{ data_root };
using osm_ptr = std::shared_ptr<handler_i>;
concurrent_shared_map<std::string, osm_ptr> osm_by_path;
concurrent_shared_map<std::string, osm_ptr> osm_bbox;
lru_cache<std::string, osm_ptr, 50> osm_bbox;
std::mutex download_lock;
std::mutex osm_bbox_lock;
std::mutex osm_http_lock;
std::mutex osm_extract_lock;
std::unique_ptr<PngImage> heat_image;
concurrent_shared_vector<std::string> files_to_delete;
~maps_holder_t();
};
class MapgenEarth : public MapgenV7
@@ -105,8 +115,21 @@ public:
pos_t get_height(pos_t x, pos_t z);
ll pos_to_ll(pos_t x, pos_t z);
ll pos_to_ll(const v3pos_t &p);
v2pos_t ll_to_pos(const ll &l);
//v2d ll_to_pos_absolute(const ll &l);
void bresenham(
pos_t xa, pos_t za, pos_t xb, pos_t zb, pos_t y, pos_t h, const MapNode &n);
weather::heat_t calcBlockHeat(const v3pos_t &p, uint64_t seed, float timeofday,
float totaltime, bool use_weather) override;
weather::humidity_t calcBlockHumidity(const v3pos_t &p, uint64_t seed,
float timeofday, float totaltime, bool use_weather) override;
struct Stat
{
std::atomic_int set{};
std::atomic_int miss{};
std::atomic_int level{};
std::atomic_int check{};
std::atomic_int fill{};
void clean() { set = miss = level = check = fill = 0; }
} stat;
};
-1
View File
@@ -330,7 +330,6 @@ int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
return MAX_MAP_GENERATION_LIMIT;
}
void MapgenV7::makeChunk(BlockMakeData *data)
{
// Pre-conditions
+20 -10
View File
@@ -307,36 +307,45 @@ Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 po
}
// Freeminer Weather
s16 BiomeManager::calcBlockHeat(v3pos_t p, uint64_t seed, float timeofday, float totaltime, bool use_weather) {
weather::heat_t BiomeManager::calcBlockHeat(const v3pos_t &p, uint64_t seed,
float timeofday, float totaltime, bool use_weather)
{
//variant 1: full random
//f32 heat = NoisePerlin3D(np_heat, p.X, env->getGameTime()/100, p.Z, seed);
//variant 2: season change based on default heat map
auto heat = NoiseFractal2D(&(mapgen_params->bparams->np_heat), p.X, p.Z, seed); // -30..20..70
auto heat = NoiseFractal2D(
&(mapgen_params->bparams->np_heat), p.X, p.Z, seed); // -30..20..70
// auto heat =calcHeatAtPoint(p);
if (use_weather) {
f32 seasonv = totaltime;
seasonv /= 86400 * year_days; // season change speed
seasonv += (f32)p.X / weather_heat_width; // you can walk to area with other season
seasonv +=
(f32)p.X / weather_heat_width; // you can walk to area with other season
seasonv = sin(seasonv * M_PI);
//heat += (weather_heat_season * (heat < offset ? 2 : 0.5)) * seasonv; // -60..0..30
heat += (weather_heat_season) * seasonv; // -60..0..30
heat += (weather_heat_season)*seasonv; // -60..0..30
// daily change, hotter at sun +4, colder at night -4
heat += weather_heat_daily * (sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-64..0..34
heat += weather_heat_daily *
(sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-64..0..34
}
heat += p.Y / weather_heat_height; // upper=colder, lower=hotter, 3c per 1000
if (weather_hot_core && p.Y < -(WEATHER_LIMIT-weather_hot_core))
heat += 6000 * (1.0-((float)(p.Y - -WEATHER_LIMIT)/weather_hot_core)); //hot core, later via realms
if (weather_hot_core && p.Y < -(WEATHER_LIMIT - weather_hot_core))
heat += 6000 * (1.0 - ((float)(p.Y - -WEATHER_LIMIT) /
weather_hot_core)); //hot core, later via realms
return heat;
}
s16 BiomeManager::calcBlockHumidity(v3pos_t p, uint64_t seed, float timeofday, float totaltime, bool use_weather) {
weather::humidity_t BiomeManager::calcBlockHumidity(const v3pos_t &p, uint64_t seed,
float timeofday, float totaltime, bool use_weather)
{
auto humidity = NoiseFractal2D(&(mapgen_params->bparams->np_humidity), p.X, p.Z, seed);
auto humidity =
NoiseFractal2D(&(mapgen_params->bparams->np_humidity), p.X, p.Z, seed);
// auto humidity = calcHumidityAtPoint(p);
if (use_weather) {
@@ -344,7 +353,8 @@ s16 BiomeManager::calcBlockHumidity(v3pos_t p, uint64_t seed, float timeofday, f
seasonv /= 86400 * weather_humidity_days; // bad weather change speed (2 days)
seasonv += (f32)p.Z / weather_humidity_width;
humidity += weather_humidity_season * sin(seasonv * M_PI);
humidity += weather_humidity_daily * (sin(cycle_shift(timeofday, -0.1) * M_PI) - 0.5);
humidity +=
weather_humidity_daily * (sin(cycle_shift(timeofday, -0.1) * M_PI) - 0.5);
}
humidity += p.Y / weather_humidity_height; // upper=dry, lower=wet, 3c per 1000
+4 -3
View File
@@ -5,6 +5,7 @@
#pragma once
#include "fm_weather.h"
#include "irr_v3d.h"
#include "objdef.h"
#include "nodedef.h"
@@ -245,9 +246,9 @@ public:
s32 weather_humidity_height;
s32 weather_hot_core;
MapgenParams * mapgen_params = nullptr;
s16 calcBlockHeat(v3pos_t p, uint64_t seed, float timeofday, float totaltime, bool use_weather = 1);
s16 calcBlockHumidity(v3pos_t p, uint64_t seed, float timeofday, float totaltime, bool use_weather = 1);
MapgenParams * mapgen_params{};
weather::heat_t calcBlockHeat(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather = 1);
weather::humidity_t calcBlockHumidity(const v3pos_t &p, uint64_t seed, float timeofday, float totaltime, bool use_weather = 1);
//====
BiomeGen *createBiomeGen(BiomeGenType type, BiomeParams *params, v3s16 chunksize)
+12 -3
View File
@@ -22,16 +22,25 @@ IConnection *createMTP(float timeout, bool ipv6, PeerHandler *handler, bool simp
{
constexpr auto MAX_PACKET_SIZE_SINGLEPLAYER = 65000;
// safe minimum across internet networks for ipv4 and ipv6
u32 MAX_PACKET_SIZE = simple_singleplayer_mode ? MAX_PACKET_SIZE_SINGLEPLAYER : 1300;
u32 MAX_PACKET_SIZE = simple_singleplayer_mode ? MAX_PACKET_SIZE_SINGLEPLAYER :
#ifdef _WIN32
512; // TODO: find working maximum?
#else
1350;
#endif
#if USE_MULTI
return new con::ConnectionMulti(MAX_PACKET_SIZE, timeout, ipv6, handler);
#elif USE_ENET
return new con::ConnectionEnet(MAX_PACKET_SIZE, timeout, ipv6, handler);
#elif USE_SCTP
return new con::ConnectionSctp(MAX_PACKET_SIZE, timeout, ipv6, handler);
return new con::ConnectionSctp(
MAX_PACKET_SIZE, timeout, ipv6,
handler);
#elif MINETEST_TRANSPORT
return new con::Connection(MAX_PACKET_SIZE, timeout, ipv6, handler);
return new con::Connection(
MAX_PACKET_SIZE, timeout, ipv6,
handler);
#endif
}
+44 -44
View File
@@ -38,25 +38,25 @@ enum
TOCLIENT_BLOCKDATA_STEP,
TOCLIENT_BLOCKDATA_CONTENT_ONLY,
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM1,
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM2
TOCLIENT_BLOCKDATA_CONTENT_ONLY_PARAM2,
};
enum
{
TOCLIENT_ADDNODE_POS,
TOCLIENT_ADDNODE_NODE,
TOCLIENT_ADDNODE_REMOVE_METADATA
TOCLIENT_ADDNODE_REMOVE_METADATA,
};
enum
{
TOCLIENT_REMOVENODE_POS
TOCLIENT_REMOVENODE_POS,
};
enum
{
// string, serialized inventory
TOCLIENT_INVENTORY_DATA
TOCLIENT_INVENTORY_DATA,
};
enum
@@ -64,13 +64,13 @@ enum
// u16 time (0-23999)
TOCLIENT_TIME_OF_DAY_TIME,
// f32 time_speed
TOCLIENT_TIME_OF_DAY_TIME_SPEED
TOCLIENT_TIME_OF_DAY_TIME_SPEED,
};
enum
{
// string
TOCLIENT_CHAT_MESSAGE_DATA
TOCLIENT_CHAT_MESSAGE_DATA,
};
enum
@@ -78,7 +78,7 @@ enum
// list of ids
TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_REMOVE,
// list of [id, type, initialization_data]
TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_ADD
TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_ADD,
};
struct ActiveObjectAddData
@@ -114,7 +114,7 @@ enum
// f32 pitch
TOCLIENT_MOVE_PLAYER_PITCH,
// f32 yaw
TOCLIENT_MOVE_PLAYER_YAW
TOCLIENT_MOVE_PLAYER_YAW,
// TOCLIENT_MOVE_PLAYER_SPEED
};
@@ -125,7 +125,7 @@ enum
TOCLIENT_ACCESS_DENIED_CUSTOM_STRING,
// u16 command
TOCLIENT_ACCESS_DENIED_REASON,
TOCLIENT_ACCESS_DENIED_RECONNECT
TOCLIENT_ACCESS_DENIED_RECONNECT,
};
#define TOCLIENT_PUNCH_PLAYER 0x11
@@ -140,13 +140,13 @@ enum
// bool set camera point target
TOCLIENT_DEATHSCREEN_SET_CAMERA,
// v3f camera point target (to point the death cause or whatever)
TOCLIENT_DEATHSCREEN_CAMERA_POINT
TOCLIENT_DEATHSCREEN_CAMERA_POINT,
};
enum
{
// vector<pair<name, data>>
TOCLIENT_MEDIA_MEDIA
TOCLIENT_MEDIA_MEDIA,
};
typedef std::vector<std::pair<std::string, std::string>> MediaData;
@@ -154,7 +154,7 @@ typedef std::vector<std::pair<std::string, std::string>> MediaData;
enum
{
TOCLIENT_NODEDEF_DEFINITIONS,
TOCLIENT_NODEDEF_DEFINITIONS_ZIP
TOCLIENT_NODEDEF_DEFINITIONS_ZIP,
};
enum
@@ -162,13 +162,13 @@ enum
// list of [string name, string sha1_digest]
TOCLIENT_ANNOUNCE_MEDIA_LIST,
// string, url of remote media server
TOCLIENT_ANNOUNCE_MEDIA_REMOTE_SERVER
TOCLIENT_ANNOUNCE_MEDIA_REMOTE_SERVER,
};
enum
{
TOCLIENT_ITEMDEF_DEFINITIONS,
TOCLIENT_ITEMDEF_DEFINITIONS_ZIP
TOCLIENT_ITEMDEF_DEFINITIONS_ZIP,
};
typedef std::vector<std::pair<std::string, std::string>> MediaAnnounceList;
@@ -188,25 +188,25 @@ enum
// u16
TOCLIENT_PLAY_SOUND_OBJECT_ID,
// bool
TOCLIENT_PLAY_SOUND_LOOP
TOCLIENT_PLAY_SOUND_LOOP,
};
enum
{
// s32
TOCLIENT_STOP_SOUND_ID
TOCLIENT_STOP_SOUND_ID,
};
enum
{
// list of strings
TOCLIENT_PRIVILEGES_PRIVILEGES
TOCLIENT_PRIVILEGES_PRIVILEGES,
};
enum
{
// string
TOCLIENT_INVENTORY_FORMSPEC_DATA
TOCLIENT_INVENTORY_FORMSPEC_DATA,
};
enum
@@ -238,7 +238,7 @@ enum
TOCLIENT_MOVEMENT_LIQUID_FLUIDITY_SMOOTH,
TOCLIENT_MOVEMENT_LIQUID_SINK,
TOCLIENT_MOVEMENT_GRAVITY,
TOCLIENT_MOVEMENT_FALL_AERODYNAMICS
TOCLIENT_MOVEMENT_FALL_AERODYNAMICS,
};
enum
@@ -278,7 +278,7 @@ enum
enum
{
TOCLIENT_DELETE_PARTICLESPAWNER_ID
TOCLIENT_DELETE_PARTICLESPAWNER_ID,
};
enum
@@ -311,38 +311,38 @@ enum
TOCLIENT_HUDCHANGE_V3F,
TOCLIENT_HUDCHANGE_STRING,
TOCLIENT_HUDCHANGE_U32,
TOCLIENT_HUDCHANGE_V2S32
TOCLIENT_HUDCHANGE_V2S32,
};
enum
{
TOCLIENT_HUD_SET_FLAGS_FLAGS,
TOCLIENT_HUD_SET_FLAGS_MASK
TOCLIENT_HUD_SET_FLAGS_MASK,
};
enum
{
TOCLIENT_HUD_SET_PARAM_ID,
TOCLIENT_HUD_SET_PARAM_VALUE
TOCLIENT_HUD_SET_PARAM_VALUE,
};
enum
{
// u16 breath
TOCLIENT_BREATH_BREATH
TOCLIENT_BREATH_BREATH,
};
enum
{
TOCLIENT_SET_SKY_COLOR,
TOCLIENT_SET_SKY_TYPE,
TOCLIENT_SET_SKY_PARAMS
TOCLIENT_SET_SKY_PARAMS,
};
enum
{
TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_DO,
TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_VALUE
TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_VALUE,
};
enum
@@ -351,13 +351,13 @@ enum
TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALK,
TOCLIENT_LOCAL_PLAYER_ANIMATIONS_DIG,
TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALKDIG,
TOCLIENT_LOCAL_PLAYER_ANIMATIONS_FRAME_SPEED
TOCLIENT_LOCAL_PLAYER_ANIMATIONS_FRAME_SPEED,
};
enum
{
TOCLIENT_EYE_OFFSET_FIRST,
TOCLIENT_EYE_OFFSET_THIRD
TOCLIENT_EYE_OFFSET_THIRD,
};
enum
@@ -366,7 +366,7 @@ enum
TOSERVER_INIT_COMPRESSION,
TOSERVER_INIT_PROTOCOL_VERSION_MIN,
TOSERVER_INIT_PROTOCOL_VERSION_MAX,
TOSERVER_INIT_NAME
TOSERVER_INIT_NAME,
};
enum
@@ -377,7 +377,7 @@ enum
TOSERVER_INIT_LEGACY_PASSWORD,
TOSERVER_INIT_LEGACY_PROTOCOL_VERSION_MIN,
TOSERVER_INIT_LEGACY_PROTOCOL_VERSION_MAX,
TOSERVER_INIT_LEGACY_PROTOCOL_VERSION_FM
TOSERVER_INIT_LEGACY_PROTOCOL_VERSION_FM,
};
enum
@@ -391,66 +391,66 @@ enum
// f32
TOSERVER_PLAYERPOS_YAW,
// u32
TOSERVER_PLAYERPOS_KEY_PRESSED
TOSERVER_PLAYERPOS_KEY_PRESSED,
};
enum
{
TOSERVER_DELETEDBLOCKS_DATA
TOSERVER_DELETEDBLOCKS_DATA,
};
enum
{
TOSERVER_INVENTORY_ACTION_DATA
TOSERVER_INVENTORY_ACTION_DATA,
};
enum
{
TOSERVER_CHAT_MESSAGE_DATA
TOSERVER_CHAT_MESSAGE_DATA,
};
enum
{
TOSERVER_DAMAGE_VALUE
TOSERVER_DAMAGE_VALUE,
};
enum
{
TOSERVER_CHANGE_PASSWORD_OLD,
TOSERVER_CHANGE_PASSWORD_NEW
TOSERVER_CHANGE_PASSWORD_NEW,
};
enum
{
TOSERVER_PLAYERITEM_VALUE
TOSERVER_PLAYERITEM_VALUE,
};
enum
{
TOSERVER_REMOVED_SOUNDS_IDS
TOSERVER_REMOVED_SOUNDS_IDS,
};
enum
{
TOSERVER_NODEMETA_FIELDS_POS,
TOSERVER_NODEMETA_FIELDS_FORMNAME,
TOSERVER_NODEMETA_FIELDS_DATA
TOSERVER_NODEMETA_FIELDS_DATA,
};
enum
{
TOSERVER_INVENTORY_FIELDS_FORMNAME,
TOSERVER_INVENTORY_FIELDS_DATA
TOSERVER_INVENTORY_FIELDS_DATA,
};
enum
{
TOSERVER_REQUEST_MEDIA_FILES
TOSERVER_REQUEST_MEDIA_FILES,
};
enum
{
TOSERVER_BREATH_VALUE
TOSERVER_BREATH_VALUE,
};
enum
@@ -465,7 +465,7 @@ enum
*/
TOSERVER_INTERACT_ACTION,
TOSERVER_INTERACT_ITEM,
TOSERVER_INTERACT_POINTED_THING
TOSERVER_INTERACT_POINTED_THING,
};
enum
@@ -474,7 +474,7 @@ enum
TOSERVER_CLIENT_READY_VERSION_MINOR,
TOSERVER_CLIENT_READY_VERSION_PATCH,
TOSERVER_CLIENT_READY_VERSION_STRING,
TOSERVER_CLIENT_READY_VERSION_TWEAK
TOSERVER_CLIENT_READY_VERSION_TWEAK,
};
// freeminer only packets
+2
View File
@@ -223,7 +223,9 @@ bool detectVSCodeBuildDir(const std::string &path)
"out/build/Debug",
"out/build/Build",
"out/build/asan",
"out/build/asan_debug",
"out/build/tsan",
"out/build/tsan_debug",
"out/build/msan",
"out/build/ubsan",
"out/build/gperf",
+8 -1
View File
@@ -1512,6 +1512,9 @@ void Server::yieldToOtherThreads(float dtime)
PlayerSAO *Server::StageTwoClientInit(session_t peer_id)
{
uint16_t net_proto_version_fm{};
std::string full_version;
std::string playername;
std::unique_ptr<PlayerSAO> sao;
{
@@ -1520,6 +1523,8 @@ PlayerSAO *Server::StageTwoClientInit(session_t peer_id)
if (client) {
playername = client->getName();
sao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
net_proto_version_fm = client->net_proto_version_fm;
full_version = client->getFullVer();
}
}
@@ -1585,7 +1590,9 @@ PlayerSAO *Server::StageTwoClientInit(session_t peer_id)
std::string ip_str = getPeerAddress(player->getPeerId()).serializeString();
const auto &names = m_clients.getPlayerNames();
actionstream << player->getName() << " [" << ip_str << "] (" << player->protocol_version << ") joins game. List of players: ";
actionstream << player->getName() << " [" << ip_str << "] ("
<< player->protocol_version << " : " << net_proto_version_fm << " : "
<< full_version << ") joins game. List of players: ";
for (const std::string &name : names)
actionstream << name << " ";
actionstream << player->getName() << std::endl;
+6 -5
View File
@@ -336,7 +336,8 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
}
for (auto &changed_block : *changed_blocks) {
MapBlock *block = changed_block.second;
const auto block = getBlock(changed_block.first); // very bad, changed_block should contain MapBlockPtr
//MapBlock *block = changed_block.second;
if (!block)
continue;
/*
@@ -349,8 +350,8 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
if (save_generated_block)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_EXPIRE_IS_AIR, false);
else
block->setLightingComplete(0);
block->setLightingComplete(0);
}
auto *senv = &((Server *)m_gamedef)->getEnv();
@@ -379,9 +380,9 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
// of LBMs and other stuff.
block->setTimestampNoChangedFlag(now);
}
updateBlockHeat(senv, bp * MAP_BLOCKSIZE, block);
updateBlockHeat(senv, bp * MAP_BLOCKSIZE, block);
updateBlockHumidity(senv, bp * MAP_BLOCKSIZE, block);
changed_blocks_for_merge.emplace(bp);
}
m_chunks_in_progress.erase(bpmin);
+7 -9
View File
@@ -4,6 +4,7 @@
#pragma once
#include "fm_weather.h"
#include "irr_v3d.h"
#include "mapblock.h"
#include "threading/concurrent_set.h"
@@ -50,15 +51,12 @@ class ServerMap : public Map
{
public:
// freeminer:
using humidity_t = s16;
using heat_t = s16;
virtual heat_t updateBlockHeat(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block = nullptr, unordered_map_v3pos<heat_t> *cache = nullptr,
// freeminer:
virtual weather::heat_t updateBlockHeat(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block = nullptr, unordered_map_v3bpos<weather::heat_t> *cache = nullptr,
bool block_add = true);
virtual humidity_t updateBlockHumidity(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block = nullptr, unordered_map_v3pos<humidity_t> *cache = nullptr,
virtual weather::humidity_t updateBlockHumidity(ServerEnvironment *env, const v3pos_t &p,
MapBlock *block = nullptr, unordered_map_v3bpos<weather::humidity_t> *cache = nullptr,
bool block_add = true);
size_t transforming_liquid_size();
@@ -85,7 +83,7 @@ public:
std::mutex m_lighting_modified_mutex;
std::map<v3bpos_t, int> m_lighting_modified_blocks;
std::map<unsigned int, lighting_map_t> m_lighting_modified_blocks_range;
void lighting_modified_add(const v3pos_t &pos, int range = 5);
void lighting_modified_add(const v3bpos_t &pos, int range = 5);
void unspreadLight(enum LightBank bank, std::map<v3pos_t, u8> &from_nodes,
std::set<v3pos_t> &light_sources,
+279
View File
@@ -0,0 +1,279 @@
// https://github.com/Guiorgy/cpp-lru-cache/blob/std-only/include/lrucache.hpp
/*
** File: lrucache.hpp
**
** Author: Alexander Ponomarev
** Created on June 20, 2013, 5:09 PM
**
** Author: Guiorgy
** Forked on October 23, 2024
*/
#pragma once
#include <unordered_map>
#include <functional>
#include <optional>
#include <utility>
#include <tuple>
#include <list>
// A helper macro that determines whether a specific attribute is supported by the current compiler. If __has_cpp_attribute is not defined, __cplusplus alone is used as a fallback.
#ifdef __has_cpp_attribute
#define GUIORGY_ATTRIBUTE_AVAILABLE(attribute_token, test_value, cpp_version) \
(__has_cpp_attribute(attribute_token) >= test_value && __cplusplus >= cpp_version)
#else
#define GUIORGY_ATTRIBUTE_AVAILABLE(attribute_token, test_value, cpp_version) \
(__cplusplus >= cpp_version)
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wreserved-attribute-identifier"
#endif
#if !GUIORGY_ATTRIBUTE_AVAILABLE(nodiscard, 201907L, 202002L)
#ifdef nodiscard
#define GUIORGY_nodiscard_BEFORE
#undef nodiscard
#endif
#define nodiscard(explanation) nodiscard
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
template<typename key_t, typename value_t, const std::size_t max_size>
class lru_cache final {
static_assert(max_size > 0);
typedef typename std::pair<key_t, value_t> key_value_pair_t;
typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
typedef typename std::list<key_value_pair_t>::reverse_iterator list_reverse_iterator_t;
typedef typename std::unordered_map<key_t, list_iterator_t>::iterator map_iterator_t;
public:
typedef typename std::list<key_value_pair_t>::const_iterator iterator;
typedef typename std::list<key_value_pair_t>::const_iterator const_iterator;
typedef typename std::list<key_value_pair_t>::const_reverse_iterator reverse_iterator;
typedef typename std::list<key_value_pair_t>::const_reverse_iterator const_reverse_iterator;
private:
std::list<key_value_pair_t> _cache_items_list;
std::unordered_map<key_t, list_iterator_t> _cache_items_map;
public:
lru_cache() = default;
~lru_cache() = default;
lru_cache(const lru_cache& other) {
_cache_items_list = other._cache_items_list;
_cache_items_map.reserve(_cache_items_list.size());
for (list_iterator_t it = _cache_items_list.begin(); it != _cache_items_list.end(); ++it) {
_cache_items_map.emplace_hint(_cache_items_map.end(), it->first, it);
}
}
lru_cache(lru_cache&&) = default;
lru_cache& operator=(lru_cache const& other) {
_cache_items_list = other._cache_items_list;
_cache_items_map.reserve(_cache_items_list.size());
for (list_iterator_t it = _cache_items_list.begin(); it != _cache_items_list.end(); ++it) {
_cache_items_map.emplace_hint(_cache_items_map.end(), it->first, it);
}
return *this;
}
lru_cache& operator=(lru_cache &&) = default;
private:
void put(const key_t& key) {
map_iterator_t it = _cache_items_map.find(key);
if (it != _cache_items_map.end()) {
_cache_items_list.erase(it->second);
it->second = _cache_items_list.begin();
} else {
_cache_items_map.emplace_hint(it, key, _cache_items_list.begin());
}
if (_cache_items_map.size() > max_size) {
list_reverse_iterator_t last = _cache_items_list.rbegin();
_cache_items_map.erase(last->first);
_cache_items_list.pop_back();
}
}
public:
void put(const key_t& key, const value_t& value) {
_cache_items_list.emplace_front(key, value);
put(key);
}
void put(const key_t& key, value_t&& value) {
_cache_items_list.emplace_front(key, std::move(value));
put(key);
}
template<typename... ValueArgs>
const value_t& emplace(const key_t& key, ValueArgs&&... value_args) {
const value_t& value = _cache_items_list.emplace_front(
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(std::forward<ValueArgs>(value_args)...)
).second;
put(key);
return value;
}
[[nodiscard("Use touch(const key_t& key) instead if all you want is to push the key to the bottom of the removal order")]] const std::optional<value_t> get(const key_t& key) {
map_iterator_t it = _cache_items_map.find(key);
if (it == _cache_items_map.end()) {
return std::nullopt;
} else {
if (it->second != _cache_items_list.begin()) {
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
}
return it->second->second;
}
}
[[nodiscard("Use touch(const key_t& key) instead if all you want is to push the key to the bottom of the removal order")]] const std::optional<std::reference_wrapper<const value_t>> get_ref(const key_t& key) {
map_iterator_t it = _cache_items_map.find(key);
if (it == _cache_items_map.end()) {
return std::nullopt;
} else {
if (it->second != _cache_items_list.begin()) {
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
}
return std::make_optional(std::cref(it->second->second));
}
}
[[nodiscard("Use touch(const key_t& key) instead if all you want is to push the key to the bottom of the removal order")]] bool try_get(const key_t& key, value_t& value_out) {
map_iterator_t it = _cache_items_map.find(key);
if (it == _cache_items_map.end()) {
return false;
} else {
if (it->second != _cache_items_list.begin()) {
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
}
value_out = it->second->second;
return true;
}
}
[[nodiscard("Use touch(const key_t& key) instead if all you want is to push the key to the bottom of the removal order")]] bool try_get_ref(const key_t& key, const value_t*& value_out) {
map_iterator_t it = _cache_items_map.find(key);
if (it == _cache_items_map.end()) {
value_out = nullptr;
return false;
} else {
if (it->second != _cache_items_list.begin()) {
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
}
value_out = &(it->second->second);
return true;
}
}
bool touch(const key_t& key) {
map_iterator_t it = _cache_items_map.find(key);
if (it == _cache_items_map.end()) {
return false;
} else {
if (it->second != _cache_items_list.begin()) {
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
}
return true;
}
}
bool remove(const key_t& key) {
map_iterator_t it = _cache_items_map.find(key);
if (it != _cache_items_map.end()) {
_cache_items_list.erase(it->second);
_cache_items_map.erase(it);
return true;
} else {
return false;
}
}
[[nodiscard]] bool exists(const key_t& key) const {
return _cache_items_map.find(key) != _cache_items_map.end();
}
[[nodiscard]] bool contains(const key_t& key) const {
return _cache_items_map.find(key) != _cache_items_map.end();
}
[[nodiscard]] std::size_t size() const noexcept {
return _cache_items_map.size();
}
void clear() noexcept {
_cache_items_map.clear();
_cache_items_list.clear();
}
[[nodiscard]] const_iterator cbegin() const noexcept {
return _cache_items_list.cbegin();
}
[[nodiscard]] const_iterator begin() const noexcept {
return cbegin();
}
[[nodiscard]] const_iterator cend() const noexcept {
return _cache_items_list.cend();
}
[[nodiscard]] const_iterator end() const noexcept {
return cend();
}
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
return _cache_items_list.crbegin();
}
[[nodiscard]] const_iterator rbegin() const noexcept {
return crbegin();
}
[[nodiscard]] const_reverse_iterator crend() const noexcept {
return _cache_items_list.crend();
}
[[nodiscard]] const_iterator rend() const noexcept {
return crend();
}
};
// Restore nodiscard if it was already defined, otherwise undefine it
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wreserved-attribute-identifier"
#endif
#ifdef GUIORGY_nodiscard_BEFORE
#undef nodiscard
#define nodiscard GUIORGY_nodiscard_BEFORE
#undef GUIORGY_nodiscard_BEFORE
#else
#ifdef nodiscard
#undef nodiscard
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
// Cleanup of internal macros.
#undef GUIORGY_ATTRIBUTE_AVAILABLE
+5 -3
View File
@@ -83,7 +83,8 @@ $0 ----world_sand
$0 -mg_name=earth -mg_earth='{"center":{"z":36.822183, "y":0, "x":30.583390}}' bot
#$0 -mg_name=earth -mg_earth='{"scale":{"z":10000, "y":0.01, "x":10000}}' bot
$0 -mg_name=earth -mg_earth='{"scale":{"z":10000, "y":100, "x":10000}}' bot
$0 -mg_name=earth -mg_earth='{"center":{"z":27.9878279,"y":0,"x":86.923833}}' -static_spawnpoint='(130,8842,56)' bot # everest
$0 -mg_name=earth -mg_earth='{"center":{"z":27.9878279,"y":0,"x":86.923833}}' -static_spawnpoint='(130,8842,56)' bot # Everest
$0 -mg_name=earth -mg_earth='{"center":{"z":22.28422,"x":114.15996,"y":0} }' bot # HongKong
$0 ---cmake_minetest=1 ---build_name=_minetest ----headless ----headless_optimize --address=cool.server.org --port=30001 ---clients_num=25 clients
@@ -214,7 +215,8 @@ our $options = {
profiler_max_page => 1,
profiler_page => 1,
debug_log_level => 'info',
movement_speed_fast => 10000,
movement_speed_fast => 100000,
movement_acceleration_fast => 100,
max_block_send_distance => 100,
default_privs => 'interact, shout, teleport, settime, privs, fly, noclip, fast, debug',
default_privs_creative => 'interact, shout, teleport, settime, privs, fly, noclip, fast, debug',
@@ -412,7 +414,7 @@ $commands = {
file_append(
"$config->{logdir}/run.sh",
join "\n",
qq{# } . join(' ', $0, map { /[\s"]/ ? "'" . $_ . "'" : $_ } @ARGV),
qq{# } . join(' ', $0, map { /[()\s"]/ ? "'" . $_ . "'" : $_ } @ARGV),
qq{cd "$build_dir"},
""
);