Prevent VoxelManipulator size overflow

This commit is contained in:
sfan5 2025-01-08 19:30:48 +01:00
parent 2cdf3af1b8
commit 9dd09d1056
4 changed files with 33 additions and 31 deletions

View file

@ -5044,7 +5044,7 @@ inside the VoxelManip.
can use `core.emerge_area` to make sure that the area you want to can use `core.emerge_area` to make sure that the area you want to
read/write is already generated. read/write is already generated.
* Other mods, or the core itself, could possibly modify the area of the map * Other mods, or the engine itself, could possibly modify the area of the map
currently loaded into a VoxelManip object. With the exception of Mapgen currently loaded into a VoxelManip object. With the exception of Mapgen
VoxelManips (see above section), the internal buffers are not updated. For VoxelManips (see above section), the internal buffers are not updated. For
this reason, it is strongly encouraged to complete the usage of a particular this reason, it is strongly encouraged to complete the usage of a particular
@ -5059,9 +5059,11 @@ inside the VoxelManip.
Methods Methods
------- -------
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object * `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object
containing the region formed by `p1` and `p2`. containing the region formed by `p1` and `p2`.
* returns actual emerged `pmin`, actual emerged `pmax` * returns actual emerged `pmin`, actual emerged `pmax`
* Note that calling this multiple times will *add* to the area loaded in the
VoxelManip, and not reset it.
* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to * `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to
the map. the map.
* **important**: data must be set using `VoxelManip:set_data()` before * **important**: data must be set using `VoxelManip:set_data()` before
@ -5120,8 +5122,8 @@ Methods
generated mapchunk above are propagated down into the mapchunk, defaults generated mapchunk above are propagated down into the mapchunk, defaults
to `true` if left out. to `true` if left out.
* `update_liquids()`: Update liquid flow * `update_liquids()`: Update liquid flow
* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified * `was_modified()`: Returns `true` if the data in the VoxelManip has been modified
since it was last read from the map. This means you have to call `get_data` again. since it was last read from the map. This means you have to call `get_data()` again.
This only applies to a `VoxelManip` object from `core.get_mapgen_object`, This only applies to a `VoxelManip` object from `core.get_mapgen_object`,
where the engine will keep the map and the VM in sync automatically. where the engine will keep the map and the VM in sync automatically.
* Note: this doesn't do what you think it does and is subject to removal. Don't use it! * Note: this doesn't do what you think it does and is subject to removal. Don't use it!

View file

@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
assert(map); assert(map);
} }
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
bool load_if_inexistent)
{ {
TimeTaker timer1("initialEmerge", &emerge_time); TimeTaker timer1("initialEmerge", &emerge_time);
assert(m_map); assert(m_map);
// Units of these are MapBlocks
v3s16 p_min = blockpos_min;
v3s16 p_max = blockpos_max;
VoxelArea block_area_nodes VoxelArea block_area_nodes
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
infostream<<std::endl; infostream<<std::endl;
} }
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
addArea(block_area_nodes); addArea(block_area_nodes);
for(s32 z=p_min.Z; z<=p_max.Z; z++) for(s32 z=p_min.Z; z<=p_max.Z; z++)
@ -812,16 +808,12 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
setFlags(a, VOXELFLAG_NO_DATA); setFlags(a, VOXELFLAG_NO_DATA);
} }
} }
/*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
{
// Mark that block was loaded as blank
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
m_loaded_blocks[p] = flags; m_loaded_blocks[p] = flags;
} }
m_is_dirty = false; if (all_new)
m_is_dirty = false;
} }
void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks, void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
/* /*
Copy data of all blocks Copy data of all blocks
*/ */
assert(!m_loaded_blocks.empty());
for (auto &loaded_block : m_loaded_blocks) { for (auto &loaded_block : m_loaded_blocks) {
v3s16 p = loaded_block.first; v3s16 p = loaded_block.first;
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);

View file

@ -298,9 +298,6 @@ protected:
u32 needed_count); u32 needed_count);
}; };
#define VMANIP_BLOCK_DATA_INEXIST 1
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
class MMVManip : public VoxelManipulator class MMVManip : public VoxelManipulator
{ {
public: public:
@ -344,4 +341,8 @@ protected:
value = flags describing the block value = flags describing the block
*/ */
std::map<v3s16, u8> m_loaded_blocks; std::map<v3s16, u8> m_loaded_blocks;
enum : u8 {
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
};
}; };

View file

@ -113,6 +113,20 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
} }
} }
static inline void checkArea(const VoxelArea &a)
{
// won't overflow since cbrt(2^64) > 2^16
u64 real_volume = static_cast<u64>(a.getExtent().X) * a.getExtent().Y * a.getExtent().Z;
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
// Note: the hard limit is somewhere around 2^31 due to s32 type
constexpr u64 MAX_ALLOWED = 4096000;
if (real_volume > MAX_ALLOWED) {
throw BaseException("VoxelManipulator: "
"Area volume exceeds allowed value of " + std::to_string(MAX_ALLOWED));
}
}
void VoxelManipulator::addArea(const VoxelArea &area) void VoxelManipulator::addArea(const VoxelArea &area)
{ {
// Cancel if requested area has zero volume // Cancel if requested area has zero volume
@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area)
return; return;
// Calculate new area // Calculate new area
VoxelArea new_area; VoxelArea new_area = m_area;
// New area is the requested area if m_area has zero volume new_area.addArea(area);
if(m_area.hasEmptyExtent())
{ checkArea(new_area);
new_area = area;
}
// Else add requested area to m_area
else
{
new_area = m_area;
new_area.addArea(area);
}
u32 new_size = new_area.getVolume(); u32 new_size = new_area.getVolume();