From 1771b8c9a17587fdc6f58c5299c9547cfbc76e40 Mon Sep 17 00:00:00 2001 From: Lars Date: Tue, 3 Jun 2025 16:28:19 -0700 Subject: [PATCH] Remove MapSector, take 2 --- src/CMakeLists.txt | 1 - src/client/client.cpp | 6 +- src/client/clientmap.cpp | 260 +++++++++++----------------- src/client/clientmap.h | 5 - src/database/database-sqlite3.cpp | 1 - src/dummymap.h | 10 +- src/map.cpp | 184 +++++++++----------- src/map.h | 36 ++-- src/mapsector.cpp | 125 ------------- src/mapsector.h | 85 --------- src/network/clientpackethandler.cpp | 13 +- src/servermap.cpp | 145 ++++------------ src/servermap.h | 8 - src/voxelalgorithms.cpp | 6 +- 14 files changed, 236 insertions(+), 649 deletions(-) delete mode 100644 src/mapsector.cpp delete mode 100644 src/mapsector.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc87ca070..83decabf3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -463,7 +463,6 @@ set(common_SRCS map.cpp mapblock.cpp mapnode.cpp - mapsector.cpp nodedef.cpp pathfinder.cpp player.cpp diff --git a/src/client/client.cpp b/src/client/client.cpp index 02e1805af..90aa33aa1 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -31,7 +31,6 @@ #include "filesys.h" #include "mapblock_mesh.h" #include "mapblock.h" -#include "mapsector.h" #include "minimap.h" #include "modchannels.h" #include "content/mods.h" @@ -589,15 +588,14 @@ void Client::step(float dtime) bool do_mapper_update = true; ClientMap &map = m_env.getClientMap(); - MapSector *sector = map.emergeSector(v2s16(r.p.X, r.p.Z)); - MapBlock *block = sector->getBlockNoCreateNoEx(r.p.Y); + MapBlock *block = map.getBlockNoCreateNoEx(r.p); // The block in question is not visible (perhaps it is culled at the server), // create a blank block just to hold the chunk's mesh. // If the block becomes visible later it will replace the blank block. if (!block && r.mesh) - block = sector->createBlankBlock(r.p.Y); + block = map.createBlankBlock(r.p); if (block) { // Delete the old mesh diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index aad5c700d..face1861a 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -9,7 +9,6 @@ #include #include #include -#include "mapsector.h" #include "mapblock.h" #include "nodedef.h" #include "profiler.h" @@ -239,20 +238,6 @@ void ClientMap::updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset, video::SCo } } -MapSector * ClientMap::emergeSector(v2s16 p2d) -{ - // Check that it doesn't exist already - MapSector *sector = getSectorNoGenerate(p2d); - - // Create it if it does not exist yet - if (!sector) { - sector = new MapSector(this, p2d, m_gamedef); - m_sectors[p2d] = sector; - } - - return sector; -} - void ClientMap::OnRegisterSceneNode() { if(IsVisible) @@ -409,91 +394,75 @@ void ClientMap::updateDrawList() frustum and display them. */ if (m_control.range_all || m_loops_occlusion_culler) { - // Number of blocks currently loaded by the client - u32 blocks_loaded = 0; // Number of blocks with mesh in rendering range u32 blocks_in_range_with_mesh = 0; - MapBlockVect sectorblocks; + // Loop through all blocks + for (const auto &entry : m_blocks) { + MapBlock *block = entry.second; + MapBlockMesh *mesh = block->mesh; - for (auto §or_it : m_sectors) { - const MapSector *sector = sector_it.second; - v2s16 sp = sector->getPos(); + // Calculate the coordinates for range and frustum culling + v3f mesh_sphere_center; + f32 mesh_sphere_radius; - blocks_loaded += sector->size(); - if (!m_control.range_all) { - if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || - sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) - continue; + v3s16 block_pos_nodes = block->getPosRelative(); + + if (mesh) { + mesh_sphere_center = intToFloat(block_pos_nodes, BS) + + mesh->getBoundingSphereCenter(); + mesh_sphere_radius = mesh->getBoundingRadius(); + } else { + mesh_sphere_center = intToFloat(block_pos_nodes, BS) + + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS); + mesh_sphere_radius = 0.0f; } - // Loop through blocks in sector - for (const auto &entry : sector->getBlocks()) { - MapBlock *block = entry.second.get(); - MapBlockMesh *mesh = block->mesh; + // First, perform a simple distance check. + if (!m_control.range_all && + mesh_sphere_center.getDistanceFrom(m_camera_position) > + m_control.wanted_range * BS + mesh_sphere_radius) + continue; // Out of range, skip. - // Calculate the coordinates for range and frustum culling - v3f mesh_sphere_center; - f32 mesh_sphere_radius; + // Keep the block alive as long as it is in range. + block->resetUsageTimer(); + blocks_in_range_with_mesh++; - v3s16 block_pos_nodes = block->getPosRelative(); + // Frustum culling + // Only do coarse culling here, to account for fast camera movement. + // This is needed because this function is not called every frame. + float frustum_cull_extra_radius = 300.0f; + if (is_frustum_culled(mesh_sphere_center, + mesh_sphere_radius + frustum_cull_extra_radius)) { + blocks_frustum_culled++; + continue; + } - if (mesh) { - mesh_sphere_center = intToFloat(block_pos_nodes, BS) - + mesh->getBoundingSphereCenter(); - mesh_sphere_radius = mesh->getBoundingRadius(); - } else { - mesh_sphere_center = intToFloat(block_pos_nodes, BS) - + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS); - mesh_sphere_radius = 0.0f; - } + // Raytraced occlusion culling - send rays from the camera to the block's corners + if (!m_control.range_all && occlusion_culling_enabled && m_enable_raytraced_culling && + mesh && + isMeshOccluded(block, mesh_grid.cell_size, cam_pos_nodes)) { + blocks_occlusion_culled++; + continue; + } - // First, perform a simple distance check. - if (!m_control.range_all && - mesh_sphere_center.getDistanceFrom(m_camera_position) > - m_control.wanted_range * BS + mesh_sphere_radius) - continue; // Out of range, skip. - - // Keep the block alive as long as it is in range. - block->resetUsageTimer(); - blocks_in_range_with_mesh++; - - // Frustum culling - // Only do coarse culling here, to account for fast camera movement. - // This is needed because this function is not called every frame. - float frustum_cull_extra_radius = 300.0f; - if (is_frustum_culled(mesh_sphere_center, - mesh_sphere_radius + frustum_cull_extra_radius)) { - blocks_frustum_culled++; - continue; - } - - // Raytraced occlusion culling - send rays from the camera to the block's corners - if (!m_control.range_all && occlusion_culling_enabled && m_enable_raytraced_culling && - mesh && - isMeshOccluded(block, mesh_grid.cell_size, cam_pos_nodes)) { - blocks_occlusion_culled++; - continue; - } - - if (mesh_grid.cell_size > 1) { - // Block meshes are stored in the corner block of a chunk - // (where all coordinate are divisible by the chunk size) - // Add them to the de-dup set. - shortlist.emplace(mesh_grid.getMeshPos(block->getPos())); - // All other blocks we can grab and add to the keeplist right away. - m_keeplist.push_back(block); - block->refGrab(); - } else if (mesh) { - // without mesh chunking we can add the block to the drawlist - block->refGrab(); - m_drawlist.emplace(block->getPos(), block); - } + if (mesh_grid.cell_size > 1) { + // Block meshes are stored in the corner block of a chunk + // (where all coordinate are divisible by the chunk size) + // Add them to the de-dup set. + shortlist.emplace(mesh_grid.getMeshPos(block->getPos())); + // All other blocks we can grab and add to the keeplist right away. + m_keeplist.push_back(block); + block->refGrab(); + } else if (mesh) { + // without mesh chunking we can add the block to the drawlist + block->refGrab(); + m_drawlist.emplace(block->getPos(), block); } } g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh); - g_profiler->avg("MapBlocks loaded [#]", blocks_loaded); + g_profiler->avg("MapBlocks loaded [#]", m_blocks.size()); } else { // Blocks visited by the algorithm u32 blocks_visited = 0; @@ -529,10 +498,7 @@ void ClientMap::updateDrawList() blocks_visited++; - // Get the sector, block and mesh - MapSector *sector = this->getSectorNoGenerate(v2s16(block_coord.X, block_coord.Z)); - - MapBlock *block = sector ? sector->getBlockNoCreateNoEx(block_coord.Y) : nullptr; + MapBlock *block = getBlockNoCreateNoEx(block_coord); MapBlockMesh *mesh = block ? block->mesh : nullptr; @@ -729,60 +695,42 @@ void ClientMap::touchMapBlocks() v3s16 p_blocks_max; getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max); - // Number of blocks currently loaded by the client - u32 blocks_loaded = 0; // Number of blocks with mesh in rendering range u32 blocks_in_range_with_mesh = 0; - for (const auto §or_it : m_sectors) { - const MapSector *sector = sector_it.second; - v2s16 sp = sector->getPos(); + for (const auto &entry : m_blocks) { + MapBlock *block = entry.second; + MapBlockMesh *mesh = block->mesh; - blocks_loaded += sector->size(); - if (!m_control.range_all) { - if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || - sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) - continue; + // Calculate the coordinates for range and frustum culling + v3f mesh_sphere_center; + f32 mesh_sphere_radius; + + v3s16 block_pos_nodes = block->getPosRelative(); + + if (mesh) { + mesh_sphere_center = intToFloat(block_pos_nodes, BS) + + mesh->getBoundingSphereCenter(); + mesh_sphere_radius = mesh->getBoundingRadius(); + } else { + mesh_sphere_center = intToFloat(block_pos_nodes, BS) + + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS); + mesh_sphere_radius = 0.0f; } - /* - Loop through blocks in sector - */ + // First, perform a simple distance check. + if (!m_control.range_all && + mesh_sphere_center.getDistanceFrom(m_camera_position) > + m_control.wanted_range * BS + mesh_sphere_radius) + continue; // Out of range, skip. - for (const auto &entry : sector->getBlocks()) { - MapBlock *block = entry.second.get(); - MapBlockMesh *mesh = block->mesh; - - // Calculate the coordinates for range and frustum culling - v3f mesh_sphere_center; - f32 mesh_sphere_radius; - - v3s16 block_pos_nodes = block->getPosRelative(); - - if (mesh) { - mesh_sphere_center = intToFloat(block_pos_nodes, BS) - + mesh->getBoundingSphereCenter(); - mesh_sphere_radius = mesh->getBoundingRadius(); - } else { - mesh_sphere_center = intToFloat(block_pos_nodes, BS) - + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS); - mesh_sphere_radius = 0.0f; - } - - // First, perform a simple distance check. - if (!m_control.range_all && - mesh_sphere_center.getDistanceFrom(m_camera_position) > - m_control.wanted_range * BS + mesh_sphere_radius) - continue; // Out of range, skip. - - // Keep the block alive as long as it is in range. - block->resetUsageTimer(); - blocks_in_range_with_mesh++; - } + // Keep the block alive as long as it is in range. + block->resetUsageTimer(); + blocks_in_range_with_mesh++; } g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh); - g_profiler->avg("MapBlocks loaded [#]", blocks_loaded); + g_profiler->avg("MapBlocks loaded [#]", m_blocks.size()); } void MeshBufListMaps::addFromBlock(v3s16 block_pos, MapBlockMesh *block_mesh, @@ -1532,48 +1480,36 @@ void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, } m_drawlist_shadow.clear(); - // Number of blocks currently loaded by the client - u32 blocks_loaded = 0; // Number of blocks with mesh in rendering range u32 blocks_in_range_with_mesh = 0; - for (auto §or_it : m_sectors) { - const MapSector *sector = sector_it.second; - if (!sector) + for (const auto &entry : m_blocks) { + MapBlock *block = entry.second; + MapBlockMesh *mesh = block->mesh; + if (!mesh) { + // Ignore if mesh doesn't exist continue; - blocks_loaded += sector->size(); + } - /* - Loop through blocks in sector - */ - for (const auto &entry : sector->getBlocks()) { - MapBlock *block = entry.second.get(); - MapBlockMesh *mesh = block->mesh; - if (!mesh) { - // Ignore if mesh doesn't exist - continue; - } + v3f block_pos = intToFloat(block->getPosRelative(), BS) + mesh->getBoundingSphereCenter(); + v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos); + if (projection.getDistanceFrom(block_pos) > (radius + mesh->getBoundingRadius())) + continue; - v3f block_pos = intToFloat(block->getPosRelative(), BS) + mesh->getBoundingSphereCenter(); - v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos); - if (projection.getDistanceFrom(block_pos) > (radius + mesh->getBoundingRadius())) - continue; + blocks_in_range_with_mesh++; - blocks_in_range_with_mesh++; + // This block is in range. Reset usage timer. + block->resetUsageTimer(); - // This block is in range. Reset usage timer. - block->resetUsageTimer(); - - // Add to set - if (m_drawlist_shadow.emplace(block->getPos(), block).second) { - block->refGrab(); - } + // Add to set + if (m_drawlist_shadow.emplace(block->getPos(), block).second) { + block->refGrab(); } } g_profiler->avg("SHADOW MapBlock meshes in range [#]", blocks_in_range_with_mesh); g_profiler->avg("SHADOW MapBlocks drawn [#]", m_drawlist_shadow.size()); - g_profiler->avg("SHADOW MapBlocks loaded [#]", blocks_loaded); + g_profiler->avg("SHADOW MapBlocks loaded [#]", m_blocks.size()); } void ClientMap::reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) diff --git a/src/client/clientmap.h b/src/client/clientmap.h index daa9d80f1..7ac5514f2 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -69,11 +69,6 @@ public: void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset, video::SColor light_color); - /* - Forcefully get a sector from somewhere - */ - MapSector * emergeSector(v2s16 p) override; - /* ISceneNode methods */ diff --git a/src/database/database-sqlite3.cpp b/src/database/database-sqlite3.cpp index cb5dcf5f4..5352c7cc3 100644 --- a/src/database/database-sqlite3.cpp +++ b/src/database/database-sqlite3.cpp @@ -239,7 +239,6 @@ void MapDatabaseSQLite3::createDatabase() // Declaring a primary key automatically creates an index and the // order largely dictates which range operations can be sped up. // see also: - // Putting XZ before Y matches our MapSector abstraction. "PRIMARY KEY (`x`, `z`, `y`)" ");\n" ; diff --git a/src/dummymap.h b/src/dummymap.h index 408f91341..273208437 100644 --- a/src/dummymap.h +++ b/src/dummymap.h @@ -5,7 +5,6 @@ #pragma once #include "map.h" -#include "mapsector.h" class DummyMap : public Map { @@ -13,12 +12,9 @@ public: DummyMap(IGameDef *gamedef, v3s16 bpmin, v3s16 bpmax): Map(gamedef) { for (s16 z = bpmin.Z; z <= bpmax.Z; z++) - for (s16 x = bpmin.X; x <= bpmax.X; x++) { - v2s16 p2d(x, z); - MapSector *sector = new MapSector(this, p2d, gamedef); - m_sectors[p2d] = sector; - for (s16 y = bpmin.Y; y <= bpmax.Y; y++) - sector->createBlankBlock(y); + for (s16 x = bpmin.X; x <= bpmax.X; x++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) { + createBlankBlock(v3s16(x, y, z)); } } diff --git a/src/map.cpp b/src/map.cpp index 964d8b5af..1b3e800da 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3,7 +3,6 @@ // Copyright (C) 2010-2013 celeron55, Perttu Ahola #include "map.h" -#include "mapsector.h" #include "mapblock.h" #include "voxel.h" #include "voxelalgorithms.h" @@ -31,10 +30,10 @@ Map::Map(IGameDef *gamedef): Map::~Map() { /* - Free all MapSectors + Free all MapBlocks */ - for (auto §or : m_sectors) { - delete sector.second; + for (auto &entry : m_blocks) { + delete entry.second; } } @@ -55,40 +54,61 @@ void Map::dispatchEvent(const MapEditEvent &event) } } -MapSector * Map::getSectorNoGenerateNoLock(v2s16 p) +MapBlock* Map::createBlankBlockNoInsert(v3s16 p) { - if(m_sector_cache != NULL && p == m_sector_cache_p){ - MapSector * sector = m_sector_cache; - return sector; - } + if (blockpos_over_max_limit(v3s16(p))) + throw InvalidPositionException("createBlankBlockNoInsert(): pos over max mapgen limit"); - auto n = m_sectors.find(p); - - if (n == m_sectors.end()) - return NULL; - - MapSector *sector = n->second; - - // Cache the last result - m_sector_cache_p = p; - m_sector_cache = sector; - - return sector; + return new MapBlock(p, m_gamedef); } -MapSector *Map::getSectorNoGenerate(v2s16 p) +MapBlock *Map::createBlankBlock(v3s16 p) { - return getSectorNoGenerateNoLock(p); + MapBlock *block = createBlankBlockNoInsert(p); + + m_blocks[p] = block; + + return block; +} + +void Map::deleteBlockImmediate(MapBlock *block) +{ + detachBlock(block); + // returned smart-ptr is dropped +} + +std::unique_ptr Map::detachBlock(MapBlock *block) +{ + // Remove from container + auto it = m_blocks.find(block->getPos()); + assert(it != m_blocks.end()); + std::unique_ptr ret(it->second); + assert(ret.get() == block); + m_blocks.erase(it); + + // Mark as removed + block->makeOrphan(); + + return ret; +} + +void Map::insertBlock(MapBlock *block) +{ + v3s16 pos = block->getPos(); + + MapBlock *block2 = getBlockNoCreateNoEx(pos); + if (block2) { + throw AlreadyExistsException("Block already exists"); + } + + // Insert into container + m_blocks[pos] = block; } MapBlock *Map::getBlockNoCreateNoEx(v3s16 p3d) { - v2s16 p2d(p3d.X, p3d.Z); - MapSector *sector = getSectorNoGenerate(p2d); - if (!sector) - return nullptr; - MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y); - return block; + auto it = m_blocks.find(p3d); + return it != m_blocks.end() ? it->second : nullptr; } MapBlock *Map::getBlockNoCreate(v3s16 p3d) @@ -256,11 +276,9 @@ bool Map::removeNodeWithEvent(v3s16 p) } struct TimeOrderedMapBlock { - MapSector *sect; MapBlock *block; - TimeOrderedMapBlock(MapSector *sect, MapBlock *block) : - sect(sect), + TimeOrderedMapBlock(MapBlock *block) : block(block) {} @@ -281,7 +299,6 @@ void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, // Profile modified reasons Profiler modprofiler; - std::vector sector_deletion_queue; u32 deleted_blocks_count = 0; u32 saved_blocks_count = 0; u32 block_count_all = 0; @@ -292,62 +309,44 @@ void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, // If there is no practical limit, we spare creation of mapblock_queue if (max_loaded_blocks < 0) { - MapBlockVect blocks; - for (auto §or_it : m_sectors) { - MapSector *sector = sector_it.second; + for (auto it = m_blocks.begin(); it != m_blocks.end();) { + MapBlock *block = it->second; + block->incrementUsageTimer(dtime); - bool all_blocks_deleted = true; + if (block->refGet() == 0 + && block->getUsageTimer() > unload_timeout) { + v3s16 p = block->getPos(); - blocks.clear(); - sector->getBlocks(blocks); - - for (MapBlock *block : blocks) { - block->incrementUsageTimer(dtime); - - if (block->refGet() == 0 - && block->getUsageTimer() > unload_timeout) { - v3s16 p = block->getPos(); - - // Save if modified - if (block->getModified() != MOD_STATE_CLEAN - && save_before_unloading) { - modprofiler.add(block->getModifiedReasonString(), 1); - if (!saveBlock(block)) - continue; - saved_blocks_count++; + // Save if modified + if (block->getModified() != MOD_STATE_CLEAN + && save_before_unloading) { + modprofiler.add(block->getModifiedReasonString(), 1); + if (!saveBlock(block)) { + it++; + continue; } - - // Delete from memory - sector->deleteBlock(block); - - if (unloaded_blocks) - unloaded_blocks->push_back(p); - - deleted_blocks_count++; - } else { - all_blocks_deleted = false; - block_count_all++; + saved_blocks_count++; } - } - // Delete sector if we emptied it - if (all_blocks_deleted) { - sector_deletion_queue.push_back(sector_it.first); + // Delete directly from container + it = m_blocks.erase(it); + delete block; + + if (unloaded_blocks) + unloaded_blocks->push_back(p); + + deleted_blocks_count++; + } else { + block_count_all++; + it++; } } } else { std::priority_queue mapblock_queue; - MapBlockVect blocks; - for (auto §or_it : m_sectors) { - MapSector *sector = sector_it.second; - - blocks.clear(); - sector->getBlocks(blocks); - - for (MapBlock *block : blocks) { - block->incrementUsageTimer(dtime); - mapblock_queue.push(TimeOrderedMapBlock(sector, block)); - } + for (auto &entry : m_blocks) { + MapBlock *block = entry.second; + block->incrementUsageTimer(dtime); + mapblock_queue.push(TimeOrderedMapBlock(block)); } block_count_all = mapblock_queue.size(); @@ -375,7 +374,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, } // Delete from memory - b.sect->deleteBlock(block); + deleteBlockImmediate(block); if (unloaded_blocks) unloaded_blocks->push_back(p); @@ -383,13 +382,6 @@ void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, deleted_blocks_count++; block_count_all--; } - - // Delete empty sectors - for (auto §or_it : m_sectors) { - if (sector_it.second->empty()) { - sector_deletion_queue.push_back(sector_it.first); - } - } } endSave(); @@ -397,9 +389,6 @@ void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, reportMetrics(end_time - start_time, saved_blocks_count, block_count_all); - // Finally delete the empty sectors - deleteSectors(sector_deletion_queue); - if(deleted_blocks_count != 0) { PrintInfo(infostream); // ServerMap/ClientMap: @@ -422,19 +411,6 @@ void Map::unloadUnreferencedBlocks(std::vector *unloaded_blocks) timerUpdate(0, -1, 0, unloaded_blocks); } -void Map::deleteSectors(const std::vector §orList) -{ - for (v2s16 j : sectorList) { - MapSector *sector = m_sectors[j]; - // If sector is in sector cache, remove it from there - if (m_sector_cache == sector) - m_sector_cache = nullptr; - // Remove from map and delete - m_sectors.erase(j); - delete sector; - } -} - void Map::PrintInfo(std::ostream &out) { out<<"Map: "; diff --git a/src/map.h b/src/map.h index 57ede8ee6..a9517122c 100644 --- a/src/map.h +++ b/src/map.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "irrlichttypes_bloated.h" #include "mapblock.h" @@ -18,7 +19,6 @@ #include "nodetimer.h" #include "debug.h" -class MapSector; class NodeMetadata; class IGameDef; class IRollbackManager; @@ -113,22 +113,20 @@ public: // event shall be deleted by caller after the call. void dispatchEvent(const MapEditEvent &event); - // On failure returns NULL - MapSector * getSectorNoGenerateNoLock(v2s16 p2d); - // Same as the above (there exists no lock anymore) - MapSector * getSectorNoGenerate(v2s16 p2d); - - /* - This is overloaded by ClientMap and ServerMap to allow - their differing fetch methods. - */ - virtual MapSector * emergeSector(v2s16 p){ return NULL; } - // Returns InvalidPositionException if not found MapBlock * getBlockNoCreate(v3s16 p); // Returns NULL if not found MapBlock * getBlockNoCreateNoEx(v3s16 p); + MapBlock* createBlankBlockNoInsert(v3s16 p); + MapBlock *createBlankBlock(v3s16 p); + void insertBlock(MapBlock *block); + + void deleteBlockImmediate(MapBlock *block); + // Remove a block from the map without deleting it + // Returns an owning ptr to block. + std::unique_ptr detachBlock(MapBlock *block); + /* Server overrides */ virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true) { return getBlockNoCreateNoEx(p); } @@ -179,7 +177,7 @@ public: virtual bool deleteBlock(v3s16 blockpos) { return false; } /* - Updates usage timers and unloads unused blocks and sectors. + Updates usage timers and unloads unused blocks. Saves modified blocks before unloading if possible. */ void timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks, @@ -191,11 +189,6 @@ public: */ void unloadUnreferencedBlocks(std::vector *unloaded_blocks=NULL); - // Deletes sectors and their blocks from memory - // Takes cache into account - // If deleted sector is in sector cache, clears cache - void deleteSectors(const std::vector &list); - // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: " virtual void PrintInfo(std::ostream &out); @@ -248,7 +241,6 @@ public: for (s16 bz = bpmin.Z; bz <= bpmax.Z; bz++) for (s16 bx = bpmin.X; bx <= bpmax.X; bx++) for (s16 by = bpmin.Y; by <= bpmax.Y; by++) { - // y is iterated innermost to make use of the sector cache. v3s16 bp(bx, by, bz); MapBlock *block = getBlockNoCreateNoEx(bp); v3s16 basep = bp * MAP_BLOCKSIZE; @@ -282,11 +274,7 @@ protected: std::set m_event_receivers; - std::unordered_map m_sectors; - - // Be sure to set this to NULL when the cached sector is deleted - MapSector *m_sector_cache = nullptr; - v2s16 m_sector_cache_p; + std::unordered_map m_blocks; // This stores the properties of the nodes on the map. const NodeDefManager *m_nodedef; diff --git a/src/mapsector.cpp b/src/mapsector.cpp deleted file mode 100644 index 5e943345c..000000000 --- a/src/mapsector.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Luanti -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright (C) 2013 celeron55, Perttu Ahola - -#include "mapsector.h" -#include "exceptions.h" -#include "mapblock.h" -#include "serialization.h" - -MapSector::MapSector(Map *parent, v2s16 pos, IGameDef *gamedef): - m_parent(parent), - m_pos(pos), - m_gamedef(gamedef) -{ -} - -MapSector::~MapSector() -{ - deleteBlocks(); -} - -void MapSector::deleteBlocks() -{ - // Clear cache - m_block_cache = nullptr; - - // Delete all blocks - m_blocks.clear(); -} - -MapBlock *MapSector::getBlockBuffered(s16 y) -{ - MapBlock *block; - - if (m_block_cache && y == m_block_cache_y) { - return m_block_cache; - } - - // If block doesn't exist, return NULL - auto it = m_blocks.find(y); - block = it != m_blocks.end() ? it->second.get() : nullptr; - - // Cache the last result - m_block_cache_y = y; - m_block_cache = block; - - return block; -} - -MapBlock *MapSector::getBlockNoCreateNoEx(s16 y) -{ - return getBlockBuffered(y); -} - -std::unique_ptr MapSector::createBlankBlockNoInsert(s16 y) -{ - assert(getBlockBuffered(y) == nullptr); // Pre-condition - - if (blockpos_over_max_limit(v3s16(0, y, 0))) - throw InvalidPositionException("createBlankBlockNoInsert(): pos over max mapgen limit"); - - v3s16 blockpos_map(m_pos.X, y, m_pos.Y); - - return std::make_unique(blockpos_map, m_gamedef); -} - -MapBlock *MapSector::createBlankBlock(s16 y) -{ - std::unique_ptr block_u = createBlankBlockNoInsert(y); - MapBlock *block = block_u.get(); - - m_blocks[y] = std::move(block_u); - - return block; -} - -void MapSector::insertBlock(std::unique_ptr block) -{ - s16 block_y = block->getPos().Y; - - MapBlock *block2 = getBlockBuffered(block_y); - if (block2) { - throw AlreadyExistsException("Block already exists"); - } - - v2s16 p2d(block->getPos().X, block->getPos().Z); - assert(p2d == m_pos); - - // Insert into container - m_blocks[block_y] = std::move(block); -} - -void MapSector::deleteBlock(MapBlock *block) -{ - detachBlock(block); - // returned smart-ptr is dropped -} - -std::unique_ptr MapSector::detachBlock(MapBlock *block) -{ - s16 block_y = block->getPos().Y; - - // Clear from cache - m_block_cache = nullptr; - - // Remove from container - auto it = m_blocks.find(block_y); - assert(it != m_blocks.end()); - std::unique_ptr ret = std::move(it->second); - assert(ret.get() == block); - m_blocks.erase(it); - - // Mark as removed - block->makeOrphan(); - - return ret; -} - -void MapSector::getBlocks(MapBlockVect &dest) -{ - dest.reserve(dest.size() + m_blocks.size()); - for (auto &block : m_blocks) { - dest.push_back(block.second.get()); - } -} diff --git a/src/mapsector.h b/src/mapsector.h deleted file mode 100644 index d977bc63c..000000000 --- a/src/mapsector.h +++ /dev/null @@ -1,85 +0,0 @@ -// Luanti -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright (C) 2013 celeron55, Perttu Ahola - -#pragma once - -#include "irrlichttypes.h" -#include "irr_v2d.h" -#include "mapblock.h" -#include -#include -#include -#include - -class Map; -class IGameDef; - -/* - This is an Y-wise stack of MapBlocks. -*/ - -#define MAPSECTOR_SERVER 0 -#define MAPSECTOR_CLIENT 1 - -class MapSector -{ -public: - - MapSector(Map *parent, v2s16 pos, IGameDef *gamedef); - virtual ~MapSector(); - - void deleteBlocks(); - - v2s16 getPos() const - { - return m_pos; - } - - MapBlock *getBlockNoCreateNoEx(s16 y); - std::unique_ptr createBlankBlockNoInsert(s16 y); - MapBlock *createBlankBlock(s16 y); - - void insertBlock(std::unique_ptr block); - - void deleteBlock(MapBlock *block); - - // Remove a block from the map and the sector without deleting it - // Returns an owning ptr to block. - std::unique_ptr detachBlock(MapBlock *block); - - // This makes a copy of the internal collection. - // Prefer getBlocks() if possible. - void getBlocks(MapBlockVect &dest); - - // Get access to the internal collection - // This is explicitly only allowed on a const object since modifying anything while iterating is unsafe. - // The caller needs to make sure that this does not happen. - const auto &getBlocks() const { return m_blocks; } - const auto &getBlocks() = delete; - - bool empty() const { return m_blocks.empty(); } - - int size() const { return m_blocks.size(); } -protected: - - // The pile of MapBlocks - std::unordered_map> m_blocks; - - Map *m_parent; - // Position on parent (in MapBlock widths) - v2s16 m_pos; - - IGameDef *m_gamedef; - - // Last-used block is cached here for quicker access. - // Be sure to set this to nullptr when the cached block is deleted - MapBlock *m_block_cache = nullptr; - s16 m_block_cache_y; - - /* - Private methods - */ - MapBlock *getBlockBuffered(s16 y); - -}; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 6cd7150c6..9b1545a37 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -13,7 +13,6 @@ #include "client/clientmedia.h" #include "log.h" #include "servermap.h" -#include "mapsector.h" #include "client/minimap.h" #include "modchannels.h" #include "nodedef.h" @@ -285,15 +284,7 @@ void Client::handleCommand_BlockData(NetworkPacket* pkt) std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes()); std::istringstream istr(datastring, std::ios_base::binary); - MapSector *sector; - MapBlock *block; - - v2s16 p2d(p.X, p.Z); - sector = m_env.getMap().emergeSector(p2d); - - assert(sector->getPos() == p2d); - - block = sector->getBlockNoCreateNoEx(p.Y); + MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(p); if (block) { /* Update an existing block @@ -305,7 +296,7 @@ void Client::handleCommand_BlockData(NetworkPacket* pkt) /* Create a new block */ - block = sector->createBlankBlock(p.Y); + block = m_env.getMap().createBlankBlock(p); block->deSerialize(istr, m_server_ser_ver, false); block->deSerializeNetworkSpecific(istr); } diff --git a/src/servermap.cpp b/src/servermap.cpp index a71fbecae..22f6a8ac7 100644 --- a/src/servermap.cpp +++ b/src/servermap.cpp @@ -3,7 +3,6 @@ // Copyright (C) 2010-2024 celeron55, Perttu Ahola #include "map.h" -#include "mapsector.h" #include "filesys.h" #include "voxel.h" #include "voxelalgorithms.h" @@ -228,24 +227,18 @@ bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data) Create the whole area of this and the neighboring blocks */ for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++) - for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) { - v2s16 sectorpos(x, z); - // Sector metadata is loaded from disk if not already loaded. - MapSector *sector = createSector(sectorpos); - FATAL_ERROR_IF(sector == NULL, "createSector() failed"); + for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) + for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) { + v3s16 p(x, y, z); - for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) { - v3s16 p(x, y, z); + MapBlock *block = emergeBlock(p, false); + if (block == NULL) { + block = createBlock(p); - MapBlock *block = emergeBlock(p, false); - if (block == NULL) { - block = createBlock(p); - - // Block gets sunlight if this is true. - // Refer to the map generator heuristics. - bool ug = m_emerge->isBlockUnderground(p); - block->setIsUnderground(ug); - } + // Block gets sunlight if this is true. + // Refer to the map generator heuristics. + bool ug = m_emerge->isBlockUnderground(p); + block->setIsUnderground(ug); } } @@ -322,61 +315,15 @@ void ServerMap::finishBlockMake(BlockMakeData *data, m_chunks_in_progress.erase(bpmin); } -MapSector *ServerMap::createSector(v2s16 p2d) -{ - /* - Check if it exists already in memory - */ - MapSector *sector = getSectorNoGenerate(p2d); - if (sector) - return sector; - - /* - Do not create over max mapgen limit - */ - if (blockpos_over_max_limit(v3s16(p2d.X, 0, p2d.Y))) - throw InvalidPositionException("createSector(): pos over max mapgen limit"); - - /* - Generate blank sector - */ - sector = new MapSector(this, p2d, m_gamedef); - - /* - Insert to container - */ - m_sectors[p2d] = sector; - - return sector; -} - MapBlock * ServerMap::createBlock(v3s16 p) { - v2s16 p2d(p.X, p.Z); - s16 block_y = p.Y; - - /* - This will create or load a sector if not found in memory. - */ - MapSector *sector; - try { - sector = createSector(p2d); - } catch (InvalidPositionException &e) { - infostream<<"createBlock: createSector() failed"<getBlockNoCreateNoEx(block_y); + MapBlock *block = getBlockNoCreateNoEx(p); if (block) return block; // Create blank try { - block = sector->createBlankBlock(block_y); + block = createBlankBlock(p); } catch (InvalidPositionException &e) { infostream << "createBlock: createBlankBlock() failed" << std::endl; throw e; @@ -401,8 +348,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank) if (create_blank) { try { - MapSector *sector = createSector(v2s16(p.X, p.Z)); - return sector->createBlankBlock(p.Y); + return createBlankBlock(p); } catch (InvalidPositionException &e) {} } @@ -502,27 +448,21 @@ void ServerMap::save(ModifiedState save_level) // Don't do anything with sqlite unless something is really saved bool save_started = false; - for (auto §or_it : m_sectors) { - MapSector *sector = sector_it.second; + for (auto &entry : m_blocks) { + MapBlock *block = entry.second; + block_count_all++; - MapBlockVect blocks; - sector->getBlocks(blocks); - - for (MapBlock *block : blocks) { - block_count_all++; - - if(block->getModified() >= (u32)save_level) { - // Lazy beginSave() - if(!save_started) { - beginSave(); - save_started = true; - } - - modprofiler.add(block->getModifiedReasonString(), 1); - - saveBlock(block); - block_count++; + if(block->getModified() >= (u32)save_level) { + // Lazy beginSave() + if(!save_started) { + beginSave(); + save_started = true; } + + modprofiler.add(block->getModifiedReasonString(), 1); + + saveBlock(block); + block_count++; } } @@ -557,16 +497,10 @@ void ServerMap::listAllLoadableBlocks(std::vector &dst) void ServerMap::listAllLoadedBlocks(std::vector &dst) { - for (auto §or_it : m_sectors) { - MapSector *sector = sector_it.second; - - MapBlockVect blocks; - sector->getBlocks(blocks); - - for (MapBlock *block : blocks) { - v3s16 p = block->getPos(); - dst.push_back(p); - } + for (auto &entry : m_blocks) { + MapBlock *block = entry.second; + v3s16 p = block->getPos(); + dst.push_back(p); } } @@ -666,14 +600,11 @@ MapBlock *ServerMap::loadBlock(const std::string &blob, v3s16 p3d, bool save_aft bool created_new = false; try { - v2s16 p2d(p3d.X, p3d.Z); - MapSector *sector = createSector(p2d); - - std::unique_ptr block_created_new; - block = sector->getBlockNoCreateNoEx(p3d.Y); + MapBlock* block_created_new = nullptr; + block = getBlockNoCreateNoEx(p3d); if (!block) { - block_created_new = sector->createBlankBlockNoInsert(p3d.Y); - block = block_created_new.get(); + block_created_new = createBlankBlockNoInsert(p3d); + block = block_created_new; } { @@ -683,7 +614,7 @@ MapBlock *ServerMap::loadBlock(const std::string &blob, v3s16 p3d, bool save_aft // If it's a new block, insert it to the map if (block_created_new) { - sector->insertBlock(std::move(block_created_new)); + insertBlock(block_created_new); created_new = true; } } catch (SerializationError &e) { @@ -751,13 +682,9 @@ bool ServerMap::deleteBlock(v3s16 blockpos) MapBlock *block = getBlockNoCreateNoEx(blockpos); if (block) { - v2s16 p2d(blockpos.X, blockpos.Z); - MapSector *sector = getSectorNoGenerate(p2d); - if (!sector) - return false; // It may not be safe to delete the block from memory at the moment // (pointers to it could still be in use) - m_detached_blocks.push_back(sector->detachBlock(block)); + m_detached_blocks.push_back(detachBlock(block)); } return true; diff --git a/src/servermap.h b/src/servermap.h index 7b33a66a9..4e30c4266 100644 --- a/src/servermap.h +++ b/src/servermap.h @@ -49,14 +49,6 @@ public: ServerMap(const std::string &savedir, IGameDef *gamedef, EmergeManager *emerge, MetricsBackend *mb); ~ServerMap(); - /* - Get a sector from somewhere. - - Check memory - - Check disk (doesn't load blocks) - - Create blank one - */ - MapSector *createSector(v2s16 p); - /* Blocks are generated by using these and makeBlock(). */ diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index 5da39d6ed..aa61af20c 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -753,13 +753,13 @@ void update_block_border_lighting(Map *map, MapBlock *block, /*! * Resets the lighting of the given VoxelManipulator to * complete darkness and full sunlight. - * Operates in one map sector. + * Operates in one map column. * * \param offset contains the least x and z node coordinates - * of the map sector. + * of the map column. * \param light incoming sunlight, light[x][z] is true if there * is sunlight above the voxel manipulator at the given x-z coordinates. - * The array's indices are relative node coordinates in the sector. + * The array's indices are relative node coordinates in the column. * After the procedure returns, this contains outgoing light at * the bottom of the voxel manipulator. */