mirror of
https://github.com/bdnugget/freeminer.git
synced 2026-11-07 06:57:27 +00:00
Merge branch 'wip5.13.0' into wip5.14.0
This commit is contained in:
commit
af784e500e
50 files changed
+1423
-456
No files matched your search
+1
-1
@@ -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
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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:
|
||||
+1
-1
Submodule games/default updated: d9f6ce1909...d99b96e652.
+3
-12
@@ -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}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -252,8 +252,7 @@ public:
|
||||
m_animation_force_timer--;
|
||||
}
|
||||
|
||||
|
||||
// fm:
|
||||
// fm:
|
||||
/*u32 getUsageTimer() {
|
||||
return m_usage_timer;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+1
-1
Submodule src/external/websocketpp updated: 4dfe1be74e...d116480cbd.
+7
-4
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace weather
|
||||
{
|
||||
using humidity_t = int16_t;
|
||||
using heat_t = int16_t;
|
||||
}
|
||||
+69
-17
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
Submodule src/mapgen/earth/arnis-cpp updated: 6633c9e3b5...a514e6b9ff.
@@ -6,4 +6,5 @@ XZ::operator XZPoint()
|
||||
{
|
||||
return XZPoint{X, Y};
|
||||
}
|
||||
const std::vector<ProcessedNode> ProcessedElement::dummy_nodes;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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
@@ -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
@@ -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 ¶ms = mg_params->params;
|
||||
const Json::Value ¶ms = 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
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -330,7 +330,6 @@ int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
|
||||
return MAX_MAP_GENERATION_LIMIT;
|
||||
}
|
||||
|
||||
|
||||
void MapgenV7::makeChunk(BlockMakeData *data)
|
||||
{
|
||||
// Pre-conditions
|
||||
|
||||
+20
-10
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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"},
|
||||
""
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user