diff --git a/doc/lua_api.md b/doc/lua_api.md index af57c5442..b0103d120 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5044,7 +5044,7 @@ inside the VoxelManip. can use `core.emerge_area` to make sure that the area you want to 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 VoxelManips (see above section), the internal buffers are not updated. For this reason, it is strongly encouraged to complete the usage of a particular @@ -5059,9 +5059,11 @@ inside the VoxelManip. 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`. * 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 the map. * **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 to `true` if left out. * `update_liquids()`: Update liquid flow -* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified - since it was last read from the map. This means you have to call `get_data` again. +* `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. 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. * Note: this doesn't do what you think it does and is subject to removal. Don't use it! diff --git a/src/map.cpp b/src/map.cpp index 240788944..e8ccac0cc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map): assert(map); } -void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, - bool load_if_inexistent) +void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent) { TimeTaker timer1("initialEmerge", &emerge_time); assert(m_map); - // Units of these are MapBlocks - v3s16 p_min = blockpos_min; - v3s16 p_max = blockpos_max; - VoxelArea block_area_nodes (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<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_is_dirty = false; + if (all_new) + m_is_dirty = false; } void MMVManip::blitBackAll(std::map *modified_blocks, @@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map *modified_blocks, /* Copy data of all blocks */ + assert(!m_loaded_blocks.empty()); for (auto &loaded_block : m_loaded_blocks) { v3s16 p = loaded_block.first; MapBlock *block = m_map->getBlockNoCreateNoEx(p); diff --git a/src/map.h b/src/map.h index 37d1a713d..a4f0e4524 100644 --- a/src/map.h +++ b/src/map.h @@ -298,9 +298,6 @@ protected: u32 needed_count); }; -#define VMANIP_BLOCK_DATA_INEXIST 1 -#define VMANIP_BLOCK_CONTAINS_CIGNORE 2 - class MMVManip : public VoxelManipulator { public: @@ -344,4 +341,8 @@ protected: value = flags describing the block */ std::map m_loaded_blocks; + + enum : u8 { + VMANIP_BLOCK_DATA_INEXIST = 1 << 0, + }; }; diff --git a/src/voxel.cpp b/src/voxel.cpp index 8f3858a1f..f74129260 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -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(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) { // Cancel if requested area has zero volume @@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area) return; // Calculate new area - VoxelArea new_area; - // New area is the requested area if m_area has zero volume - if(m_area.hasEmptyExtent()) - { - new_area = area; - } - // Else add requested area to m_area - else - { - new_area = m_area; - new_area.addArea(area); - } + VoxelArea new_area = m_area; + new_area.addArea(area); + + checkArea(new_area); u32 new_size = new_area.getVolume();