aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/map.cpp23
-rw-r--r--src/map.h10
-rw-r--r--src/mapblock.h15
-rw-r--r--src/mapsector.cpp10
-rw-r--r--src/mapsector.h3
-rw-r--r--src/server.cpp5
-rw-r--r--src/serverenvironment.cpp13
7 files changed, 74 insertions, 5 deletions
diff --git a/src/map.cpp b/src/map.cpp
index 59d1a925d..239d5fb02 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1309,6 +1309,8 @@ ServerMap::~ServerMap()
*/
delete dbase;
delete dbase_ro;
+
+ deleteDetachedBlocks();
}
MapgenParams *ServerMap::getMapgenParams()
@@ -1888,12 +1890,31 @@ bool ServerMap::deleteBlock(v3s16 blockpos)
MapSector *sector = getSectorNoGenerate(p2d);
if (!sector)
return false;
- sector->deleteBlock(block);
+ // It may not be safe to delete the block from memory at the moment
+ // (pointers to it could still be in use)
+ sector->detachBlock(block);
+ m_detached_blocks.push_back(block);
}
return true;
}
+void ServerMap::deleteDetachedBlocks()
+{
+ for (MapBlock *block : m_detached_blocks) {
+ assert(block->isOrphan());
+ delete block;
+ }
+ m_detached_blocks.clear();
+}
+
+void ServerMap::step()
+{
+ // Delete from memory blocks removed by deleteBlocks() only when pointers
+ // to them are (probably) no longer in use
+ deleteDetachedBlocks();
+}
+
void ServerMap::PrintInfo(std::ostream &out)
{
out<<"ServerMap: ";
diff --git a/src/map.h b/src/map.h
index 9a9586fc6..7893142b7 100644
--- a/src/map.h
+++ b/src/map.h
@@ -412,8 +412,15 @@ public:
// Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
+ // Blocks are removed from the map but not deleted from memory until
+ // deleteDetachedBlocks() is called, since pointers to them may still exist
+ // when deleteBlock() is called.
bool deleteBlock(v3s16 blockpos) override;
+ void deleteDetachedBlocks();
+
+ void step();
+
void updateVManip(v3s16 pos);
// For debug printing
@@ -457,6 +464,9 @@ private:
std::set<v3s16> m_chunks_in_progress;
+ // used by deleteBlock() and deleteDetachedBlocks()
+ MapBlockVect m_detached_blocks;
+
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
f32 m_transforming_liquid_loop_count_multiplier = 1.0f;
diff --git a/src/mapblock.h b/src/mapblock.h
index b817be596..d2ffc4bb7 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -81,11 +81,24 @@ public:
return NODECONTAINER_ID_MAPBLOCK;
}*/
- Map * getParent()
+ Map *getParent()
{
return m_parent;
}
+ // Any server-modding code can "delete" arbitrary blocks (i.e. with
+ // core.delete_area), which makes them orphan. Avoid using orphan blocks for
+ // anything.
+ bool isOrphan() const
+ {
+ return !m_parent;
+ }
+
+ void makeOrphan()
+ {
+ m_parent = nullptr;
+ }
+
void reallocate()
{
for (u32 i = 0; i < nodecount; i++)
diff --git a/src/mapsector.cpp b/src/mapsector.cpp
index e6cc32e28..36a61e139 100644
--- a/src/mapsector.cpp
+++ b/src/mapsector.cpp
@@ -110,6 +110,12 @@ void MapSector::insertBlock(MapBlock *block)
void MapSector::deleteBlock(MapBlock *block)
{
+ detachBlock(block);
+ delete block;
+}
+
+void MapSector::detachBlock(MapBlock *block)
+{
s16 block_y = block->getPos().Y;
// Clear from cache
@@ -118,8 +124,8 @@ void MapSector::deleteBlock(MapBlock *block)
// Remove from container
m_blocks.erase(block_y);
- // Delete
- delete block;
+ // Mark as removed
+ block->makeOrphan();
}
void MapSector::getBlocks(MapBlockVect &dest)
diff --git a/src/mapsector.h b/src/mapsector.h
index ffd4cdd1d..04b1aa6be 100644
--- a/src/mapsector.h
+++ b/src/mapsector.h
@@ -58,6 +58,9 @@ public:
void deleteBlock(MapBlock *block);
+ // Remove a block from the map and the sector without deleting it
+ void detachBlock(MapBlock *block);
+
void getBlocks(MapBlockVect &dest);
bool empty() const { return m_blocks.empty(); }
diff --git a/src/server.cpp b/src/server.cpp
index 1ee623fa0..197e76e16 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -667,6 +667,11 @@ void Server::AsyncRunStep(bool initial_step)
}
/*
+ Note: Orphan MapBlock ptrs become dangling after this call.
+ */
+ m_env->getServerMap().step();
+
+ /*
Listen to the admin chat, if available
*/
if (m_admin_chat) {
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
index 0099b4a25..b01b4cebd 100644
--- a/src/serverenvironment.cpp
+++ b/src/serverenvironment.cpp
@@ -282,6 +282,8 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block,
continue;
for (auto lbmdef : *lbm_list) {
lbmdef->trigger(env, pos + pos_of_block, n, dtime_s);
+ if (block->isOrphan())
+ return;
n = block->getNodeNoCheck(pos);
if (n.getContent() != c)
break; // The node was changed and the LBMs no longer apply
@@ -966,6 +968,9 @@ public:
aabm.abm->trigger(m_env, p, n,
active_object_count, active_object_count_wider);
+ if (block->isOrphan())
+ return;
+
// Count surrounding objects again if the abms added any
if(m_env->m_added_objects > 0) {
active_object_count = countObjects(block, map, active_object_count_wider);
@@ -1016,13 +1021,17 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
// Activate stored objects
activateObjects(block, dtime_s);
+ if (block->isOrphan())
+ return;
/* Handle LoadingBlockModifiers */
m_lbm_mgr.applyLBMs(this, block, stamp, (float)dtime_s);
+ if (block->isOrphan())
+ return;
// Run node timers
block->step((float)dtime_s, [&](v3s16 p, MapNode n, f32 d) -> bool {
- return m_script->node_on_timer(p, n, d);
+ return !block->isOrphan() && m_script->node_on_timer(p, n, d);
});
}
@@ -1996,6 +2005,8 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
<< " type=" << (int)s_obj.type << std::endl;
// This will also add the object to the active static list
addActiveObjectRaw(obj, false, dtime_s);
+ if (block->isOrphan())
+ return;
}
// Clear stored list