mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 01:53:45 +01:00
commit before some radicallish changes to water behavior
This commit is contained in:
parent
5e0c284f3a
commit
2a0d1a059e
4
Makefile
4
Makefile
@ -13,9 +13,9 @@ JTHREADPATH = ../jthread/jthread-1.2.1
|
|||||||
CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src
|
CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src
|
||||||
|
|
||||||
#CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe
|
#CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe
|
||||||
#CXXFLAGS = -O2 -ffast-math -Wall -g -pipe
|
CXXFLAGS = -O2 -ffast-math -Wall -g -pipe
|
||||||
#CXXFLAGS = -O1 -ffast-math -Wall -g
|
#CXXFLAGS = -O1 -ffast-math -Wall -g
|
||||||
CXXFLAGS = -Wall -g -O0
|
#CXXFLAGS = -Wall -g -O0
|
||||||
|
|
||||||
#CXXFLAGS = -O3 -ffast-math -Wall
|
#CXXFLAGS = -O3 -ffast-math -Wall
|
||||||
#CXXFLAGS = -O3 -ffast-math -Wall -g
|
#CXXFLAGS = -O3 -ffast-math -Wall -g
|
||||||
|
@ -116,6 +116,14 @@ public:
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ProcessingLimitException : public BaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessingLimitException(const char *s):
|
||||||
|
BaseException(s)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Some "old-style" interrupts:
|
Some "old-style" interrupts:
|
||||||
*/
|
*/
|
||||||
|
@ -173,9 +173,12 @@ TODO: Remove LazyMeshUpdater. It is not used as supposed.
|
|||||||
FIXME: Rats somehow go underground sometimes (you can see it in water)
|
FIXME: Rats somehow go underground sometimes (you can see it in water)
|
||||||
- Does their position get saved to a border value or something?
|
- Does their position get saved to a border value or something?
|
||||||
|
|
||||||
TODO: MovingObject::move and Player::move are basically the same.
|
SUGG: MovingObject::move and Player::move are basically the same.
|
||||||
combine them.
|
combine them.
|
||||||
|
|
||||||
|
TODO: Transfer sign texts as metadata of block and not as data of
|
||||||
|
object
|
||||||
|
|
||||||
Doing now:
|
Doing now:
|
||||||
======================================================================
|
======================================================================
|
||||||
|
|
||||||
|
149
src/map.cpp
149
src/map.cpp
@ -47,10 +47,10 @@ MapBlockPointerCache::~MapBlockPointerCache()
|
|||||||
{
|
{
|
||||||
m_map->m_blockcachelock.cacheRemoved();
|
m_map->m_blockcachelock.cacheRemoved();
|
||||||
|
|
||||||
dstream<<"MapBlockPointerCache:"
|
/*dstream<<"MapBlockPointerCache:"
|
||||||
<<" from_cache_count="<<m_from_cache_count
|
<<" from_cache_count="<<m_from_cache_count
|
||||||
<<" from_map_count="<<m_from_map_count
|
<<" from_map_count="<<m_from_map_count
|
||||||
<<std::endl;
|
<<std::endl;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
|
MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
|
||||||
@ -1050,6 +1050,8 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
|||||||
// Node will be replaced with this
|
// Node will be replaced with this
|
||||||
u8 replace_material = MATERIAL_AIR;
|
u8 replace_material = MATERIAL_AIR;
|
||||||
|
|
||||||
|
// NOTE: Water is now managed elsewhere
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Find out with what material the node will be replaced.
|
Find out with what material the node will be replaced.
|
||||||
@ -1107,6 +1109,8 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If there is a node at top and it doesn't have sunlight,
|
If there is a node at top and it doesn't have sunlight,
|
||||||
there will be no sunlight going down.
|
there will be no sunlight going down.
|
||||||
@ -3143,3 +3147,144 @@ void ClientMap::PrintInfo(std::ostream &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
MapVoxelManipulator
|
||||||
|
*/
|
||||||
|
|
||||||
|
MapVoxelManipulator::MapVoxelManipulator(Map *map)
|
||||||
|
{
|
||||||
|
m_map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapVoxelManipulator::~MapVoxelManipulator()
|
||||||
|
{
|
||||||
|
dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
|
||||||
|
<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapVoxelManipulator::emerge(VoxelArea a)
|
||||||
|
{
|
||||||
|
TimeTaker timer1("emerge", g_device, &emerge_time);
|
||||||
|
|
||||||
|
// Units of these are MapBlocks
|
||||||
|
v3s16 p_min = getNodeBlockPos(a.MinEdge);
|
||||||
|
v3s16 p_max = getNodeBlockPos(a.MaxEdge);
|
||||||
|
|
||||||
|
VoxelArea block_area_nodes
|
||||||
|
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
|
||||||
|
|
||||||
|
addArea(block_area_nodes);
|
||||||
|
|
||||||
|
for(s32 z=p_min.Z; z<=p_max.Z; z++)
|
||||||
|
for(s32 y=p_min.Y; y<=p_max.Y; y++)
|
||||||
|
for(s32 x=p_min.X; x<=p_max.X; x++)
|
||||||
|
{
|
||||||
|
v3s16 p(x,y,z);
|
||||||
|
core::map<v3s16, bool>::Node *n;
|
||||||
|
n = m_loaded_blocks.find(p);
|
||||||
|
if(n != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool block_data_inexistent = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TimeTaker timer1("emerge load", g_device, &emerge_load_time);
|
||||||
|
|
||||||
|
dstream<<"Loading block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
MapBlock *block = m_map->getBlockNoCreate(p);
|
||||||
|
if(block->isDummy())
|
||||||
|
block_data_inexistent = true;
|
||||||
|
else
|
||||||
|
block->copyTo(*this);
|
||||||
|
}
|
||||||
|
catch(InvalidPositionException &e)
|
||||||
|
{
|
||||||
|
block_data_inexistent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block_data_inexistent)
|
||||||
|
{
|
||||||
|
VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
|
||||||
|
// Fill with VOXELFLAG_INEXISTENT
|
||||||
|
for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
|
||||||
|
for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
|
||||||
|
{
|
||||||
|
s32 i = m_area.index(a.MinEdge.X,y,z);
|
||||||
|
memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loaded_blocks.insert(p, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dstream<<"emerge done"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Add an option to only update eg. water and air nodes.
|
||||||
|
This will make it interfere less with important stuff if
|
||||||
|
run on background.
|
||||||
|
*/
|
||||||
|
void MapVoxelManipulator::blitBack
|
||||||
|
(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
|
{
|
||||||
|
TimeTaker timer1("blitBack", g_device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize block cache
|
||||||
|
*/
|
||||||
|
v3s16 blockpos_last;
|
||||||
|
MapBlock *block = NULL;
|
||||||
|
bool block_checked_in_modified = false;
|
||||||
|
|
||||||
|
for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
v3s16 p(x,y,z);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get block
|
||||||
|
if(block == NULL || blockpos != blockpos_last){
|
||||||
|
block = m_map->getBlockNoCreate(blockpos);
|
||||||
|
blockpos_last = blockpos;
|
||||||
|
block_checked_in_modified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate relative position in block
|
||||||
|
v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
|
||||||
|
|
||||||
|
// Don't continue if nothing has changed here
|
||||||
|
if(block->getNode(relpos) == n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//m_map->setNode(m_area.MinEdge + p, n);
|
||||||
|
block->setNode(relpos, n);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make sure block is in modified_blocks
|
||||||
|
*/
|
||||||
|
if(block_checked_in_modified == false)
|
||||||
|
{
|
||||||
|
modified_blocks[blockpos] = block;
|
||||||
|
block_checked_in_modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(InvalidPositionException &e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//END
|
||||||
|
34
src/map.h
34
src/map.h
@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "mapsector.h"
|
#include "mapsector.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "voxel.h"
|
||||||
|
|
||||||
class Map;
|
class Map;
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ class Map;
|
|||||||
NOTE: This doesn't really make anything more efficient
|
NOTE: This doesn't really make anything more efficient
|
||||||
NOTE: Use VoxelManipulator, if possible
|
NOTE: Use VoxelManipulator, if possible
|
||||||
TODO: Get rid of this?
|
TODO: Get rid of this?
|
||||||
|
NOTE: CONFIRMED: THIS CACHE DOESN'T MAKE ANYTHING ANY FASTER
|
||||||
*/
|
*/
|
||||||
class MapBlockPointerCache : public NodeContainer
|
class MapBlockPointerCache : public NodeContainer
|
||||||
{
|
{
|
||||||
@ -121,7 +123,7 @@ public:
|
|||||||
|
|
||||||
void cacheCreated()
|
void cacheCreated()
|
||||||
{
|
{
|
||||||
dstream<<"cacheCreated() begin"<<std::endl;
|
//dstream<<"cacheCreated() begin"<<std::endl;
|
||||||
JMutexAutoLock waitcachelock(m_waitcache_mutex);
|
JMutexAutoLock waitcachelock(m_waitcache_mutex);
|
||||||
JMutexAutoLock countlock(m_count_mutex);
|
JMutexAutoLock countlock(m_count_mutex);
|
||||||
|
|
||||||
@ -131,12 +133,12 @@ public:
|
|||||||
|
|
||||||
m_count++;
|
m_count++;
|
||||||
|
|
||||||
dstream<<"cacheCreated() end"<<std::endl;
|
//dstream<<"cacheCreated() end"<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cacheRemoved()
|
void cacheRemoved()
|
||||||
{
|
{
|
||||||
dstream<<"cacheRemoved() begin"<<std::endl;
|
//dstream<<"cacheRemoved() begin"<<std::endl;
|
||||||
JMutexAutoLock countlock(m_count_mutex);
|
JMutexAutoLock countlock(m_count_mutex);
|
||||||
|
|
||||||
assert(m_count > 0);
|
assert(m_count > 0);
|
||||||
@ -147,7 +149,7 @@ public:
|
|||||||
if(m_count == 0)
|
if(m_count == 0)
|
||||||
m_cache_mutex.Unlock();
|
m_cache_mutex.Unlock();
|
||||||
|
|
||||||
dstream<<"cacheRemoved() end"<<std::endl;
|
//dstream<<"cacheRemoved() end"<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -589,5 +591,29 @@ private:
|
|||||||
JMutex mesh_mutex;
|
JMutex mesh_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MapVoxelManipulator : public VoxelManipulator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapVoxelManipulator(Map *map);
|
||||||
|
virtual ~MapVoxelManipulator();
|
||||||
|
|
||||||
|
virtual void clear()
|
||||||
|
{
|
||||||
|
VoxelManipulator::clear();
|
||||||
|
m_loaded_blocks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void emerge(VoxelArea a);
|
||||||
|
|
||||||
|
void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map *m_map;
|
||||||
|
// bool is dummy value
|
||||||
|
// SUGG: How 'bout an another VoxelManipulator for storing the
|
||||||
|
// information about which block is loaded?
|
||||||
|
core::map<v3s16, bool> m_loaded_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -696,6 +696,15 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
|
|||||||
return block_below_is_valid;
|
return block_below_is_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapBlock::copyTo(VoxelManipulator &dst)
|
||||||
|
{
|
||||||
|
v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
|
||||||
|
VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
|
||||||
|
|
||||||
|
dst.copyFrom(data, data_area, v3s16(0,0,0),
|
||||||
|
getPosRelative(), data_size);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Serialization
|
Serialization
|
||||||
*/
|
*/
|
||||||
@ -755,6 +764,17 @@ void MapBlock::serialize(std::ostream &os, u8 version)
|
|||||||
paramdata[i] = data[i].param;
|
paramdata[i] = data[i].param;
|
||||||
}
|
}
|
||||||
compress(paramdata, os, version);
|
compress(paramdata, os, version);
|
||||||
|
|
||||||
|
if(version >= 10)
|
||||||
|
{
|
||||||
|
// Get and compress pressure
|
||||||
|
SharedBuffer<u8> pressuredata(nodecount);
|
||||||
|
for(u32 i=0; i<nodecount; i++)
|
||||||
|
{
|
||||||
|
pressuredata[i] = data[i].pressure;
|
||||||
|
}
|
||||||
|
compress(pressuredata, os, version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,6 +839,21 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
|
|||||||
data[i].param = s[i];
|
data[i].param = s[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(version >= 10)
|
||||||
|
{
|
||||||
|
// Uncompress and set pressure data
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
decompress(is, os, version);
|
||||||
|
std::string s = os.str();
|
||||||
|
if(s.size() != nodecount)
|
||||||
|
throw SerializationError
|
||||||
|
("MapBlock::deSerialize: invalid format");
|
||||||
|
for(u32 i=0; i<s.size(); i++)
|
||||||
|
{
|
||||||
|
data[i].pressure = s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "mapblockobject.h"
|
#include "mapblockobject.h"
|
||||||
|
#include "voxel.h"
|
||||||
|
|
||||||
#define MAP_BLOCKSIZE 16
|
#define MAP_BLOCKSIZE 16
|
||||||
|
|
||||||
@ -69,31 +70,6 @@ public:
|
|||||||
|
|
||||||
class MapBlock : public NodeContainer
|
class MapBlock : public NodeContainer
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
|
|
||||||
NodeContainer *m_parent;
|
|
||||||
// Position in blocks on parent
|
|
||||||
v3s16 m_pos;
|
|
||||||
/*
|
|
||||||
If NULL, block is a dummy block.
|
|
||||||
Dummy blocks are used for caching not-found-on-disk blocks.
|
|
||||||
*/
|
|
||||||
MapNode * data;
|
|
||||||
/*
|
|
||||||
- On the client, this is used for checking whether to
|
|
||||||
recalculate the face cache. (Is it anymore?)
|
|
||||||
- On the server, this is used for telling whether the
|
|
||||||
block has been changed from the one on disk.
|
|
||||||
*/
|
|
||||||
bool changed;
|
|
||||||
/*
|
|
||||||
Used for some initial lighting stuff.
|
|
||||||
At least /has been/ used. 8)
|
|
||||||
*/
|
|
||||||
bool is_underground;
|
|
||||||
|
|
||||||
MapBlockObjectList m_objects;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -333,10 +309,12 @@ public:
|
|||||||
|
|
||||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources);
|
bool propagateSunlight(core::map<v3s16, bool> & light_sources);
|
||||||
|
|
||||||
// Doesn't write version by itself
|
// Copies data to VoxelManipulator to getPosRelative()
|
||||||
void serialize(std::ostream &os, u8 version);
|
void copyTo(VoxelManipulator &dst);
|
||||||
|
|
||||||
void deSerialize(std::istream &is, u8 version);
|
/*
|
||||||
|
Object stuff
|
||||||
|
*/
|
||||||
|
|
||||||
void serializeObjects(std::ostream &os, u8 version)
|
void serializeObjects(std::ostream &os, u8 version)
|
||||||
{
|
{
|
||||||
@ -403,6 +381,15 @@ public:
|
|||||||
return m_objects.getCount();
|
return m_objects.getCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Serialization
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Doesn't write version by itself
|
||||||
|
void serialize(std::ostream &os, u8 version);
|
||||||
|
|
||||||
|
void deSerialize(std::istream &is, u8 version);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -420,6 +407,31 @@ private:
|
|||||||
{
|
{
|
||||||
return getNodeRef(p.X, p.Y, p.Z);
|
return getNodeRef(p.X, p.Y, p.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NodeContainer *m_parent;
|
||||||
|
// Position in blocks on parent
|
||||||
|
v3s16 m_pos;
|
||||||
|
/*
|
||||||
|
If NULL, block is a dummy block.
|
||||||
|
Dummy blocks are used for caching not-found-on-disk blocks.
|
||||||
|
*/
|
||||||
|
MapNode * data;
|
||||||
|
/*
|
||||||
|
- On the client, this is used for checking whether to
|
||||||
|
recalculate the face cache. (Is it anymore?)
|
||||||
|
- On the server, this is used for telling whether the
|
||||||
|
block has been changed from the one on disk.
|
||||||
|
*/
|
||||||
|
bool changed;
|
||||||
|
/*
|
||||||
|
Used for some initial lighting stuff.
|
||||||
|
At least /has been/ used. 8)
|
||||||
|
*/
|
||||||
|
bool is_underground;
|
||||||
|
|
||||||
|
MapBlockObjectList m_objects;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool blockpos_over_limit(v3s16 p)
|
inline bool blockpos_over_limit(v3s16 p)
|
||||||
|
@ -205,10 +205,11 @@ struct MapNode
|
|||||||
*this = n;
|
*this = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapNode(u8 data=MATERIAL_AIR, u8 a_param=0)
|
MapNode(u8 data=MATERIAL_AIR, u8 a_param=0, u8 a_pressure=0)
|
||||||
{
|
{
|
||||||
d = data;
|
d = data;
|
||||||
param = a_param;
|
param = a_param;
|
||||||
|
pressure = a_pressure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const MapNode &other)
|
bool operator==(const MapNode &other)
|
||||||
@ -261,6 +262,11 @@ struct MapNode
|
|||||||
param = a_light;
|
param = a_light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
These serialization functions are used when informing client
|
||||||
|
of a single node add
|
||||||
|
*/
|
||||||
|
|
||||||
static u32 serializedLength(u8 version)
|
static u32 serializedLength(u8 version)
|
||||||
{
|
{
|
||||||
if(!ser_ver_supported(version))
|
if(!ser_ver_supported(version))
|
||||||
@ -268,8 +274,10 @@ struct MapNode
|
|||||||
|
|
||||||
if(version == 0)
|
if(version == 0)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else if(version <= 9)
|
||||||
return 2;
|
return 2;
|
||||||
|
else
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
void serialize(u8 *dest, u8 version)
|
void serialize(u8 *dest, u8 version)
|
||||||
{
|
{
|
||||||
@ -280,10 +288,16 @@ struct MapNode
|
|||||||
{
|
{
|
||||||
dest[0] = d;
|
dest[0] = d;
|
||||||
}
|
}
|
||||||
|
else if(version <= 9)
|
||||||
|
{
|
||||||
|
dest[0] = d;
|
||||||
|
dest[1] = param;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dest[0] = d;
|
dest[0] = d;
|
||||||
dest[1] = param;
|
dest[1] = param;
|
||||||
|
dest[2] = pressure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void deSerialize(u8 *source, u8 version)
|
void deSerialize(u8 *source, u8 version)
|
||||||
@ -304,10 +318,16 @@ struct MapNode
|
|||||||
else
|
else
|
||||||
param = source[1];
|
param = source[1];
|
||||||
}
|
}
|
||||||
|
else if(version <= 9)
|
||||||
|
{
|
||||||
|
d = source[0];
|
||||||
|
param = source[1];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d = source[0];
|
d = source[0];
|
||||||
param = source[1];
|
param = source[1];
|
||||||
|
pressure = source[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -46,11 +46,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
7: block compression switched on again
|
7: block compression switched on again
|
||||||
8: (dev) server-initiated block transfers and all kinds of stuff
|
8: (dev) server-initiated block transfers and all kinds of stuff
|
||||||
9: (dev) block objects
|
9: (dev) block objects
|
||||||
|
10: (dev) water pressure
|
||||||
*/
|
*/
|
||||||
// This represents an uninitialized or invalid format
|
// This represents an uninitialized or invalid format
|
||||||
#define SER_FMT_VER_INVALID 255
|
#define SER_FMT_VER_INVALID 255
|
||||||
// Highest supported serialization version
|
// Highest supported serialization version
|
||||||
#define SER_FMT_VER_HIGHEST 9
|
#define SER_FMT_VER_HIGHEST 10
|
||||||
// Lowest supported serialization version
|
// Lowest supported serialization version
|
||||||
#define SER_FMT_VER_LOWEST 2
|
#define SER_FMT_VER_LOWEST 2
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "jmutexautolock.h"
|
#include "jmutexautolock.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "voxel.h"
|
||||||
|
|
||||||
void * ServerThread::Thread()
|
void * ServerThread::Thread()
|
||||||
{
|
{
|
||||||
@ -991,6 +992,76 @@ void Server::AsyncRunStep()
|
|||||||
Do background stuff
|
Do background stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Flow water
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
static float counter = 0.0;
|
||||||
|
counter += dtime;
|
||||||
|
if(counter >= 1.0)
|
||||||
|
{
|
||||||
|
|
||||||
|
counter = 0.0;
|
||||||
|
|
||||||
|
core::map<v3s16, MapBlock*> modified_blocks;
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
JMutexAutoLock lock(m_env_mutex);
|
||||||
|
|
||||||
|
MapVoxelManipulator v(&m_env.getMap());
|
||||||
|
|
||||||
|
/*try{
|
||||||
|
v.flowWater(m_flow_active_nodes, 0, false, 20);
|
||||||
|
//v.flowWater(p_under, 0, true, 100);
|
||||||
|
}
|
||||||
|
catch(ProcessingLimitException &e)
|
||||||
|
{
|
||||||
|
dstream<<"Processing limit reached"<<std::endl;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
v.flowWater(m_flow_active_nodes, 0, false, 20);
|
||||||
|
|
||||||
|
v.blitBack(modified_blocks);
|
||||||
|
|
||||||
|
ServerMap &map = ((ServerMap&)m_env.getMap());
|
||||||
|
|
||||||
|
// Update lighting
|
||||||
|
core::map<v3s16, MapBlock*> lighting_modified_blocks;
|
||||||
|
map.updateLighting(modified_blocks, lighting_modified_blocks);
|
||||||
|
|
||||||
|
// Add blocks modified by lighting to modified_blocks
|
||||||
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
|
i = lighting_modified_blocks.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
MapBlock *block = i.getNode()->getValue();
|
||||||
|
modified_blocks.insert(block->getPos(), block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the modified blocks unsent for all the clients
|
||||||
|
*/
|
||||||
|
|
||||||
|
JMutexAutoLock lock2(m_con_mutex);
|
||||||
|
|
||||||
|
for(core::map<u16, RemoteClient*>::Iterator
|
||||||
|
i = m_clients.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
RemoteClient *client = i.getNode()->getValue();
|
||||||
|
|
||||||
|
if(modified_blocks.size() > 0)
|
||||||
|
{
|
||||||
|
// Remove block from sent history
|
||||||
|
client->SetBlocksNotSent(modified_blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Periodically print some info
|
// Periodically print some info
|
||||||
{
|
{
|
||||||
static float counter = 0.0;
|
static float counter = 0.0;
|
||||||
@ -1459,6 +1530,31 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
*/
|
*/
|
||||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update water
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Update water pressure around modification
|
||||||
|
// This also adds it to m_flow_active_nodes if appropriate
|
||||||
|
|
||||||
|
MapVoxelManipulator v(&m_env.getMap());
|
||||||
|
|
||||||
|
VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
v.updateAreaWaterPressure(area, m_flow_active_nodes);
|
||||||
|
}
|
||||||
|
catch(ProcessingLimitException &e)
|
||||||
|
{
|
||||||
|
dstream<<"Processing limit reached"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.blitBack(modified_blocks);
|
||||||
|
|
||||||
|
// Add the node to m_flow_active_nodes.
|
||||||
|
//m_flow_active_nodes[p_under] = 1;
|
||||||
|
|
||||||
} // button == 0
|
} // button == 0
|
||||||
/*
|
/*
|
||||||
Right button places blocks and stuff
|
Right button places blocks and stuff
|
||||||
|
@ -469,6 +469,9 @@ private:
|
|||||||
|
|
||||||
BlockEmergeQueue m_emerge_queue;
|
BlockEmergeQueue m_emerge_queue;
|
||||||
|
|
||||||
|
// Nodes that are destinations of flowing liquid at the moment
|
||||||
|
core::map<v3s16, u8> m_flow_active_nodes;
|
||||||
|
|
||||||
friend class EmergeThread;
|
friend class EmergeThread;
|
||||||
friend class RemoteClient;
|
friend class RemoteClient;
|
||||||
};
|
};
|
||||||
|
75
src/test.cpp
75
src/test.cpp
@ -148,10 +148,45 @@ struct TestVoxelManipulator
|
|||||||
{
|
{
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
VoxelArea
|
||||||
|
*/
|
||||||
|
|
||||||
VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1));
|
VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1));
|
||||||
assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1);
|
assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1);
|
||||||
assert(a.index(-1,-1,-1) == 0);
|
assert(a.index(-1,-1,-1) == 0);
|
||||||
|
|
||||||
|
VoxelArea c(v3s16(-2,-2,-2), v3s16(2,2,2));
|
||||||
|
// An area that is 1 bigger in x+ and z-
|
||||||
|
VoxelArea d(v3s16(-2,-2,-3), v3s16(3,2,2));
|
||||||
|
|
||||||
|
core::list<VoxelArea> aa;
|
||||||
|
d.diff(c, aa);
|
||||||
|
|
||||||
|
// Correct results
|
||||||
|
core::array<VoxelArea> results;
|
||||||
|
results.push_back(VoxelArea(v3s16(-2,-2,-3),v3s16(3,2,-3)));
|
||||||
|
results.push_back(VoxelArea(v3s16(3,-2,-2),v3s16(3,2,2)));
|
||||||
|
|
||||||
|
assert(aa.size() == results.size());
|
||||||
|
|
||||||
|
dstream<<"Result of diff:"<<std::endl;
|
||||||
|
for(core::list<VoxelArea>::Iterator
|
||||||
|
i = aa.begin(); i != aa.end(); i++)
|
||||||
|
{
|
||||||
|
i->print(dstream);
|
||||||
|
dstream<<std::endl;
|
||||||
|
|
||||||
|
s32 j = results.linear_search(*i);
|
||||||
|
assert(j != -1);
|
||||||
|
results.erase(j, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
VoxelManipulator
|
||||||
|
*/
|
||||||
|
|
||||||
VoxelManipulator v;
|
VoxelManipulator v;
|
||||||
|
|
||||||
v.print(dstream);
|
v.print(dstream);
|
||||||
@ -186,18 +221,19 @@ struct TestVoxelManipulator
|
|||||||
v.clear();
|
v.clear();
|
||||||
|
|
||||||
const char *content =
|
const char *content =
|
||||||
"#...######"
|
"#...###### "
|
||||||
"#...##..##"
|
"#...##..## "
|
||||||
"#........ "
|
"#........ .."
|
||||||
"##########"
|
"############"
|
||||||
|
|
||||||
"#...######"
|
"#...###### "
|
||||||
"#...##..##"
|
"#...##..## "
|
||||||
"#........ "
|
"#........# "
|
||||||
"##########"
|
"############"
|
||||||
;
|
;
|
||||||
|
|
||||||
v3s16 size(10, 4, 2);
|
v3s16 size(12, 4, 2);
|
||||||
|
VoxelArea area(v3s16(0,0,0), size-v3s16(1,1,1));
|
||||||
|
|
||||||
const char *p = content;
|
const char *p = content;
|
||||||
for(s16 z=0; z<size.Z; z++)
|
for(s16 z=0; z<size.Z; z++)
|
||||||
@ -205,7 +241,7 @@ struct TestVoxelManipulator
|
|||||||
for(s16 x=0; x<size.X; x++)
|
for(s16 x=0; x<size.X; x++)
|
||||||
{
|
{
|
||||||
MapNode n;
|
MapNode n;
|
||||||
n.pressure = size.Y - y;
|
//n.pressure = size.Y - y;
|
||||||
if(*p == '#')
|
if(*p == '#')
|
||||||
n.d = MATERIAL_STONE;
|
n.d = MATERIAL_STONE;
|
||||||
else if(*p == '.')
|
else if(*p == '.')
|
||||||
@ -218,7 +254,24 @@ struct TestVoxelManipulator
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
v.print(dstream);
|
v.print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
|
||||||
|
core::map<v3s16, u8> active_nodes;
|
||||||
|
v.updateAreaWaterPressure(area, active_nodes);
|
||||||
|
|
||||||
|
v.print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
|
||||||
|
s16 highest_y = -32768;
|
||||||
|
assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == -1);
|
||||||
|
assert(highest_y == 3);
|
||||||
|
|
||||||
|
active_nodes.clear();
|
||||||
|
active_nodes[v3s16(9,1,0)] = 1;
|
||||||
|
//v.flowWater(active_nodes, 0, false);
|
||||||
|
v.flowWater(active_nodes, 0, true);
|
||||||
|
|
||||||
|
dstream<<"Final result of flowWater:"<<std::endl;
|
||||||
|
v.print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
|
||||||
//assert(0);
|
//assert(0);
|
||||||
}
|
}
|
||||||
|
@ -394,12 +394,18 @@ private:
|
|||||||
class TimeTaker
|
class TimeTaker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TimeTaker(const char *name, IrrlichtDevice *dev)
|
TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_dev = dev;
|
m_dev = dev;
|
||||||
m_time1 = m_dev->getTimer()->getRealTime();
|
m_result = result;
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
if(dev == NULL)
|
||||||
|
{
|
||||||
|
m_time1 = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_time1 = m_dev->getTimer()->getRealTime();
|
||||||
}
|
}
|
||||||
~TimeTaker()
|
~TimeTaker()
|
||||||
{
|
{
|
||||||
@ -409,10 +415,24 @@ public:
|
|||||||
{
|
{
|
||||||
if(m_running)
|
if(m_running)
|
||||||
{
|
{
|
||||||
|
if(m_dev == NULL)
|
||||||
|
{
|
||||||
|
/*if(quiet == false)
|
||||||
|
std::cout<<"Couldn't measure time for "<<m_name
|
||||||
|
<<": dev==NULL"<<std::endl;*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
u32 time2 = m_dev->getTimer()->getRealTime();
|
u32 time2 = m_dev->getTimer()->getRealTime();
|
||||||
u32 dtime = time2 - m_time1;
|
u32 dtime = time2 - m_time1;
|
||||||
|
if(m_result != NULL)
|
||||||
|
{
|
||||||
|
(*m_result) += dtime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if(quiet == false)
|
if(quiet == false)
|
||||||
std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
|
std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
|
||||||
|
}
|
||||||
m_running = false;
|
m_running = false;
|
||||||
return dtime;
|
return dtime;
|
||||||
}
|
}
|
||||||
@ -423,6 +443,7 @@ private:
|
|||||||
IrrlichtDevice *m_dev;
|
IrrlichtDevice *m_dev;
|
||||||
u32 m_time1;
|
u32 m_time1;
|
||||||
bool m_running;
|
bool m_running;
|
||||||
|
u32 *m_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculates the borders of a "d-radius" cube
|
// Calculates the borders of a "d-radius" cube
|
||||||
|
790
src/voxel.cpp
790
src/voxel.cpp
@ -20,6 +20,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
|
||||||
|
// For TimeTaker
|
||||||
|
#include "main.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Debug stuff
|
||||||
|
*/
|
||||||
|
u32 addarea_time = 0;
|
||||||
|
u32 emerge_time = 0;
|
||||||
|
u32 emerge_load_time = 0;
|
||||||
|
u32 clearflag_time = 0;
|
||||||
|
//u32 getwaterpressure_time = 0;
|
||||||
|
//u32 spreadwaterpressure_time = 0;
|
||||||
|
u32 updateareawaterpressure_time = 0;
|
||||||
|
u32 flowwater_pre_time = 0;
|
||||||
|
|
||||||
|
|
||||||
VoxelManipulator::VoxelManipulator():
|
VoxelManipulator::VoxelManipulator():
|
||||||
m_data(NULL),
|
m_data(NULL),
|
||||||
m_flags(NULL)
|
m_flags(NULL)
|
||||||
@ -47,7 +64,7 @@ void VoxelManipulator::clear()
|
|||||||
m_flags = NULL;
|
m_flags = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelManipulator::print(std::ostream &o)
|
void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
|
||||||
{
|
{
|
||||||
v3s16 em = m_area.getExtent();
|
v3s16 em = m_area.getExtent();
|
||||||
v3s16 of = m_area.MinEdge;
|
v3s16 of = m_area.MinEdge;
|
||||||
@ -78,9 +95,30 @@ void VoxelManipulator::print(std::ostream &o)
|
|||||||
{
|
{
|
||||||
c = 'X';
|
c = 'X';
|
||||||
u8 m = m_data[m_area.index(x,y,z)].d;
|
u8 m = m_data[m_area.index(x,y,z)].d;
|
||||||
|
u8 pr = m_data[m_area.index(x,y,z)].pressure;
|
||||||
|
if(mode == VOXELPRINT_MATERIAL)
|
||||||
|
{
|
||||||
if(m <= 9)
|
if(m <= 9)
|
||||||
c = m + '0';
|
c = m + '0';
|
||||||
}
|
}
|
||||||
|
else if(mode == VOXELPRINT_WATERPRESSURE)
|
||||||
|
{
|
||||||
|
if(m == MATERIAL_WATER)
|
||||||
|
{
|
||||||
|
c = 'w';
|
||||||
|
if(pr <= 9)
|
||||||
|
c = pr + '0';
|
||||||
|
}
|
||||||
|
else if(m == MATERIAL_AIR)
|
||||||
|
{
|
||||||
|
c = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
o<<c;
|
o<<c;
|
||||||
}
|
}
|
||||||
o<<' ';
|
o<<' ';
|
||||||
@ -99,6 +137,8 @@ void VoxelManipulator::addArea(VoxelArea area)
|
|||||||
if(m_area.contains(area))
|
if(m_area.contains(area))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
TimeTaker timer("addArea", g_device, &addarea_time);
|
||||||
|
|
||||||
// Calculate new area
|
// Calculate new area
|
||||||
VoxelArea new_area;
|
VoxelArea new_area;
|
||||||
// New area is the requested area if m_area has zero volume
|
// New area is the requested area if m_area has zero volume
|
||||||
@ -163,6 +203,21 @@ void VoxelManipulator::addArea(VoxelArea area)
|
|||||||
delete[] old_data;
|
delete[] old_data;
|
||||||
if(old_flags)
|
if(old_flags)
|
||||||
delete[] old_flags;
|
delete[] old_flags;
|
||||||
|
|
||||||
|
//dstream<<"addArea done"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelManipulator::copyFrom(MapNode *src, VoxelArea src_area,
|
||||||
|
v3s16 from_pos, v3s16 to_pos, v3s16 size)
|
||||||
|
{
|
||||||
|
for(s16 z=0; z<size.Z; z++)
|
||||||
|
for(s16 y=0; y<size.Y; y++)
|
||||||
|
{
|
||||||
|
s32 i_src = src_area.index(from_pos.X, from_pos.Y+y, from_pos.Z+z);
|
||||||
|
s32 i_local = m_area.index(to_pos.X, to_pos.Y+y, to_pos.Z+z);
|
||||||
|
memcpy(&m_data[i_local], &src[i_src], size.X*sizeof(MapNode));
|
||||||
|
memset(&m_flags[i_local], 0, size.X);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelManipulator::interpolate(VoxelArea area)
|
void VoxelManipulator::interpolate(VoxelArea area)
|
||||||
@ -230,7 +285,318 @@ void VoxelManipulator::interpolate(VoxelArea area)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelManipulator::flowWater(v3s16 removed_pos)
|
|
||||||
|
void VoxelManipulator::clearFlag(u8 flags)
|
||||||
|
{
|
||||||
|
// 0-1ms on moderate area
|
||||||
|
TimeTaker timer("clearFlag", g_device, &clearflag_time);
|
||||||
|
|
||||||
|
v3s16 s = m_area.getExtent();
|
||||||
|
|
||||||
|
/*dstream<<"clearFlag clearing area of size "
|
||||||
|
<<""<<s.X<<"x"<<s.Y<<"x"<<s.Z<<""
|
||||||
|
<<std::endl;*/
|
||||||
|
|
||||||
|
//s32 count = 0;
|
||||||
|
|
||||||
|
/*for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
u8 f = m_flags[m_area.index(x,y,z)];
|
||||||
|
m_flags[m_area.index(x,y,z)] &= ~flags;
|
||||||
|
if(m_flags[m_area.index(x,y,z)] != f)
|
||||||
|
count++;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
s32 volume = m_area.getVolume();
|
||||||
|
for(s32 i=0; i<volume; i++)
|
||||||
|
{
|
||||||
|
m_flags[i] &= ~flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*s32 volume = m_area.getVolume();
|
||||||
|
for(s32 i=0; i<volume; i++)
|
||||||
|
{
|
||||||
|
u8 f = m_flags[i];
|
||||||
|
m_flags[i] &= ~flags;
|
||||||
|
if(m_flags[i] != f)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
dstream<<"clearFlag changed "<<count<<" flags out of "
|
||||||
|
<<volume<<" nodes"<<std::endl;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
|
||||||
|
{
|
||||||
|
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED2;
|
||||||
|
|
||||||
|
if(p.Y > highest_y)
|
||||||
|
highest_y = p.Y;
|
||||||
|
|
||||||
|
recur_count++;
|
||||||
|
if(recur_count > 30)
|
||||||
|
throw ProcessingLimitException
|
||||||
|
("getWaterPressure recur_count limit reached");
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load neighboring nodes
|
||||||
|
// TODO: A bigger area would be better
|
||||||
|
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
|
||||||
|
|
||||||
|
s32 i;
|
||||||
|
for(i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
v3s16 p2 = p + dirs[i];
|
||||||
|
u8 f = m_flags[m_area.index(p2)];
|
||||||
|
// Ignore inexistent or checked nodes
|
||||||
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED2))
|
||||||
|
continue;
|
||||||
|
MapNode &n = m_data[m_area.index(p2)];
|
||||||
|
// Ignore non-liquid nodes
|
||||||
|
if(material_liquid(n.d) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int pr;
|
||||||
|
|
||||||
|
// If at surface
|
||||||
|
/*if(n.pressure == 1)
|
||||||
|
{
|
||||||
|
pr = 1;
|
||||||
|
}
|
||||||
|
// Otherwise recurse more
|
||||||
|
else*/
|
||||||
|
{
|
||||||
|
pr = getWaterPressure(p2, highest_y, recur_count);
|
||||||
|
if(pr == -1)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If block is at top, pressure here is one higher
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
if(pr < 255)
|
||||||
|
pr++;
|
||||||
|
}
|
||||||
|
// If block is at bottom, pressure here is one lower
|
||||||
|
else if(i == 5)
|
||||||
|
{
|
||||||
|
if(pr > 1)
|
||||||
|
pr--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node is on the pressure route
|
||||||
|
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED4;
|
||||||
|
|
||||||
|
// Got pressure
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing useful found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||||
|
VoxelArea request_area,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recur_count)
|
||||||
|
{
|
||||||
|
recur_count++;
|
||||||
|
if(recur_count > 10000)
|
||||||
|
throw ProcessingLimitException
|
||||||
|
("spreadWaterPressure recur_count limit reached");
|
||||||
|
|
||||||
|
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
|
||||||
|
m_data[m_area.index(p)].pressure = pr;
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load neighboring nodes
|
||||||
|
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
|
||||||
|
|
||||||
|
s32 i;
|
||||||
|
for(i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
v3s16 p2 = p + dirs[i];
|
||||||
|
|
||||||
|
u8 f = m_flags[m_area.index(p2)];
|
||||||
|
|
||||||
|
// Ignore inexistent and checked nodes
|
||||||
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MapNode &n = m_data[m_area.index(p2)];
|
||||||
|
|
||||||
|
/*
|
||||||
|
If material is air:
|
||||||
|
add to active_nodes if there is flow-causing pressure.
|
||||||
|
NOTE: Do not remove anything from there. We cannot know
|
||||||
|
here if some other neighbor of it causes flow.
|
||||||
|
*/
|
||||||
|
if(n.d == MATERIAL_AIR)
|
||||||
|
{
|
||||||
|
bool pressure_causes_flow = false;
|
||||||
|
// If block is at top
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
if(pr >= 3)
|
||||||
|
pressure_causes_flow = true;
|
||||||
|
}
|
||||||
|
// If block is at bottom
|
||||||
|
else if(i == 5)
|
||||||
|
{
|
||||||
|
pressure_causes_flow = true;
|
||||||
|
}
|
||||||
|
// If block is at side
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(pr >= 2)
|
||||||
|
pressure_causes_flow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pressure_causes_flow)
|
||||||
|
{
|
||||||
|
active_nodes[p2] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore non-liquid nodes
|
||||||
|
if(material_liquid(n.d) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int pr2 = pr;
|
||||||
|
// If block is at top, pressure there is lower
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
if(pr2 > 0)
|
||||||
|
pr2--;
|
||||||
|
}
|
||||||
|
// If block is at bottom, pressure there is higher
|
||||||
|
else if(i == 5)
|
||||||
|
{
|
||||||
|
if(pr2 < 255)
|
||||||
|
pr2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if correct pressure is already set and is not on
|
||||||
|
// request_area
|
||||||
|
if(n.pressure == pr2 && request_area.contains(p2) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
spreadWaterPressure(p2, pr2, request_area, active_nodes, recur_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
bool checked3_is_clear)
|
||||||
|
{
|
||||||
|
TimeTaker timer("updateAreaWaterPressure", g_device,
|
||||||
|
&updateareawaterpressure_time);
|
||||||
|
|
||||||
|
emerge(a);
|
||||||
|
|
||||||
|
bool checked2_clear = false;
|
||||||
|
|
||||||
|
if(checked3_is_clear == false)
|
||||||
|
{
|
||||||
|
//clearFlag(VOXELFLAG_CHECKED3);
|
||||||
|
|
||||||
|
clearFlag(VOXELFLAG_CHECKED3 | VOXELFLAG_CHECKED2);
|
||||||
|
checked2_clear = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
v3s16 p(x,y,z);
|
||||||
|
|
||||||
|
u8 f = m_flags[m_area.index(p)];
|
||||||
|
// Ignore inexistent or checked nodes
|
||||||
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
|
||||||
|
continue;
|
||||||
|
MapNode &n = m_data[m_area.index(p)];
|
||||||
|
// Ignore non-liquid nodes
|
||||||
|
if(material_liquid(n.d) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(checked2_clear == false)
|
||||||
|
{
|
||||||
|
clearFlag(VOXELFLAG_CHECKED2);
|
||||||
|
checked2_clear = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
checked2_clear = false;
|
||||||
|
|
||||||
|
s16 highest_y = -32768;
|
||||||
|
int recur_count = 0;
|
||||||
|
int pr = -1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 0-1ms @ recur_count <= 100
|
||||||
|
//TimeTaker timer("getWaterPressure", g_device);
|
||||||
|
pr = getWaterPressure(p, highest_y, recur_count);
|
||||||
|
}
|
||||||
|
catch(ProcessingLimitException &e)
|
||||||
|
{
|
||||||
|
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pr == -1)
|
||||||
|
{
|
||||||
|
assert(highest_y != -32768);
|
||||||
|
|
||||||
|
pr = highest_y - p.Y + 1;
|
||||||
|
if(pr > 255)
|
||||||
|
pr = 255;
|
||||||
|
|
||||||
|
/*dstream<<"WARNING: Pressure at ("
|
||||||
|
<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||||
|
<<" = "<<pr
|
||||||
|
//<<" and highest_y == -32768"
|
||||||
|
<<std::endl;
|
||||||
|
assert(highest_y != -32768);
|
||||||
|
continue;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 0ms
|
||||||
|
//TimeTaker timer("spreadWaterPressure", g_device);
|
||||||
|
spreadWaterPressure(p, pr, a, active_nodes, 0);
|
||||||
|
}
|
||||||
|
catch(ProcessingLimitException &e)
|
||||||
|
{
|
||||||
|
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recursion_depth, bool debugprint,
|
||||||
|
int *counter, int counterlimit)
|
||||||
{
|
{
|
||||||
v3s16 dirs[6] = {
|
v3s16 dirs[6] = {
|
||||||
v3s16(0,1,0), // top
|
v3s16(0,1,0), // top
|
||||||
@ -241,16 +607,43 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
|||||||
v3s16(0,-1,0), // bottom
|
v3s16(0,-1,0), // bottom
|
||||||
};
|
};
|
||||||
|
|
||||||
|
recursion_depth++;
|
||||||
|
|
||||||
v3s16 p;
|
v3s16 p;
|
||||||
|
|
||||||
|
// Randomize horizontal order
|
||||||
|
static s32 cs = 0;
|
||||||
|
if(cs < 3)
|
||||||
|
cs++;
|
||||||
|
else
|
||||||
|
cs = 0;
|
||||||
|
s16 s1 = (cs & 1) ? 1 : -1;
|
||||||
|
s16 s2 = (cs & 2) ? 1 : -1;
|
||||||
|
//dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
|
||||||
|
|
||||||
// Load neighboring nodes
|
// Load neighboring nodes
|
||||||
// TODO: A bigger area would be better
|
|
||||||
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
|
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
|
||||||
|
|
||||||
|
// Ignore incorrect removed_pos
|
||||||
|
{
|
||||||
|
u8 f = m_flags[m_area.index(removed_pos)];
|
||||||
|
// Ignore inexistent or checked node
|
||||||
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
||||||
|
return false;
|
||||||
|
MapNode &n = m_data[m_area.index(removed_pos)];
|
||||||
|
// Water can move only to air
|
||||||
|
if(n.d != MATERIAL_AIR)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
s32 i;
|
s32 i;
|
||||||
for(i=0; i<6; i++)
|
for(i=0; i<6; i++)
|
||||||
{
|
{
|
||||||
p = removed_pos + dirs[i];
|
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
u8 f = m_flags[m_area.index(p)];
|
||||||
// Inexistent or checked nodes can't move
|
// Inexistent or checked nodes can't move
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
||||||
@ -280,30 +673,66 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
|||||||
|
|
||||||
// If there is nothing to move, return
|
// If there is nothing to move, return
|
||||||
if(i==6)
|
if(i==6)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Switch nodes at p and removed_pos
|
// Switch nodes at p and removed_pos
|
||||||
MapNode n = m_data[m_area.index(p)];
|
u8 m = m_data[m_area.index(p)].d;
|
||||||
u8 f = m_flags[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_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
|
||||||
m_flags[m_area.index(p)] = m_flags[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_data[m_area.index(removed_pos)].d = m;
|
||||||
m_flags[m_area.index(removed_pos)] = f;
|
m_flags[m_area.index(removed_pos)] = f;
|
||||||
|
|
||||||
// Mark p checked
|
// Mark removed_pos checked
|
||||||
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED;
|
m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
|
||||||
|
// If block was dropped from surface, increase pressure
|
||||||
|
if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
|
||||||
|
{
|
||||||
|
m_data[m_area.index(removed_pos)].pressure = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
}*/
|
||||||
|
|
||||||
// Update pressure
|
// Update pressure
|
||||||
//TODO
|
VoxelArea a;
|
||||||
|
a.addPoint(p - v3s16(1,1,1));
|
||||||
|
a.addPoint(p + v3s16(1,1,1));
|
||||||
|
a.addPoint(removed_pos - v3s16(1,1,1));
|
||||||
|
a.addPoint(removed_pos + v3s16(1,1,1));
|
||||||
|
updateAreaWaterPressure(a, active_nodes);
|
||||||
|
|
||||||
|
/*if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
//std::cin.get();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
//std::cin.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}//timer1
|
||||||
|
|
||||||
// Flow water to the newly created empty position
|
// Flow water to the newly created empty position
|
||||||
flowWater(p);
|
flowWater(p, active_nodes, recursion_depth,
|
||||||
|
debugprint, counter, counterlimit);
|
||||||
|
|
||||||
|
find_again:
|
||||||
// Try flowing water to empty positions around removed_pos.
|
// Try flowing water to empty positions around removed_pos.
|
||||||
// They are checked in reverse order compared to the previous loop.
|
// They are checked in reverse order compared to the previous loop.
|
||||||
for(i=5; i>=0; i--)
|
for(s32 i=5; i>=0; i--)
|
||||||
{
|
{
|
||||||
p = removed_pos + dirs[i];
|
//v3s16 p = removed_pos + dirs[i];
|
||||||
|
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
u8 f = m_flags[m_area.index(p)];
|
||||||
// Water can't move to inexistent nodes
|
// Water can't move to inexistent nodes
|
||||||
if(f & VOXELFLAG_INEXISTENT)
|
if(f & VOXELFLAG_INEXISTENT)
|
||||||
@ -312,102 +741,291 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
|||||||
// Water can only move to air
|
// Water can only move to air
|
||||||
if(n.d != MATERIAL_AIR)
|
if(n.d != MATERIAL_AIR)
|
||||||
continue;
|
continue;
|
||||||
flowWater(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// Flow water to node
|
||||||
MapVoxelManipulator
|
bool moved =
|
||||||
*/
|
flowWater(p, active_nodes, recursion_depth,
|
||||||
|
debugprint, counter, counterlimit);
|
||||||
|
|
||||||
MapVoxelManipulator::MapVoxelManipulator(Map *map)
|
if(moved)
|
||||||
{
|
|
||||||
m_map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapVoxelManipulator::emerge(VoxelArea a)
|
|
||||||
{
|
|
||||||
v3s16 size = a.getExtent();
|
|
||||||
|
|
||||||
addArea(a);
|
|
||||||
|
|
||||||
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 p(x,y,z);
|
// Search again from all neighbors
|
||||||
s32 i = m_area.index(a.MinEdge + p);
|
goto find_again;
|
||||||
// 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[i] = n;
|
|
||||||
m_flags[i] = 0;
|
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
}
|
||||||
|
|
||||||
|
if(counter != NULL)
|
||||||
{
|
{
|
||||||
m_flags[i] = VOXELFLAG_INEXISTENT;
|
(*counter)++;
|
||||||
|
if((*counter) % 10 == 0)
|
||||||
|
dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
if(counterlimit != -1 && (*counter) > counterlimit)
|
||||||
|
{
|
||||||
|
dstream<<"Counter limit reached; returning"<<std::endl;
|
||||||
|
throw ProcessingLimitException("flowWater counterlimit reached");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||||
void MapVoxelManipulator::blitBack
|
core::map<v3s16, u8> &active_nodes,
|
||||||
(core::map<v3s16, MapBlock*> & modified_blocks)
|
int recursion_depth, bool debugprint,
|
||||||
|
int *counter, int counterlimit)
|
||||||
{
|
{
|
||||||
/*
|
v3s16 dirs[6] = {
|
||||||
Initialize block cache
|
v3s16(0,1,0), // top
|
||||||
*/
|
v3s16(-1,0,0), // left
|
||||||
v3s16 blockpos_last;
|
v3s16(1,0,0), // right
|
||||||
MapBlock *block = NULL;
|
v3s16(0,0,-1), // front
|
||||||
bool block_checked_in_modified = false;
|
v3s16(0,0,1), // back
|
||||||
|
v3s16(0,-1,0), // bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
recursion_depth++;
|
||||||
|
|
||||||
|
v3s16 p;
|
||||||
|
|
||||||
|
// Randomize horizontal order
|
||||||
|
static s32 cs = 0;
|
||||||
|
if(cs < 3)
|
||||||
|
cs++;
|
||||||
|
else
|
||||||
|
cs = 0;
|
||||||
|
s16 s1 = (cs & 1) ? 1 : -1;
|
||||||
|
s16 s2 = (cs & 2) ? 1 : -1;
|
||||||
|
//dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
|
||||||
|
|
||||||
for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
|
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
v3s16 p(x,y,z);
|
TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
|
||||||
|
|
||||||
|
// Load neighboring nodes
|
||||||
|
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
|
||||||
|
|
||||||
|
// Ignore incorrect removed_pos
|
||||||
|
{
|
||||||
|
u8 f = m_flags[m_area.index(removed_pos)];
|
||||||
|
// Ignore inexistent or checked node
|
||||||
|
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
||||||
|
return false;
|
||||||
|
MapNode &n = m_data[m_area.index(removed_pos)];
|
||||||
|
// Water can move only to air
|
||||||
|
if(n.d != MATERIAL_AIR)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 i;
|
||||||
|
for(i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
u8 f = m_flags[m_area.index(p)];
|
||||||
if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
|
// 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;
|
||||||
|
}
|
||||||
|
// If block is at bottom, select it if it has enough pressure
|
||||||
|
if(i == 5)
|
||||||
|
{
|
||||||
|
if(n.pressure >= 3)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Else block is at some side. Select it if it has enough pressure
|
||||||
|
if(n.pressure >= 2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is nothing to move, return
|
||||||
|
if(i==6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Switch nodes at p and removed_pos
|
||||||
|
u8 m = m_data[m_area.index(p)].d;
|
||||||
|
u8 f = m_flags[m_area.index(p)];
|
||||||
|
m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
|
||||||
|
m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
|
||||||
|
m_data[m_area.index(removed_pos)].d = m;
|
||||||
|
m_flags[m_area.index(removed_pos)] = f;
|
||||||
|
|
||||||
|
// Mark removed_pos checked
|
||||||
|
m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
|
||||||
|
// If block was dropped from surface, increase pressure
|
||||||
|
if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
|
||||||
|
{
|
||||||
|
m_data[m_area.index(removed_pos)].pressure = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Update pressure
|
||||||
|
VoxelArea a;
|
||||||
|
a.addPoint(p - v3s16(1,1,1));
|
||||||
|
a.addPoint(p + v3s16(1,1,1));
|
||||||
|
a.addPoint(removed_pos - v3s16(1,1,1));
|
||||||
|
a.addPoint(removed_pos + v3s16(1,1,1));
|
||||||
|
updateAreaWaterPressure(a, active_nodes);
|
||||||
|
|
||||||
|
/*if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
//std::cin.get();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if(debugprint)
|
||||||
|
{
|
||||||
|
dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
|
||||||
|
print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||||
|
//std::cin.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}//timer1
|
||||||
|
|
||||||
|
// Flow water to the newly created empty position
|
||||||
|
flowWater(p, active_nodes, recursion_depth,
|
||||||
|
debugprint, counter, counterlimit);
|
||||||
|
|
||||||
|
find_again:
|
||||||
|
// Try flowing water to empty positions around removed_pos.
|
||||||
|
// They are checked in reverse order compared to the previous loop.
|
||||||
|
for(s32 i=5; i>=0; i--)
|
||||||
|
{
|
||||||
|
//v3s16 p = removed_pos + dirs[i];
|
||||||
|
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
|
||||||
|
|
||||||
|
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;
|
continue;
|
||||||
|
|
||||||
MapNode &n = m_data[m_area.index(p)];
|
// Flow water to node
|
||||||
|
bool moved =
|
||||||
|
flowWater(p, active_nodes, recursion_depth,
|
||||||
|
debugprint, counter, counterlimit);
|
||||||
|
|
||||||
v3s16 blockpos = getNodeBlockPos(p);
|
if(moved)
|
||||||
|
{
|
||||||
|
// Search again from all neighbors
|
||||||
|
goto find_again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(counter != NULL)
|
||||||
|
{
|
||||||
|
(*counter)++;
|
||||||
|
if((*counter) % 10 == 0)
|
||||||
|
dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
if(counterlimit != -1 && (*counter) > counterlimit)
|
||||||
|
{
|
||||||
|
dstream<<"Counter limit reached; returning"<<std::endl;
|
||||||
|
throw ProcessingLimitException("flowWater counterlimit reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelManipulator::flowWater(
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recursion_depth, bool debugprint,
|
||||||
|
int counterlimit)
|
||||||
|
{
|
||||||
|
addarea_time = 0;
|
||||||
|
emerge_time = 0;
|
||||||
|
emerge_load_time = 0;
|
||||||
|
clearflag_time = 0;
|
||||||
|
updateareawaterpressure_time = 0;
|
||||||
|
flowwater_pre_time = 0;
|
||||||
|
|
||||||
|
TimeTaker timer1("flowWater (active_nodes)", g_device);
|
||||||
|
|
||||||
|
dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get block
|
|
||||||
if(block == NULL || blockpos != blockpos_last){
|
|
||||||
block = m_map->getBlockNoCreate(blockpos);
|
|
||||||
blockpos_last = blockpos;
|
|
||||||
block_checked_in_modified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate relative position in block
|
// Flow water to active nodes
|
||||||
v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
|
for(;;)
|
||||||
|
|
||||||
// Don't continue if nothing has changed here
|
|
||||||
if(block->getNode(relpos) == n)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//m_map->setNode(m_area.MinEdge + p, n);
|
|
||||||
block->setNode(relpos, n);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Make sure block is in modified_blocks
|
|
||||||
*/
|
|
||||||
if(block_checked_in_modified == false)
|
|
||||||
{
|
{
|
||||||
modified_blocks[blockpos] = block;
|
// Clear check flags
|
||||||
block_checked_in_modified = true;
|
clearFlag(VOXELFLAG_CHECKED);
|
||||||
}
|
|
||||||
}
|
if(active_nodes.size() == 0)
|
||||||
catch(InvalidPositionException &e)
|
break;
|
||||||
|
|
||||||
|
dstream<<"Selecting a new active_node"<<std::endl;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Take first one
|
||||||
|
core::map<v3s16, u8>::Node
|
||||||
|
*n = active_nodes.getIterator().getNode();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// Take random one
|
||||||
|
s32 k = (s32)rand() % (s32)active_nodes.size();
|
||||||
|
//s32 k = 0;
|
||||||
|
core::map<v3s16, u8>::Iterator
|
||||||
|
i = active_nodes.getIterator().getNode();
|
||||||
|
for(s32 j=0; j<k; j++)
|
||||||
{
|
{
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
core::map<v3s16, u8>::Node *n = i.getNode();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
v3s16 p = n->getKey();
|
||||||
|
active_nodes.remove(p);
|
||||||
|
flowWater(p, active_nodes, recursion_depth,
|
||||||
|
debugprint, &counter, counterlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(ProcessingLimitException &e)
|
||||||
|
{
|
||||||
|
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
v3s16 e = m_area.getExtent();
|
||||||
|
s32 v = m_area.getVolume();
|
||||||
|
dstream<<"flowWater (active): moved "<<counter<<" nodes, "
|
||||||
|
<<"area ended up as "
|
||||||
|
<<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
dstream<<"addarea_time: "<<addarea_time
|
||||||
|
<<", emerge_time: "<<emerge_time
|
||||||
|
<<", emerge_load_time: "<<emerge_load_time
|
||||||
|
<<", clearflag_time: "<<clearflag_time
|
||||||
|
<<", flowwater_pre_time: "<<flowwater_pre_time
|
||||||
|
<<", updateareawaterpressure_time: "<<updateareawaterpressure_time
|
||||||
|
<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//END
|
//END
|
||||||
|
265
src/voxel.h
265
src/voxel.h
@ -21,8 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#define VOXEL_HEADER
|
#define VOXEL_HEADER
|
||||||
|
|
||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
#include "mapblock.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "mapnode.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A fast voxel manipulator class
|
A fast voxel manipulator class
|
||||||
@ -30,6 +31,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
Not thread-safe.
|
Not thread-safe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Debug stuff
|
||||||
|
*/
|
||||||
|
extern u32 emerge_time;
|
||||||
|
extern u32 emerge_load_time;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This class resembles aabbox3d<s16> a lot, but has inclusive
|
This class resembles aabbox3d<s16> a lot, but has inclusive
|
||||||
edges for saner handling of integer sizes
|
edges for saner handling of integer sizes
|
||||||
@ -53,8 +60,18 @@ public:
|
|||||||
MaxEdge(p)
|
MaxEdge(p)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Modifying methods
|
||||||
|
*/
|
||||||
|
|
||||||
void addArea(VoxelArea &a)
|
void addArea(VoxelArea &a)
|
||||||
{
|
{
|
||||||
|
if(getExtent() == v3s16(0,0,0))
|
||||||
|
{
|
||||||
|
*this = a;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
|
if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
|
||||||
if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
|
if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
|
||||||
if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
|
if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
|
||||||
@ -64,6 +81,12 @@ public:
|
|||||||
}
|
}
|
||||||
void addPoint(v3s16 p)
|
void addPoint(v3s16 p)
|
||||||
{
|
{
|
||||||
|
if(getExtent() == v3s16(0,0,0))
|
||||||
|
{
|
||||||
|
MinEdge = p;
|
||||||
|
MaxEdge = p;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(p.X < MinEdge.X) MinEdge.X = p.X;
|
if(p.X < MinEdge.X) MinEdge.X = p.X;
|
||||||
if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
|
if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
|
||||||
if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
|
if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
|
||||||
@ -71,6 +94,30 @@ public:
|
|||||||
if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
|
if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
|
||||||
if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
|
if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pad with d nodes
|
||||||
|
void pad(v3s16 d)
|
||||||
|
{
|
||||||
|
MinEdge -= d;
|
||||||
|
MaxEdge += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void operator+=(v3s16 off)
|
||||||
|
{
|
||||||
|
MinEdge += off;
|
||||||
|
MaxEdge += off;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator-=(v3s16 off)
|
||||||
|
{
|
||||||
|
MinEdge -= off;
|
||||||
|
MaxEdge -= off;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
const methods
|
||||||
|
*/
|
||||||
|
|
||||||
v3s16 getExtent() const
|
v3s16 getExtent() const
|
||||||
{
|
{
|
||||||
return MaxEdge - MinEdge + v3s16(1,1,1);
|
return MaxEdge - MinEdge + v3s16(1,1,1);
|
||||||
@ -80,8 +127,13 @@ public:
|
|||||||
v3s16 e = getExtent();
|
v3s16 e = getExtent();
|
||||||
return (s32)e.X * (s32)e.Y * (s32)e.Z;
|
return (s32)e.X * (s32)e.Y * (s32)e.Z;
|
||||||
}
|
}
|
||||||
bool contains(VoxelArea &a) const
|
bool contains(const VoxelArea &a) const
|
||||||
{
|
{
|
||||||
|
// No area contains an empty area
|
||||||
|
// NOTE: Algorithms depend on this, so do not change.
|
||||||
|
if(a.getExtent() == v3s16(0,0,0))
|
||||||
|
return false;
|
||||||
|
|
||||||
return(
|
return(
|
||||||
a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
|
a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
|
||||||
a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
|
a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
|
||||||
@ -102,6 +154,95 @@ public:
|
|||||||
&& MaxEdge == other.MaxEdge);
|
&& MaxEdge == other.MaxEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VoxelArea operator+(v3s16 off) const
|
||||||
|
{
|
||||||
|
return VoxelArea(MinEdge+off, MaxEdge+off);
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelArea operator-(v3s16 off) const
|
||||||
|
{
|
||||||
|
return VoxelArea(MinEdge-off, MaxEdge-off);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns 0-6 non-overlapping areas that can be added to
|
||||||
|
a to make up this area.
|
||||||
|
|
||||||
|
a: area inside *this
|
||||||
|
*/
|
||||||
|
void diff(const VoxelArea &a, core::list<VoxelArea> &result)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This can result in a maximum of 6 areas
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If a is an empty area, return the current area as a whole
|
||||||
|
if(a.getExtent() == v3s16(0,0,0))
|
||||||
|
{
|
||||||
|
VoxelArea b = *this;
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(contains(a));
|
||||||
|
|
||||||
|
// Take back area, XY inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
|
||||||
|
v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take front area, XY inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
|
||||||
|
v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take top area, X inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
|
||||||
|
v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take bottom area, X inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
|
||||||
|
v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take left area, non-inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
|
||||||
|
v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take right area, non-inclusive
|
||||||
|
{
|
||||||
|
v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
|
||||||
|
v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
|
||||||
|
VoxelArea b(min, max);
|
||||||
|
if(b.getVolume() != 0)
|
||||||
|
result.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Translates position from virtual coordinates to array index
|
Translates position from virtual coordinates to array index
|
||||||
*/
|
*/
|
||||||
@ -120,13 +261,15 @@ public:
|
|||||||
|
|
||||||
void print(std::ostream &o) const
|
void print(std::ostream &o) const
|
||||||
{
|
{
|
||||||
|
v3s16 e = getExtent();
|
||||||
o<<"("<<MinEdge.X
|
o<<"("<<MinEdge.X
|
||||||
<<","<<MinEdge.Y
|
<<","<<MinEdge.Y
|
||||||
<<","<<MinEdge.Z
|
<<","<<MinEdge.Z
|
||||||
<<")("<<MaxEdge.X
|
<<")("<<MaxEdge.X
|
||||||
<<","<<MaxEdge.Y
|
<<","<<MaxEdge.Y
|
||||||
<<","<<MaxEdge.Z
|
<<","<<MaxEdge.Z
|
||||||
<<")";
|
<<")"
|
||||||
|
<<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edges are inclusive
|
// Edges are inclusive
|
||||||
@ -139,18 +282,35 @@ public:
|
|||||||
// Checked as being inexistent in source
|
// Checked as being inexistent in source
|
||||||
#define VOXELFLAG_INEXISTENT (1<<1)
|
#define VOXELFLAG_INEXISTENT (1<<1)
|
||||||
// Algorithm-dependent
|
// Algorithm-dependent
|
||||||
|
// flowWater: "visited"
|
||||||
#define VOXELFLAG_CHECKED (1<<2)
|
#define VOXELFLAG_CHECKED (1<<2)
|
||||||
|
// Algorithm-dependent
|
||||||
|
// getWaterPressure: "visited"
|
||||||
|
#define VOXELFLAG_CHECKED2 (1<<3)
|
||||||
|
// Algorithm-dependent
|
||||||
|
// spreadWaterPressure: "visited"
|
||||||
|
#define VOXELFLAG_CHECKED3 (1<<4)
|
||||||
|
// Algorithm-dependent
|
||||||
|
// water: "pressure check route node"
|
||||||
|
#define VOXELFLAG_CHECKED4 (1<<5)
|
||||||
|
|
||||||
class VoxelManipulator : public NodeContainer
|
enum VoxelPrintMode
|
||||||
|
{
|
||||||
|
VOXELPRINT_NOTHING,
|
||||||
|
VOXELPRINT_MATERIAL,
|
||||||
|
VOXELPRINT_WATERPRESSURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoxelManipulator /*: public NodeContainer*/
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VoxelManipulator();
|
VoxelManipulator();
|
||||||
~VoxelManipulator();
|
virtual ~VoxelManipulator();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Virtuals from NodeContainer
|
Virtuals from NodeContainer
|
||||||
*/
|
*/
|
||||||
virtual u16 nodeContainerId() const
|
/*virtual u16 nodeContainerId() const
|
||||||
{
|
{
|
||||||
return NODECONTAINER_ID_VOXELMANIPULATOR;
|
return NODECONTAINER_ID_VOXELMANIPULATOR;
|
||||||
}
|
}
|
||||||
@ -158,7 +318,7 @@ public:
|
|||||||
{
|
{
|
||||||
emerge(p);
|
emerge(p);
|
||||||
return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
|
return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
|
||||||
}
|
}*/
|
||||||
// These are a bit slow and shouldn't be used internally
|
// These are a bit slow and shouldn't be used internally
|
||||||
MapNode getNode(v3s16 p)
|
MapNode getNode(v3s16 p)
|
||||||
{
|
{
|
||||||
@ -166,7 +326,7 @@ public:
|
|||||||
|
|
||||||
if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
|
if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
|
||||||
{
|
{
|
||||||
dstream<<"ERROR: VoxelManipulator::getNode(): "
|
dstream<<"EXCEPT: VoxelManipulator::getNode(): "
|
||||||
<<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
<<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||||
<<", index="<<m_area.index(p)
|
<<", index="<<m_area.index(p)
|
||||||
<<", flags="<<(int)m_flags[m_area.index(p)]
|
<<", flags="<<(int)m_flags[m_area.index(p)]
|
||||||
@ -214,19 +374,80 @@ public:
|
|||||||
Control
|
Control
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void clear();
|
virtual void clear();
|
||||||
|
|
||||||
void print(std::ostream &o);
|
void print(std::ostream &o, VoxelPrintMode mode=VOXELPRINT_MATERIAL);
|
||||||
|
|
||||||
void addArea(VoxelArea area);
|
void addArea(VoxelArea area);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy data and set flags to 0
|
||||||
|
dst_area.getExtent() <= src_area.getExtent()
|
||||||
|
*/
|
||||||
|
void copyFrom(MapNode *src, VoxelArea src_area,
|
||||||
|
v3s16 from_pos, v3s16 to_pos, v3s16 size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Algorithms
|
Algorithms
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void interpolate(VoxelArea area);
|
void interpolate(VoxelArea area);
|
||||||
|
|
||||||
void flowWater(v3s16 removed_pos);
|
void clearFlag(u8 flag);
|
||||||
|
|
||||||
|
// VOXELFLAG_CHECKED2s must usually be cleared before calling
|
||||||
|
// -1: dead end, 0-255: pressure
|
||||||
|
// highest_y: Highest found water y is stored here.
|
||||||
|
// Must be initialized to -32768
|
||||||
|
int getWaterPressure(v3s16 p, s16 &highest_y, int recur_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
VOXELFLAG_CHECKED3s must usually be cleared before calling.
|
||||||
|
|
||||||
|
active_nodes: surface-touching air nodes with flow-causing
|
||||||
|
pressure. set-like dummy map container.
|
||||||
|
|
||||||
|
Spreads pressure pr at node p to request_area or as far as
|
||||||
|
there is invalid pressure.
|
||||||
|
*/
|
||||||
|
void spreadWaterPressure(v3s16 p, int pr,
|
||||||
|
VoxelArea request_area,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recur_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
VOXELFLAG_CHECKED3s must usually be cleared before calling.
|
||||||
|
*/
|
||||||
|
void updateAreaWaterPressure(VoxelArea a,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
bool checked3_is_clear=false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns true if moved something
|
||||||
|
*/
|
||||||
|
bool flowWater(v3s16 removed_pos,
|
||||||
|
core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recursion_depth=0,
|
||||||
|
bool debugprint=false, int *counter=NULL,
|
||||||
|
int counterlimit=-1
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
To flow some water, call this with the target node in
|
||||||
|
active_nodes
|
||||||
|
TODO: Make the active_nodes map to contain some vectors
|
||||||
|
that are properly sorted according to water flow order.
|
||||||
|
The current order makes water flow strangely if the
|
||||||
|
first one is always taken.
|
||||||
|
No, active_nodes should preserve the order stuff is
|
||||||
|
added to it, in addition to adhering the water flow
|
||||||
|
order.
|
||||||
|
*/
|
||||||
|
void flowWater(core::map<v3s16, u8> &active_nodes,
|
||||||
|
int recursion_depth=0,
|
||||||
|
bool debugprint=false,
|
||||||
|
int counterlimit=-1
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Virtual functions
|
Virtual functions
|
||||||
@ -265,32 +486,24 @@ public:
|
|||||||
MaxEdge is 1 higher than maximum allowed position
|
MaxEdge is 1 higher than maximum allowed position
|
||||||
*/
|
*/
|
||||||
VoxelArea m_area;
|
VoxelArea m_area;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NULL if data size is 0 (extent (0,0,0))
|
NULL if data size is 0 (extent (0,0,0))
|
||||||
Data is stored as [z*h*w + y*h + x]
|
Data is stored as [z*h*w + y*h + x]
|
||||||
*/
|
*/
|
||||||
MapNode *m_data;
|
MapNode *m_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Flags of all nodes
|
Flags of all nodes
|
||||||
*/
|
*/
|
||||||
u8 *m_flags;
|
u8 *m_flags;
|
||||||
|
|
||||||
|
//TODO: Use these or remove them
|
||||||
|
//TODO: Would these make any speed improvement?
|
||||||
|
//bool m_pressure_route_valid;
|
||||||
|
//v3s16 m_pressure_route_surface;
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Map;
|
|
||||||
|
|
||||||
class MapVoxelManipulator : public VoxelManipulator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MapVoxelManipulator(Map *map);
|
|
||||||
|
|
||||||
virtual void emerge(VoxelArea a);
|
|
||||||
|
|
||||||
void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Map *m_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user