CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src\r
\r
#CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe\r
-CXXFLAGS = -O2 -ffast-math -Wall -g -pipe\r
+#CXXFLAGS = -O2 -ffast-math -Wall -g -pipe\r
#CXXFLAGS = -O1 -ffast-math -Wall -g\r
-#CXXFLAGS = -Wall -g -O0\r
+CXXFLAGS = -Wall -g -O0\r
\r
#CXXFLAGS = -O3 -ffast-math -Wall\r
#CXXFLAGS = -O3 -ffast-math -Wall -g\r
using for UnlimitedHeightmap? (getting all neighbors\r
when generating)\r
\r
+TODO: Proper handling of spawning place (try to find something that\r
+ is not in the middle of an ocean (some land to stand on at\r
+ least) and save it in map config.\r
SUGG: Set server to automatically find a good spawning place in some\r
place where there is water and land.\r
- Map to have a getWalkableNear(p)\r
Doing now:\r
======================================================================\r
\r
+Water dynamics pseudo-code (block = MapNode):\r
+SUGG: Create separate flag table in VoxelManipulator to allow fast\r
+clearing of "modified" flags\r
+\r
+neighborCausedPressure(pos):\r
+ pressure = 0\r
+ dirs = {down, left, right, back, front, up}\r
+ for d in dirs:\r
+ pos2 = pos + d\r
+ p = block_at(pos2).pressure\r
+ if d.Y == 1 and p > min:\r
+ p -= 1\r
+ if d.Y == -1 and p < max:\r
+ p += 1\r
+ if p > pressure:\r
+ pressure = p\r
+ return pressure\r
+\r
+# This should somehow update all changed pressure values\r
+# in an unknown body of water\r
+updateWaterPressure(pos):\r
+ TODO\r
+\r
+FIXME: This goes in an indefinite loop when there is an underwater\r
+chamber like this:\r
+\r
+#111######\r
+#222##22##\r
+#33333333x<- block removed from here\r
+##########\r
+\r
+#111######\r
+#222##22##\r
+#3333333x1\r
+##########\r
+\r
+#111######\r
+#222##22##\r
+#333333x11\r
+##########\r
+\r
+#111######\r
+#222##2x##\r
+#333333333\r
+##########\r
+\r
+#111######\r
+#222##x2##\r
+#333333333\r
+##########\r
+\r
+Now, consider moving to the last block not allowed.\r
+\r
+Consider it a 3D case with a depth of 2. We're now at this situation.\r
+Note the additional blocking ## in the second depth plane.\r
+\r
+z=1 z=2\r
+#111###### #111######\r
+#222##x2## #222##22##\r
+#333333333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#222##22## #222##x2##\r
+#333333333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#222##22## #222##2x##\r
+#333333333 #33333##33 \r
+########## ##########\r
+\r
+Now there is nowhere to go, without going to an already visited block,\r
+but the pressure calculated in here from neighboring blocks is >= 2,\r
+so it is not the final ending.\r
+\r
+We will back up to a state where there is somewhere to go to.\r
+It is this state:\r
+\r
+#111###### #111######\r
+#222##22## #222##22##\r
+#333333x33 #33333##33\r
+########## ##########\r
+\r
+Then just go on, avoiding already visited blocks:\r
+\r
+#111###### #111######\r
+#222##22## #222##22##\r
+#33333x333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#222##22## #222##22##\r
+#3333x3333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#222##22## #222##22##\r
+#333x33333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#222##22## #222##22##\r
+#33x333333 #33333##33\r
+########## ##########\r
+\r
+#111###### #111######\r
+#22x##22## #222##22##\r
+#333333333 #33333##33\r
+########## ##########\r
+\r
+#11x###### #111######\r
+#222##22## #222##22##\r
+#333333333 #33333##33\r
+########## ##########\r
+\r
+"Blob". the air bubble finally got out of the water.\r
+Then return recursively to a state where there is air next to water,\r
+clear the visit flags and feed the neighbor of the water recursively\r
+to the algorithm.\r
+\r
+#11 ###### #111######\r
+#222##22## #222##22##\r
+#333333333x #33333##33\r
+########## ##########\r
+\r
+#11 ###### #111######\r
+#222##22## #222##22##\r
+#33333333x3 #33333##33\r
+########## ##########\r
+\r
+...and so on.\r
+\r
+\r
+# removed_pos: a position that has been changed from something to air\r
+flowWater(removed_pos):\r
+ dirs = {top, left, right, back, front, bottom}\r
+ selected_dir = None\r
+ for d in dirs:\r
+ b2 = removed_pos + d\r
+\r
+ # Ignore positions that don't have water\r
+ if block_at(b2) != water:\r
+ continue\r
+\r
+ # Ignore positions that have already been checked\r
+ if block_at(b2).checked:\r
+ continue\r
+\r
+ # If block is at top, select it always.\r
+ if d.Y == 1:\r
+ selected_dir = d\r
+ break\r
+\r
+ # If block is at bottom, select it if it has enough pressure.\r
+ # >= 3 needed for stability (and sanity)\r
+ if d.Y == -1:\r
+ if block_at(b2).pressure >= 3:\r
+ selected_dir = d\r
+ break\r
+ continue\r
+ \r
+ # Else block is at some side. select it if it has enough pressure.\r
+ if block_at(b2).pressure >= 2:\r
+ selected_dir = d\r
+ break\r
+ \r
+ # If there is nothing to do anymore, return.\r
+ if selected_dir == None\r
+ return\r
+ \r
+ b2 = removed_pos + selected_dir\r
+ \r
+ # Move block\r
+ set_block(removed_pos, block_at(b2))\r
+ set_block(b2, air_block)\r
+ \r
+ # Update pressure\r
+ updateWaterPressure(removed_pos)\r
+ \r
+ # Flow water to the newly created empty position\r
+ flowWater(b2)\r
+\r
+ # Check empty positions around and try flowing water to them\r
+ for d in dirs:\r
+ b3 = removed_pos + d\r
+ # Ignore positions that are not air\r
+ if block_at(b3) is not air:\r
+ continue\r
+ flowWater(b3)\r
+\r
\r
======================================================================\r
\r
/*
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.
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,
*/
s8 param;
+ u8 pressure;
+
MapNode(const MapNode & n)
{
*this = n;
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);
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);
}
};
#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 ";
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
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)
{
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++;
}
}
-#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
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;
}
}
}
{
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);
#include <iostream>
/*
- TODO: A fast voxel manipulator class
+ A fast voxel manipulator class
Not thread-safe.
*/
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 &&
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);
/*
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;
//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
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:
}
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
/*
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;
+ }
}
/*
*/
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:
};