forked from Mirrorlandia_minetest/minetest
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
|
||||
|
||||
#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 = -Wall -g -O0
|
||||
#CXXFLAGS = -Wall -g -O0
|
||||
|
||||
#CXXFLAGS = -O3 -ffast-math -Wall
|
||||
#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:
|
||||
*/
|
||||
|
@ -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)
|
||||
- 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.
|
||||
|
||||
TODO: Transfer sign texts as metadata of block and not as data of
|
||||
object
|
||||
|
||||
Doing now:
|
||||
======================================================================
|
||||
|
||||
|
149
src/map.cpp
149
src/map.cpp
@ -47,10 +47,10 @@ MapBlockPointerCache::~MapBlockPointerCache()
|
||||
{
|
||||
m_map->m_blockcachelock.cacheRemoved();
|
||||
|
||||
dstream<<"MapBlockPointerCache:"
|
||||
/*dstream<<"MapBlockPointerCache:"
|
||||
<<" from_cache_count="<<m_from_cache_count
|
||||
<<" from_map_count="<<m_from_map_count
|
||||
<<std::endl;
|
||||
<<std::endl;*/
|
||||
}
|
||||
|
||||
MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
|
||||
@ -1050,6 +1050,8 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||
// Node will be replaced with this
|
||||
u8 replace_material = MATERIAL_AIR;
|
||||
|
||||
// NOTE: Water is now managed elsewhere
|
||||
#if 0
|
||||
{
|
||||
/*
|
||||
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,
|
||||
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 "mapsector.h"
|
||||
#include "constants.h"
|
||||
#include "voxel.h"
|
||||
|
||||
class Map;
|
||||
|
||||
@ -49,6 +50,7 @@ class Map;
|
||||
NOTE: This doesn't really make anything more efficient
|
||||
NOTE: Use VoxelManipulator, if possible
|
||||
TODO: Get rid of this?
|
||||
NOTE: CONFIRMED: THIS CACHE DOESN'T MAKE ANYTHING ANY FASTER
|
||||
*/
|
||||
class MapBlockPointerCache : public NodeContainer
|
||||
{
|
||||
@ -121,7 +123,7 @@ public:
|
||||
|
||||
void cacheCreated()
|
||||
{
|
||||
dstream<<"cacheCreated() begin"<<std::endl;
|
||||
//dstream<<"cacheCreated() begin"<<std::endl;
|
||||
JMutexAutoLock waitcachelock(m_waitcache_mutex);
|
||||
JMutexAutoLock countlock(m_count_mutex);
|
||||
|
||||
@ -131,12 +133,12 @@ public:
|
||||
|
||||
m_count++;
|
||||
|
||||
dstream<<"cacheCreated() end"<<std::endl;
|
||||
//dstream<<"cacheCreated() end"<<std::endl;
|
||||
}
|
||||
|
||||
void cacheRemoved()
|
||||
{
|
||||
dstream<<"cacheRemoved() begin"<<std::endl;
|
||||
//dstream<<"cacheRemoved() begin"<<std::endl;
|
||||
JMutexAutoLock countlock(m_count_mutex);
|
||||
|
||||
assert(m_count > 0);
|
||||
@ -147,7 +149,7 @@ public:
|
||||
if(m_count == 0)
|
||||
m_cache_mutex.Unlock();
|
||||
|
||||
dstream<<"cacheRemoved() end"<<std::endl;
|
||||
//dstream<<"cacheRemoved() end"<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -589,5 +591,29 @@ private:
|
||||
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
|
||||
|
||||
|
@ -696,6 +696,15 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
|
||||
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
|
||||
*/
|
||||
@ -755,6 +764,17 @@ void MapBlock::serialize(std::ostream &os, u8 version)
|
||||
paramdata[i] = data[i].param;
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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 "constants.h"
|
||||
#include "mapblockobject.h"
|
||||
#include "voxel.h"
|
||||
|
||||
#define MAP_BLOCKSIZE 16
|
||||
|
||||
@ -69,31 +70,6 @@ public:
|
||||
|
||||
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:
|
||||
|
||||
/*
|
||||
@ -333,10 +309,12 @@ public:
|
||||
|
||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources);
|
||||
|
||||
// Doesn't write version by itself
|
||||
void serialize(std::ostream &os, u8 version);
|
||||
// Copies data to VoxelManipulator to getPosRelative()
|
||||
void copyTo(VoxelManipulator &dst);
|
||||
|
||||
void deSerialize(std::istream &is, u8 version);
|
||||
/*
|
||||
Object stuff
|
||||
*/
|
||||
|
||||
void serializeObjects(std::ostream &os, u8 version)
|
||||
{
|
||||
@ -403,6 +381,15 @@ public:
|
||||
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:
|
||||
|
||||
/*
|
||||
@ -420,6 +407,31 @@ private:
|
||||
{
|
||||
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)
|
||||
|
@ -205,10 +205,11 @@ struct MapNode
|
||||
*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;
|
||||
param = a_param;
|
||||
pressure = a_pressure;
|
||||
}
|
||||
|
||||
bool operator==(const MapNode &other)
|
||||
@ -261,6 +262,11 @@ struct MapNode
|
||||
param = a_light;
|
||||
}
|
||||
|
||||
/*
|
||||
These serialization functions are used when informing client
|
||||
of a single node add
|
||||
*/
|
||||
|
||||
static u32 serializedLength(u8 version)
|
||||
{
|
||||
if(!ser_ver_supported(version))
|
||||
@ -268,8 +274,10 @@ struct MapNode
|
||||
|
||||
if(version == 0)
|
||||
return 1;
|
||||
else
|
||||
else if(version <= 9)
|
||||
return 2;
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
void serialize(u8 *dest, u8 version)
|
||||
{
|
||||
@ -280,10 +288,16 @@ struct MapNode
|
||||
{
|
||||
dest[0] = d;
|
||||
}
|
||||
else if(version <= 9)
|
||||
{
|
||||
dest[0] = d;
|
||||
dest[1] = param;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = d;
|
||||
dest[1] = param;
|
||||
dest[2] = pressure;
|
||||
}
|
||||
}
|
||||
void deSerialize(u8 *source, u8 version)
|
||||
@ -304,10 +318,16 @@ struct MapNode
|
||||
else
|
||||
param = source[1];
|
||||
}
|
||||
else if(version <= 9)
|
||||
{
|
||||
d = source[0];
|
||||
param = source[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
d = source[0];
|
||||
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
|
||||
8: (dev) server-initiated block transfers and all kinds of stuff
|
||||
9: (dev) block objects
|
||||
10: (dev) water pressure
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 9
|
||||
#define SER_FMT_VER_HIGHEST 10
|
||||
// Lowest supported serialization version
|
||||
#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 "main.h"
|
||||
#include "constants.h"
|
||||
#include "voxel.h"
|
||||
|
||||
void * ServerThread::Thread()
|
||||
{
|
||||
@ -990,6 +991,76 @@ void Server::AsyncRunStep()
|
||||
/*
|
||||
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
|
||||
{
|
||||
@ -1458,6 +1529,31 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
(this takes some time so it is done after the quick stuff)
|
||||
*/
|
||||
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
|
||||
/*
|
||||
|
@ -469,6 +469,9 @@ private:
|
||||
|
||||
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 RemoteClient;
|
||||
};
|
||||
|
75
src/test.cpp
75
src/test.cpp
@ -148,10 +148,45 @@ struct TestVoxelManipulator
|
||||
{
|
||||
void Run()
|
||||
{
|
||||
/*
|
||||
VoxelArea
|
||||
*/
|
||||
|
||||
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(-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;
|
||||
|
||||
v.print(dstream);
|
||||
@ -186,18 +221,19 @@ struct TestVoxelManipulator
|
||||
v.clear();
|
||||
|
||||
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;
|
||||
for(s16 z=0; z<size.Z; z++)
|
||||
@ -205,7 +241,7 @@ struct TestVoxelManipulator
|
||||
for(s16 x=0; x<size.X; x++)
|
||||
{
|
||||
MapNode n;
|
||||
n.pressure = size.Y - y;
|
||||
//n.pressure = size.Y - y;
|
||||
if(*p == '#')
|
||||
n.d = MATERIAL_STONE;
|
||||
else if(*p == '.')
|
||||
@ -218,7 +254,24 @@ struct TestVoxelManipulator
|
||||
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);
|
||||
}
|
||||
|
@ -394,12 +394,18 @@ private:
|
||||
class TimeTaker
|
||||
{
|
||||
public:
|
||||
TimeTaker(const char *name, IrrlichtDevice *dev)
|
||||
TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
|
||||
{
|
||||
m_name = name;
|
||||
m_dev = dev;
|
||||
m_time1 = m_dev->getTimer()->getRealTime();
|
||||
m_result = result;
|
||||
m_running = true;
|
||||
if(dev == NULL)
|
||||
{
|
||||
m_time1 = 0;
|
||||
return;
|
||||
}
|
||||
m_time1 = m_dev->getTimer()->getRealTime();
|
||||
}
|
||||
~TimeTaker()
|
||||
{
|
||||
@ -409,10 +415,24 @@ public:
|
||||
{
|
||||
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 dtime = time2 - m_time1;
|
||||
if(quiet == false)
|
||||
std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
|
||||
if(m_result != NULL)
|
||||
{
|
||||
(*m_result) += dtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(quiet == false)
|
||||
std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
|
||||
}
|
||||
m_running = false;
|
||||
return dtime;
|
||||
}
|
||||
@ -423,6 +443,7 @@ private:
|
||||
IrrlichtDevice *m_dev;
|
||||
u32 m_time1;
|
||||
bool m_running;
|
||||
u32 *m_result;
|
||||
};
|
||||
|
||||
// Calculates the borders of a "d-radius" cube
|
||||
|
818
src/voxel.cpp
818
src/voxel.cpp
@ -20,6 +20,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "voxel.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():
|
||||
m_data(NULL),
|
||||
m_flags(NULL)
|
||||
@ -47,7 +64,7 @@ void VoxelManipulator::clear()
|
||||
m_flags = NULL;
|
||||
}
|
||||
|
||||
void VoxelManipulator::print(std::ostream &o)
|
||||
void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
|
||||
{
|
||||
v3s16 em = m_area.getExtent();
|
||||
v3s16 of = m_area.MinEdge;
|
||||
@ -78,8 +95,29 @@ void VoxelManipulator::print(std::ostream &o)
|
||||
{
|
||||
c = 'X';
|
||||
u8 m = m_data[m_area.index(x,y,z)].d;
|
||||
if(m <= 9)
|
||||
c = m + '0';
|
||||
u8 pr = m_data[m_area.index(x,y,z)].pressure;
|
||||
if(mode == VOXELPRINT_MATERIAL)
|
||||
{
|
||||
if(m <= 9)
|
||||
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;
|
||||
}
|
||||
@ -99,6 +137,8 @@ void VoxelManipulator::addArea(VoxelArea area)
|
||||
if(m_area.contains(area))
|
||||
return;
|
||||
|
||||
TimeTaker timer("addArea", g_device, &addarea_time);
|
||||
|
||||
// Calculate new area
|
||||
VoxelArea new_area;
|
||||
// New area is the requested area if m_area has zero volume
|
||||
@ -163,6 +203,21 @@ void VoxelManipulator::addArea(VoxelArea area)
|
||||
delete[] old_data;
|
||||
if(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)
|
||||
@ -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(0,1,0), // top
|
||||
@ -241,16 +607,43 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
||||
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;
|
||||
|
||||
{
|
||||
TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
|
||||
|
||||
// Load neighboring nodes
|
||||
// TODO: A bigger area would be better
|
||||
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 + 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)];
|
||||
// Inexistent or checked nodes can't move
|
||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
||||
@ -280,30 +673,66 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
||||
|
||||
// If there is nothing to move, return
|
||||
if(i==6)
|
||||
return;
|
||||
|
||||
return false;
|
||||
|
||||
// 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)];
|
||||
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_data[m_area.index(removed_pos)] = n;
|
||||
m_data[m_area.index(removed_pos)].d = m;
|
||||
m_flags[m_area.index(removed_pos)] = f;
|
||||
|
||||
// Mark p checked
|
||||
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED;
|
||||
// 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
|
||||
//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
|
||||
flowWater(p);
|
||||
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(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)];
|
||||
// Water can't move to inexistent nodes
|
||||
if(f & VOXELFLAG_INEXISTENT)
|
||||
@ -312,102 +741,291 @@ void VoxelManipulator::flowWater(v3s16 removed_pos)
|
||||
// Water can only move to air
|
||||
if(n.d != MATERIAL_AIR)
|
||||
continue;
|
||||
flowWater(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MapVoxelManipulator
|
||||
*/
|
||||
|
||||
MapVoxelManipulator::MapVoxelManipulator(Map *map)
|
||||
{
|
||||
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);
|
||||
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[i] = n;
|
||||
m_flags[i] = 0;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
|
||||
// Flow water to node
|
||||
bool moved =
|
||||
flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);
|
||||
|
||||
if(moved)
|
||||
{
|
||||
m_flags[i] = VOXELFLAG_INEXISTENT;
|
||||
// Search again from all neighbors
|
||||
goto find_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapVoxelManipulator::blitBack
|
||||
(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||
{
|
||||
/*
|
||||
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++)
|
||||
if(counter != NULL)
|
||||
{
|
||||
v3s16 p(x,y,z);
|
||||
(*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,
|
||||
core::map<v3s16, u8> &active_nodes,
|
||||
int recursion_depth, bool debugprint,
|
||||
int *counter, int counterlimit)
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
{
|
||||
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)];
|
||||
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)];
|
||||
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
|
||||
try
|
||||
// Only liquid nodes can move
|
||||
if(material_liquid(n.d) == false)
|
||||
continue;
|
||||
// If block is at top, select it always
|
||||
if(i == 0)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
// 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;
|
||||
|
||||
// Flow water to node
|
||||
bool moved =
|
||||
flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
// Flow water to active nodes
|
||||
for(;;)
|
||||
{
|
||||
// Clear check flags
|
||||
clearFlag(VOXELFLAG_CHECKED);
|
||||
|
||||
if(active_nodes.size() == 0)
|
||||
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
|
||||
|
267
src/voxel.h
267
src/voxel.h
@ -21,8 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define VOXEL_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapblock.h"
|
||||
#include <iostream>
|
||||
#include "debug.h"
|
||||
#include "mapnode.h"
|
||||
|
||||
/*
|
||||
A fast voxel manipulator class
|
||||
@ -30,6 +31,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
Not thread-safe.
|
||||
*/
|
||||
|
||||
/*
|
||||
Debug stuff
|
||||
*/
|
||||
extern u32 emerge_time;
|
||||
extern u32 emerge_load_time;
|
||||
|
||||
/*
|
||||
This class resembles aabbox3d<s16> a lot, but has inclusive
|
||||
edges for saner handling of integer sizes
|
||||
@ -53,8 +60,18 @@ public:
|
||||
MaxEdge(p)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
Modifying methods
|
||||
*/
|
||||
|
||||
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.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
|
||||
if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
|
||||
@ -64,6 +81,12 @@ public:
|
||||
}
|
||||
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.Y < MinEdge.Y) MinEdge.Y = p.Y;
|
||||
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.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
|
||||
{
|
||||
return MaxEdge - MinEdge + v3s16(1,1,1);
|
||||
@ -80,8 +127,13 @@ public:
|
||||
v3s16 e = getExtent();
|
||||
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(
|
||||
a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
|
||||
a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
|
||||
@ -101,6 +153,95 @@ public:
|
||||
return (MinEdge == other.MinEdge
|
||||
&& 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
|
||||
@ -120,13 +261,15 @@ public:
|
||||
|
||||
void print(std::ostream &o) const
|
||||
{
|
||||
v3s16 e = getExtent();
|
||||
o<<"("<<MinEdge.X
|
||||
<<","<<MinEdge.Y
|
||||
<<","<<MinEdge.Z
|
||||
<<")("<<MaxEdge.X
|
||||
<<","<<MaxEdge.Y
|
||||
<<","<<MaxEdge.Z
|
||||
<<")";
|
||||
<<")"
|
||||
<<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
|
||||
}
|
||||
|
||||
// Edges are inclusive
|
||||
@ -139,18 +282,35 @@ public:
|
||||
// Checked as being inexistent in source
|
||||
#define VOXELFLAG_INEXISTENT (1<<1)
|
||||
// Algorithm-dependent
|
||||
// flowWater: "visited"
|
||||
#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:
|
||||
VoxelManipulator();
|
||||
~VoxelManipulator();
|
||||
virtual ~VoxelManipulator();
|
||||
|
||||
/*
|
||||
Virtuals from NodeContainer
|
||||
*/
|
||||
virtual u16 nodeContainerId() const
|
||||
/*virtual u16 nodeContainerId() const
|
||||
{
|
||||
return NODECONTAINER_ID_VOXELMANIPULATOR;
|
||||
}
|
||||
@ -158,7 +318,7 @@ public:
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -166,7 +326,7 @@ public:
|
||||
|
||||
if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
|
||||
{
|
||||
dstream<<"ERROR: VoxelManipulator::getNode(): "
|
||||
dstream<<"EXCEPT: VoxelManipulator::getNode(): "
|
||||
<<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<", index="<<m_area.index(p)
|
||||
<<", flags="<<(int)m_flags[m_area.index(p)]
|
||||
@ -214,19 +374,80 @@ public:
|
||||
Control
|
||||
*/
|
||||
|
||||
void clear();
|
||||
|
||||
void print(std::ostream &o);
|
||||
virtual void clear();
|
||||
|
||||
void print(std::ostream &o, VoxelPrintMode mode=VOXELPRINT_MATERIAL);
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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
|
||||
@ -265,32 +486,24 @@ public:
|
||||
MaxEdge is 1 higher than maximum allowed position
|
||||
*/
|
||||
VoxelArea m_area;
|
||||
|
||||
/*
|
||||
NULL if data size is 0 (extent (0,0,0))
|
||||
Data is stored as [z*h*w + y*h + x]
|
||||
*/
|
||||
MapNode *m_data;
|
||||
|
||||
/*
|
||||
Flags of all nodes
|
||||
*/
|
||||
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:
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user