diff options
author | Perttu Ahola <celeron55@gmail.com> | 2010-12-01 15:20:12 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2010-12-01 15:20:12 +0200 |
commit | 5e0c284f3a8debdd9ebb080f80e36dceb7bc4ce2 (patch) | |
tree | d9c4f61f491b57ad7b84df0925186e2183da140b /src | |
parent | 38353751c9f4e03fb6a0b855e6d8b5691af71dc0 (diff) | |
download | minetest-5e0c284f3a8debdd9ebb080f80e36dceb7bc4ce2.tar.gz minetest-5e0c284f3a8debdd9ebb080f80e36dceb7bc4ce2.tar.bz2 minetest-5e0c284f3a8debdd9ebb080f80e36dceb7bc4ce2.zip |
some work-in-progress water stuff
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 194 | ||||
-rw-r--r-- | src/mapnode.h | 22 | ||||
-rw-r--r-- | src/test.cpp | 55 | ||||
-rw-r--r-- | src/voxel.cpp | 264 | ||||
-rw-r--r-- | src/voxel.h | 119 |
5 files changed, 508 insertions, 146 deletions
diff --git a/src/main.cpp b/src/main.cpp index 677f03843..938eb14ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,6 +81,9 @@ SUGGESTION: Use same technique for sector heightmaps as what we're using for UnlimitedHeightmap? (getting all neighbors
when generating)
+TODO: Proper handling of spawning place (try to find something that
+ is not in the middle of an ocean (some land to stand on at
+ least) and save it in map config.
SUGG: Set server to automatically find a good spawning place in some
place where there is water and land.
- Map to have a getWalkableNear(p)
@@ -176,6 +179,197 @@ TODO: MovingObject::move and Player::move are basically the same. Doing now:
======================================================================
+Water dynamics pseudo-code (block = MapNode):
+SUGG: Create separate flag table in VoxelManipulator to allow fast
+clearing of "modified" flags
+
+neighborCausedPressure(pos):
+ pressure = 0
+ dirs = {down, left, right, back, front, up}
+ for d in dirs:
+ pos2 = pos + d
+ p = block_at(pos2).pressure
+ if d.Y == 1 and p > min:
+ p -= 1
+ if d.Y == -1 and p < max:
+ p += 1
+ if p > pressure:
+ pressure = p
+ return pressure
+
+# This should somehow update all changed pressure values
+# in an unknown body of water
+updateWaterPressure(pos):
+ TODO
+
+FIXME: This goes in an indefinite loop when there is an underwater
+chamber like this:
+
+#111######
+#222##22##
+#33333333x<- block removed from here
+##########
+
+#111######
+#222##22##
+#3333333x1
+##########
+
+#111######
+#222##22##
+#333333x11
+##########
+
+#111######
+#222##2x##
+#333333333
+##########
+
+#111######
+#222##x2##
+#333333333
+##########
+
+Now, consider moving to the last block not allowed.
+
+Consider it a 3D case with a depth of 2. We're now at this situation.
+Note the additional blocking ## in the second depth plane.
+
+z=1 z=2
+#111###### #111######
+#222##x2## #222##22##
+#333333333 #33333##33
+########## ##########
+
+#111###### #111######
+#222##22## #222##x2##
+#333333333 #33333##33
+########## ##########
+
+#111###### #111######
+#222##22## #222##2x##
+#333333333 #33333##33
+########## ##########
+
+Now there is nowhere to go, without going to an already visited block,
+but the pressure calculated in here from neighboring blocks is >= 2,
+so it is not the final ending.
+
+We will back up to a state where there is somewhere to go to.
+It is this state:
+
+#111###### #111######
+#222##22## #222##22##
+#333333x33 #33333##33
+########## ##########
+
+Then just go on, avoiding already visited blocks:
+
+#111###### #111######
+#222##22## #222##22##
+#33333x333 #33333##33
+########## ##########
+
+#111###### #111######
+#222##22## #222##22##
+#3333x3333 #33333##33
+########## ##########
+
+#111###### #111######
+#222##22## #222##22##
+#333x33333 #33333##33
+########## ##########
+
+#111###### #111######
+#222##22## #222##22##
+#33x333333 #33333##33
+########## ##########
+
+#111###### #111######
+#22x##22## #222##22##
+#333333333 #33333##33
+########## ##########
+
+#11x###### #111######
+#222##22## #222##22##
+#333333333 #33333##33
+########## ##########
+
+"Blob". the air bubble finally got out of the water.
+Then return recursively to a state where there is air next to water,
+clear the visit flags and feed the neighbor of the water recursively
+to the algorithm.
+
+#11 ###### #111######
+#222##22## #222##22##
+#333333333x #33333##33
+########## ##########
+
+#11 ###### #111######
+#222##22## #222##22##
+#33333333x3 #33333##33
+########## ##########
+
+...and so on.
+
+
+# removed_pos: a position that has been changed from something to air
+flowWater(removed_pos):
+ dirs = {top, left, right, back, front, bottom}
+ selected_dir = None
+ for d in dirs:
+ b2 = removed_pos + d
+
+ # Ignore positions that don't have water
+ if block_at(b2) != water:
+ continue
+
+ # Ignore positions that have already been checked
+ if block_at(b2).checked:
+ continue
+
+ # If block is at top, select it always.
+ if d.Y == 1:
+ selected_dir = d
+ break
+
+ # If block is at bottom, select it if it has enough pressure.
+ # >= 3 needed for stability (and sanity)
+ if d.Y == -1:
+ if block_at(b2).pressure >= 3:
+ selected_dir = d
+ break
+ continue
+
+ # Else block is at some side. select it if it has enough pressure.
+ if block_at(b2).pressure >= 2:
+ selected_dir = d
+ break
+
+ # If there is nothing to do anymore, return.
+ if selected_dir == None
+ return
+
+ b2 = removed_pos + selected_dir
+
+ # Move block
+ set_block(removed_pos, block_at(b2))
+ set_block(b2, air_block)
+
+ # Update pressure
+ updateWaterPressure(removed_pos)
+
+ # Flow water to the newly created empty position
+ flowWater(b2)
+
+ # Check empty positions around and try flowing water to them
+ for d in dirs:
+ b3 = removed_pos + d
+ # Ignore positions that are not air
+ if block_at(b3) is not air:
+ continue
+ flowWater(b3)
+
======================================================================
diff --git a/src/mapnode.h b/src/mapnode.h index 789cedb27..02abe4e52 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -35,9 +35,6 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Ignored node. - param is used for custom information in special containers, - like VoxelManipulator. - Anything that stores MapNodes doesn't have to preserve parameters associated with this material. @@ -67,27 +64,12 @@ enum Material MATERIAL_GRASS, - /* - For water, the param is water pressure. 0...127. - TODO: No, at least the lowest nibble is used for lighting. - - - Water will be a bit like light, but with different flow - behavior. - - Water blocks will fall down if there is empty space below. - - If there is water below, the pressure of the block below is - the pressure of the current block + 1, or higher. - - If there is any pressure in a horizontally neighboring - block, a water block will try to move away from it. - - If there is >=2 of pressure in a block below, water will - try to move upwards. - - NOTE: To keep large operations fast, we have to keep a - cache of the water-air-surfaces, just like with light - */ MATERIAL_WATER, MATERIAL_LIGHT, MATERIAL_TREE, + MATERIAL_LEAVES, MATERIAL_GRASS_FOOTSTEPS, @@ -216,6 +198,8 @@ struct MapNode */ s8 param; + u8 pressure; + MapNode(const MapNode & n) { *this = n; diff --git a/src/test.cpp b/src/test.cpp index 005db2d24..6b285e3a4 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -157,17 +157,16 @@ struct TestVoxelManipulator v.print(dstream); dstream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl; - - //v[v3s16(-1,0,-1)] = MapNode(2); - v[v3s16(-1,0,-1)].d = 2; + + v.setNodeNoRef(v3s16(-1,0,-1), MapNode(2)); v.print(dstream); - assert(v[v3s16(-1,0,-1)].d == 2); + assert(v.getNode(v3s16(-1,0,-1)).d == 2); dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl; - assert(v[v3s16(0,0,-1)].d == MATERIAL_IGNORE); + EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,0,-1))); v.print(dstream); @@ -177,9 +176,51 @@ struct TestVoxelManipulator v.print(dstream); - assert(v[v3s16(-1,0,-1)].d == 2); - assert(v[v3s16(0,1,1)].d == MATERIAL_IGNORE); + assert(v.getNode(v3s16(-1,0,-1)).d == 2); + EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1))); + + /* + Water stuff + */ + + v.clear(); + + const char *content = + "#...######" + "#...##..##" + "#........ " + "##########" + + "#...######" + "#...##..##" + "#........ " + "##########" + ; + + v3s16 size(10, 4, 2); + const char *p = content; + for(s16 z=0; z<size.Z; z++) + for(s16 y=size.Y-1; y>=0; y--) + for(s16 x=0; x<size.X; x++) + { + MapNode n; + n.pressure = size.Y - y; + if(*p == '#') + n.d = MATERIAL_STONE; + else if(*p == '.') + n.d = MATERIAL_WATER; + else if(*p == ' ') + n.d = MATERIAL_AIR; + else + assert(0); + v.setNode(v3s16(x,y,z), n); + p++; + } + + v.print(dstream); + + //assert(0); } }; diff --git a/src/voxel.cpp b/src/voxel.cpp index fc3b4c428..fe176a27a 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -21,36 +21,98 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" VoxelManipulator::VoxelManipulator(): - m_data(NULL) + m_data(NULL), + m_flags(NULL) { } VoxelManipulator::~VoxelManipulator() { + clear(); if(m_data) delete[] m_data; + if(m_flags) + delete[] m_flags; +} + +void VoxelManipulator::clear() +{ + // Reset area to volume=0 + m_area = VoxelArea(); + if(m_data) + delete[] m_data; + m_data = NULL; + if(m_flags) + delete[] m_flags; + m_flags = NULL; +} + +void VoxelManipulator::print(std::ostream &o) +{ + v3s16 em = m_area.getExtent(); + v3s16 of = m_area.MinEdge; + o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z + <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl; + + for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--) + { + if(em.X >= 3 && em.Y >= 3) + { + if (y==m_area.MinEdge.Y+2) o<<"^ "; + else if(y==m_area.MinEdge.Y+1) o<<"| "; + else if(y==m_area.MinEdge.Y+0) o<<"y x-> "; + else o<<" "; + } + + for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++) + { + for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++) + { + u8 f = m_flags[m_area.index(x,y,z)]; + char c; + if(f & VOXELFLAG_NOT_LOADED) + c = 'N'; + else if(f & VOXELFLAG_INEXISTENT) + c = 'I'; + else + { + c = 'X'; + u8 m = m_data[m_area.index(x,y,z)].d; + if(m <= 9) + c = m + '0'; + } + o<<c; + } + o<<' '; + } + o<<std::endl; + } } void VoxelManipulator::addArea(VoxelArea area) { + // Cancel if requested area has zero volume if(area.getExtent() == v3s16(0,0,0)) return; + // Cancel if m_area already contains the requested area + if(m_area.contains(area)) + return; + // Calculate new area VoxelArea new_area; + // New area is the requested area if m_area has zero volume if(m_area.getExtent() == v3s16(0,0,0)) { new_area = area; } + // Else add requested area to m_area else { new_area = m_area; new_area.addArea(area); } - if(new_area == m_area) - return; - s32 new_size = new_area.getVolume(); /*dstream<<"adding area "; @@ -63,11 +125,11 @@ void VoxelManipulator::addArea(VoxelArea area) dstream<<std::endl;*/ // Allocate and clear new data - MapNode *new_data; - new_data = new MapNode[new_size]; + MapNode *new_data = new MapNode[new_size]; + u8 *new_flags = new u8[new_size]; for(s32 i=0; i<new_size; i++) { - new_data[i].d = MATERIAL_IGNORE; + new_flags[i] = VOXELFLAG_NOT_LOADED; } // Copy old data @@ -76,48 +138,31 @@ void VoxelManipulator::addArea(VoxelArea area) for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++) for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++) { - new_data[new_area.index(z,y,x)] = m_data[m_area.index(x,y,z)]; + // If loaded, copy data and flags + if((m_flags[m_area.index(x,y,z)] & VOXELFLAG_NOT_LOADED) == false) + { + new_data[new_area.index(x,y,z)] = m_data[m_area.index(x,y,z)]; + new_flags[new_area.index(x,y,z)] = m_flags[m_area.index(x,y,z)]; + } } - // Replace member + // Replace area, data and flags + m_area = new_area; + MapNode *old_data = m_data; - m_data = new_data; - delete[] old_data; -} + u8 *old_flags = m_flags; -void VoxelManipulator::print(std::ostream &o) -{ - v3s16 em = m_area.getExtent(); - v3s16 of = m_area.MinEdge; - o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z - <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl; - - for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++) - { - if(em.X >= 3 && em.Y >= 3) - { - if(y==m_area.MinEdge.Y+0) o<<"y x-> "; - if(y==m_area.MinEdge.Y+1) o<<"| "; - if(y==m_area.MinEdge.Y+2) o<<"V "; - } + /*dstream<<"old_data="<<(int)old_data<<", new_data="<<(int)new_data + <<", old_flags="<<(int)m_flags<<", new_flags="<<(int)new_flags<<std::endl;*/ - for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++) - { - for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++) - { - u8 m = m_data[m_area.index(x,y,z)].d; - char c = 'X'; - if(m == MATERIAL_IGNORE) - c = 'I'; - else if(m <= 9) - c = m + '0'; - o<<c; - } - o<<' '; - } - o<<std::endl; - } + m_data = new_data; + m_flags = new_flags; + + if(old_data) + delete[] old_data; + if(old_flags) + delete[] old_flags; } void VoxelManipulator::interpolate(VoxelArea area) @@ -156,10 +201,13 @@ void VoxelManipulator::interpolate(VoxelArea area) { v3s16 p2 = p + dirs[i]; - MapNode &n = m_data[m_area.index(p2)]; - if(n.d == MATERIAL_IGNORE) + u8 f = m_flags[m_area.index(p2)]; + assert(!(f & VOXELFLAG_NOT_LOADED)); + if(f & VOXELFLAG_INEXISTENT) continue; + MapNode &n = m_data[m_area.index(p2)]; + airness += (n.d == MATERIAL_AIR) ? 1 : -1; total++; @@ -182,57 +230,91 @@ void VoxelManipulator::interpolate(VoxelArea area) } } -#if 0 -void VoxelManipulator::blitFromNodeContainer - (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c) +void VoxelManipulator::flowWater(v3s16 removed_pos) { - VoxelArea a_to(p_to, p_to+size-v3s16(1,1,1)); - addArea(a_to); - for(s16 z=0; z<size.Z; z++) - for(s16 y=0; y<size.Y; y++) - for(s16 x=0; x<size.X; x++) + v3s16 dirs[6] = { + v3s16(0,1,0), // top + v3s16(-1,0,0), // left + v3s16(1,0,0), // right + v3s16(0,0,-1), // front + v3s16(0,0,1), // back + v3s16(0,-1,0), // bottom + }; + + v3s16 p; + + // Load neighboring nodes + // TODO: A bigger area would be better + emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1))); + + s32 i; + for(i=0; i<6; i++) { - v3s16 p(x,y,z); - try{ - MapNode n = c->getNode(p_from + p); - m_data[m_area.index(p_to + p)] = n; - } - catch(InvalidPositionException &e) + p = removed_pos + dirs[i]; + u8 f = m_flags[m_area.index(p)]; + // Inexistent or checked nodes can't move + if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED)) + continue; + MapNode &n = m_data[m_area.index(p)]; + // Only liquid nodes can move + if(material_liquid(n.d) == false) + continue; + // If block is at top, select it always + if(i == 0) { + break; } - - /*v3s16 p(x,y,z); - MapNode n(MATERIAL_IGNORE); - try{ - n = c->getNode(p_from + p); + // If block is at bottom, select it if it has enough pressure + if(i == 5) + { + if(n.pressure >= 3) + break; + continue; } - catch(InvalidPositionException &e) + // Else block is at some side. Select it if it has enough pressure + if(n.pressure >= 2) { + break; } - m_data[m_area.index(p_to + p)] = n;*/ } -} -void VoxelManipulator::blitToNodeContainer - (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c) -{ - for(s16 z=0; z<size.Z; z++) - for(s16 y=0; y<size.Y; y++) - for(s16 x=0; x<size.X; x++) + // If there is nothing to move, return + if(i==6) + return; + + // Switch nodes at p and removed_pos + MapNode n = m_data[m_area.index(p)]; + u8 f = m_flags[m_area.index(p)]; + m_data[m_area.index(p)] = m_data[m_area.index(removed_pos)]; + m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)]; + m_data[m_area.index(removed_pos)] = n; + m_flags[m_area.index(removed_pos)] = f; + + // Mark p checked + m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED; + + // Update pressure + //TODO + + // Flow water to the newly created empty position + flowWater(p); + + // Try flowing water to empty positions around removed_pos. + // They are checked in reverse order compared to the previous loop. + for(i=5; i>=0; i--) { - v3s16 p(x,y,z); - try{ - MapNode &n = m_data[m_area.index(p_from + p)]; - if(n.d == MATERIAL_IGNORE) - continue; - c->setNode(p_to + p, n); - } - catch(InvalidPositionException &e) - { - } + p = removed_pos + dirs[i]; + u8 f = m_flags[m_area.index(p)]; + // Water can't move to inexistent nodes + if(f & VOXELFLAG_INEXISTENT) + continue; + MapNode &n = m_data[m_area.index(p)]; + // Water can only move to air + if(n.d != MATERIAL_AIR) + continue; + flowWater(p); } } -#endif /* MapVoxelManipulator @@ -254,12 +336,18 @@ void MapVoxelManipulator::emerge(VoxelArea a) for(s16 x=0; x<size.X; x++) { v3s16 p(x,y,z); + s32 i = m_area.index(a.MinEdge + p); + // Don't touch nodes that have already been loaded + if(!(m_flags[i] & VOXELFLAG_NOT_LOADED)) + continue; try{ MapNode n = m_map->getNode(a.MinEdge + p); - m_data[m_area.index(a.MinEdge + p)] = n; + m_data[i] = n; + m_flags[i] = 0; } catch(InvalidPositionException &e) { + m_flags[i] = VOXELFLAG_INEXISTENT; } } } @@ -280,9 +368,11 @@ void MapVoxelManipulator::blitBack { v3s16 p(x,y,z); - MapNode &n = m_data[m_area.index(p)]; - if(n.d == MATERIAL_IGNORE) + u8 f = m_flags[m_area.index(p)]; + if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT)) continue; + + MapNode &n = m_data[m_area.index(p)]; v3s16 blockpos = getNodeBlockPos(p); diff --git a/src/voxel.h b/src/voxel.h index 2bc591d2a..3a4dacd49 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <iostream> /* - TODO: A fast voxel manipulator class + A fast voxel manipulator class Not thread-safe. */ @@ -71,16 +71,24 @@ public: if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y; if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z; } - v3s16 getExtent() + v3s16 getExtent() const { return MaxEdge - MinEdge + v3s16(1,1,1); } - s32 getVolume() + s32 getVolume() const { v3s16 e = getExtent(); return (s32)e.X * (s32)e.Y * (s32)e.Z; } - bool isInside(v3s16 p) + bool contains(VoxelArea &a) const + { + return( + a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X && + a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y && + a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z + ); + } + bool contains(v3s16 p) const { return( p.X >= MinEdge.X && p.X <= MaxEdge.X && @@ -88,7 +96,7 @@ public: p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z ); } - bool operator==(const VoxelArea &other) + bool operator==(const VoxelArea &other) const { return (MinEdge == other.MinEdge && MaxEdge == other.MaxEdge); @@ -97,7 +105,7 @@ public: /* Translates position from virtual coordinates to array index */ - s32 index(s16 x, s16 y, s16 z) + s32 index(s16 x, s16 y, s16 z) const { v3s16 em = getExtent(); v3s16 off = MinEdge; @@ -105,12 +113,12 @@ public: //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" "; return i; } - s32 index(v3s16 p) + s32 index(v3s16 p) const { return index(p.X, p.Y, p.Z); } - void print(std::ostream &o) + void print(std::ostream &o) const { o<<"("<<MinEdge.X <<","<<MinEdge.Y @@ -126,6 +134,13 @@ public: v3s16 MaxEdge; }; +// Hasn't been copied from source (emerged) +#define VOXELFLAG_NOT_LOADED (1<<0) +// Checked as being inexistent in source +#define VOXELFLAG_INEXISTENT (1<<1) +// Algorithm-dependent +#define VOXELFLAG_CHECKED (1<<2) + class VoxelManipulator : public NodeContainer { public: @@ -141,53 +156,77 @@ public: } bool isValidPosition(v3s16 p) { - return m_area.isInside(p); + emerge(p); + return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT); } // These are a bit slow and shouldn't be used internally MapNode getNode(v3s16 p) { - if(isValidPosition(p) == false) - emerge(VoxelArea(p)); + emerge(p); - MapNode &n = m_data[m_area.index(p)]; - - //TODO: Is this the right behaviour? - if(n.d == MATERIAL_IGNORE) + if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT) + { + dstream<<"ERROR: VoxelManipulator::getNode(): " + <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")" + <<", index="<<m_area.index(p) + <<", flags="<<(int)m_flags[m_area.index(p)] + <<" is inexistent"<<std::endl; throw InvalidPositionException - ("Not returning MATERIAL_IGNORE in VoxelManipulator"); + ("VoxelManipulator: getNode: inexistent"); + } - return n; + return m_data[m_area.index(p)]; } - void setNode(v3s16 p, MapNode & n) + void setNode(v3s16 p, MapNode &n) { - if(isValidPosition(p) == false) - emerge(VoxelArea(p)); + emerge(p); + m_data[m_area.index(p)] = n; + m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT; + m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED; } - - MapNode & operator[](v3s16 p) + void setNodeNoRef(v3s16 p, MapNode n) + { + setNode(p, n); + } + + /*void setExists(VoxelArea a) + { + emerge(a); + for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) + for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) + for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++) + { + m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT; + } + }*/ + + /*MapNode & operator[](v3s16 p) { //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl; if(isValidPosition(p) == false) emerge(VoxelArea(p)); + return m_data[m_area.index(p)]; - } + }*/ /* - Manipulation of bigger chunks + Control */ + + void clear(); void print(std::ostream &o); void addArea(VoxelArea area); + /* + Algorithms + */ + void interpolate(VoxelArea area); - /*void blitFromNodeContainer - (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c); - - void blitToNodeContainer - (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c);*/ + void flowWater(v3s16 removed_pos); /* Virtual functions @@ -195,13 +234,25 @@ public: /* Get the contents of the requested area from somewhere. + Shall touch only nodes that have VOXELFLAG_NOT_LOADED + Shall reset VOXELFLAG_NOT_LOADED - If not found from source, add as MATERIAL_IGNORE. + If not found from source, add with VOXELFLAG_INEXISTENT */ virtual void emerge(VoxelArea a) { //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl; addArea(a); + for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) + for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) + for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++) + { + s32 i = m_area.index(x,y,z); + // Don't touch nodes that have already been loaded + if(!(m_flags[i] & VOXELFLAG_NOT_LOADED)) + continue; + m_flags[i] = VOXELFLAG_INEXISTENT; + } } /* @@ -215,12 +266,14 @@ public: */ VoxelArea m_area; /* - NULL if data size is 0 + NULL if data size is 0 (extent (0,0,0)) Data is stored as [z*h*w + y*h + x] - Special data values: - MATERIAL_IGNORE: Unspecified node */ MapNode *m_data; + /* + Flags of all nodes + */ + u8 *m_flags; private: }; |