Merge remote-tracking branch 'oblomov/liquid_fixes'
commit
f98eda4d52
|
@ -26,6 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
#define WATER_ALPHA 160
|
#define WATER_ALPHA 160
|
||||||
|
|
||||||
|
#define WATER_VISC 1
|
||||||
|
#define LAVA_VISC 7
|
||||||
|
|
||||||
// TODO: Get rid of these and set up some attributes like toughness,
|
// TODO: Get rid of these and set up some attributes like toughness,
|
||||||
// fluffyness, and a funciton to calculate time and durability loss
|
// fluffyness, and a funciton to calculate time and durability loss
|
||||||
// (and sound? and whatever else) from them
|
// (and sound? and whatever else) from them
|
||||||
|
@ -374,6 +377,7 @@ void content_mapnode_init()
|
||||||
f->liquid_type = LIQUID_FLOWING;
|
f->liquid_type = LIQUID_FLOWING;
|
||||||
f->liquid_alternative_flowing = CONTENT_WATER;
|
f->liquid_alternative_flowing = CONTENT_WATER;
|
||||||
f->liquid_alternative_source = CONTENT_WATERSOURCE;
|
f->liquid_alternative_source = CONTENT_WATERSOURCE;
|
||||||
|
f->liquid_viscosity = WATER_VISC;
|
||||||
f->vertex_alpha = WATER_ALPHA;
|
f->vertex_alpha = WATER_ALPHA;
|
||||||
if(f->special_material == NULL && g_texturesource)
|
if(f->special_material == NULL && g_texturesource)
|
||||||
{
|
{
|
||||||
|
@ -421,6 +425,7 @@ void content_mapnode_init()
|
||||||
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
|
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
|
||||||
f->liquid_alternative_flowing = CONTENT_WATER;
|
f->liquid_alternative_flowing = CONTENT_WATER;
|
||||||
f->liquid_alternative_source = CONTENT_WATERSOURCE;
|
f->liquid_alternative_source = CONTENT_WATERSOURCE;
|
||||||
|
f->liquid_viscosity = WATER_VISC;
|
||||||
f->vertex_alpha = WATER_ALPHA;
|
f->vertex_alpha = WATER_ALPHA;
|
||||||
if(f->special_material == NULL && g_texturesource)
|
if(f->special_material == NULL && g_texturesource)
|
||||||
{
|
{
|
||||||
|
@ -451,6 +456,7 @@ void content_mapnode_init()
|
||||||
f->liquid_type = LIQUID_FLOWING;
|
f->liquid_type = LIQUID_FLOWING;
|
||||||
f->liquid_alternative_flowing = CONTENT_LAVA;
|
f->liquid_alternative_flowing = CONTENT_LAVA;
|
||||||
f->liquid_alternative_source = CONTENT_LAVASOURCE;
|
f->liquid_alternative_source = CONTENT_LAVASOURCE;
|
||||||
|
f->liquid_viscosity = LAVA_VISC;
|
||||||
f->damage_per_second = 4*2;
|
f->damage_per_second = 4*2;
|
||||||
if(f->special_material == NULL && g_texturesource)
|
if(f->special_material == NULL && g_texturesource)
|
||||||
{
|
{
|
||||||
|
@ -499,6 +505,7 @@ void content_mapnode_init()
|
||||||
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
|
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
|
||||||
f->liquid_alternative_flowing = CONTENT_LAVA;
|
f->liquid_alternative_flowing = CONTENT_LAVA;
|
||||||
f->liquid_alternative_source = CONTENT_LAVASOURCE;
|
f->liquid_alternative_source = CONTENT_LAVASOURCE;
|
||||||
|
f->liquid_viscosity = LAVA_VISC;
|
||||||
f->damage_per_second = 4*2;
|
f->damage_per_second = 4*2;
|
||||||
if(f->special_material == NULL && g_texturesource)
|
if(f->special_material == NULL && g_texturesource)
|
||||||
{
|
{
|
||||||
|
|
111
src/map.cpp
111
src/map.cpp
|
@ -1562,6 +1562,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
/*if(initial_size != 0)
|
/*if(initial_size != 0)
|
||||||
dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
|
dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
|
||||||
|
|
||||||
|
// list of nodes that due to viscosity have not reached their max level height
|
||||||
|
UniqueQueue<v3s16> must_reflow;
|
||||||
|
|
||||||
while(m_transforming_liquid.size() != 0)
|
while(m_transforming_liquid.size() != 0)
|
||||||
{
|
{
|
||||||
// This should be done here so that it is done when continue is used
|
// This should be done here so that it is done when continue is used
|
||||||
|
@ -1575,7 +1578,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
v3s16 p0 = m_transforming_liquid.pop_front();
|
v3s16 p0 = m_transforming_liquid.pop_front();
|
||||||
|
|
||||||
MapNode n0 = getNodeNoEx(p0);
|
MapNode n0 = getNodeNoEx(p0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect information about current node
|
Collect information about current node
|
||||||
*/
|
*/
|
||||||
|
@ -1584,7 +1587,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
LiquidType liquid_type = content_features(n0.getContent()).liquid_type;
|
LiquidType liquid_type = content_features(n0.getContent()).liquid_type;
|
||||||
switch (liquid_type) {
|
switch (liquid_type) {
|
||||||
case LIQUID_SOURCE:
|
case LIQUID_SOURCE:
|
||||||
liquid_level = 8;
|
liquid_level = LIQUID_LEVEL_SOURCE;
|
||||||
liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing;
|
liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing;
|
||||||
break;
|
break;
|
||||||
case LIQUID_FLOWING:
|
case LIQUID_FLOWING:
|
||||||
|
@ -1599,18 +1602,11 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
liquid_kind = CONTENT_AIR;
|
liquid_kind = CONTENT_AIR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect information about the environment
|
Collect information about the environment
|
||||||
*/
|
*/
|
||||||
v3s16 dirs[6] = {
|
const v3s16 *dirs = g_6dirs;
|
||||||
v3s16( 0, 1, 0), // top
|
|
||||||
v3s16( 0,-1, 0), // bottom
|
|
||||||
v3s16( 1, 0, 0), // right
|
|
||||||
v3s16(-1, 0, 0), // left
|
|
||||||
v3s16( 0, 0, 1), // back
|
|
||||||
v3s16( 0, 0,-1), // front
|
|
||||||
};
|
|
||||||
NodeNeighbor sources[6]; // surrounding sources
|
NodeNeighbor sources[6]; // surrounding sources
|
||||||
int num_sources = 0;
|
int num_sources = 0;
|
||||||
NodeNeighbor flows[6]; // surrounding flowing liquid nodes
|
NodeNeighbor flows[6]; // surrounding flowing liquid nodes
|
||||||
|
@ -1623,10 +1619,10 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
for (u16 i = 0; i < 6; i++) {
|
for (u16 i = 0; i < 6; i++) {
|
||||||
NeighborType nt = NEIGHBOR_SAME_LEVEL;
|
NeighborType nt = NEIGHBOR_SAME_LEVEL;
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 1:
|
||||||
nt = NEIGHBOR_UPPER;
|
nt = NEIGHBOR_UPPER;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 4:
|
||||||
nt = NEIGHBOR_LOWER;
|
nt = NEIGHBOR_LOWER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1636,9 +1632,15 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
case LIQUID_NONE:
|
case LIQUID_NONE:
|
||||||
if (nb.n.getContent() == CONTENT_AIR) {
|
if (nb.n.getContent() == CONTENT_AIR) {
|
||||||
airs[num_airs++] = nb;
|
airs[num_airs++] = nb;
|
||||||
|
// if the current node is a water source the neighbor
|
||||||
|
// should be enqueded for transformation regardless of whether the
|
||||||
|
// current node changes or not.
|
||||||
|
if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
|
||||||
|
m_transforming_liquid.push_back(npos);
|
||||||
// if the current node happens to be a flowing node, it will start to flow down here.
|
// if the current node happens to be a flowing node, it will start to flow down here.
|
||||||
if (nb.t == NEIGHBOR_LOWER)
|
if (nb.t == NEIGHBOR_LOWER) {
|
||||||
flowing_down = true;
|
flowing_down = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
neutrals[num_neutrals++] = nb;
|
neutrals[num_neutrals++] = nb;
|
||||||
}
|
}
|
||||||
|
@ -1667,12 +1669,13 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
decide on the type (and possibly level) of the current node
|
decide on the type (and possibly level) of the current node
|
||||||
*/
|
*/
|
||||||
content_t new_node_content;
|
content_t new_node_content;
|
||||||
s8 new_node_level = -1;
|
s8 new_node_level = -1;
|
||||||
|
s8 max_node_level = -1;
|
||||||
if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
|
if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
|
||||||
// liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
|
// liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
|
||||||
// or the flowing alternative of the first of the surrounding sources (if it's air), so
|
// or the flowing alternative of the first of the surrounding sources (if it's air), so
|
||||||
|
@ -1681,49 +1684,53 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
} else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
|
} else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
|
||||||
// liquid_kind is set properly, see above
|
// liquid_kind is set properly, see above
|
||||||
new_node_content = liquid_kind;
|
new_node_content = liquid_kind;
|
||||||
new_node_level = 7;
|
max_node_level = new_node_level = LIQUID_LEVEL_MAX;
|
||||||
} else {
|
} else {
|
||||||
// no surrounding sources, so get the maximum level that can flow into this node
|
// no surrounding sources, so get the maximum level that can flow into this node
|
||||||
for (u16 i = 0; i < num_flows; i++) {
|
for (u16 i = 0; i < num_flows; i++) {
|
||||||
u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
|
u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
|
||||||
switch (flows[i].t) {
|
switch (flows[i].t) {
|
||||||
case NEIGHBOR_UPPER:
|
case NEIGHBOR_UPPER:
|
||||||
if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) {
|
if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
|
||||||
new_node_level = 7;
|
max_node_level = LIQUID_LEVEL_MAX;
|
||||||
if (nb_liquid_level + WATER_DROP_BOOST < 7)
|
if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
|
||||||
new_node_level = nb_liquid_level + WATER_DROP_BOOST;
|
max_node_level = nb_liquid_level + WATER_DROP_BOOST;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NEIGHBOR_LOWER:
|
case NEIGHBOR_LOWER:
|
||||||
break;
|
break;
|
||||||
case NEIGHBOR_SAME_LEVEL:
|
case NEIGHBOR_SAME_LEVEL:
|
||||||
if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
|
if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
|
||||||
nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) {
|
nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
|
||||||
new_node_level = nb_liquid_level - 1;
|
max_node_level = nb_liquid_level - 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// don't flow as far in open terrain - if there isn't at least one adjacent solid block,
|
|
||||||
// substract another unit from the resulting water level.
|
u8 viscosity = content_features(liquid_kind).liquid_viscosity;
|
||||||
if (!flowing_down && new_node_level >= 1) {
|
if (viscosity > 1 && max_node_level != liquid_level) {
|
||||||
bool at_wall = false;
|
// amount to gain, limited by viscosity
|
||||||
for (u16 i = 0; i < num_neutrals; i++) {
|
// must be at least 1 in absolute value
|
||||||
if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) {
|
s8 level_inc = max_node_level - liquid_level;
|
||||||
at_wall = true;
|
if (level_inc < -viscosity || level_inc > viscosity)
|
||||||
break;
|
new_node_level = liquid_level + level_inc/viscosity;
|
||||||
}
|
else if (level_inc < 0)
|
||||||
}
|
new_node_level = liquid_level - 1;
|
||||||
if (!at_wall)
|
else if (level_inc > 0)
|
||||||
new_node_level -= 1;
|
new_node_level = liquid_level + 1;
|
||||||
}
|
if (new_node_level != max_node_level)
|
||||||
|
must_reflow.push_back(p0);
|
||||||
|
} else
|
||||||
|
new_node_level = max_node_level;
|
||||||
|
|
||||||
if (new_node_level >= 0)
|
if (new_node_level >= 0)
|
||||||
new_node_content = liquid_kind;
|
new_node_content = liquid_kind;
|
||||||
else
|
else
|
||||||
new_node_content = CONTENT_AIR;
|
new_node_content = CONTENT_AIR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check if anything has changed. if not, just continue with the next node.
|
check if anything has changed. if not, just continue with the next node.
|
||||||
*/
|
*/
|
||||||
|
@ -1732,31 +1739,32 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
|
((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
|
||||||
== flowing_down)))
|
== flowing_down)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
update the current node
|
update the current node
|
||||||
*/
|
*/
|
||||||
bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
|
bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
|
||||||
n0.setContent(new_node_content);
|
if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) {
|
||||||
if (content_features(n0.getContent()).liquid_type == LIQUID_FLOWING) {
|
|
||||||
// set level to last 3 bits, flowing down bit to 4th bit
|
// set level to last 3 bits, flowing down bit to 4th bit
|
||||||
n0.param2 |= (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
|
n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
|
||||||
} else {
|
} else {
|
||||||
// set the liquid level and flow bit to 0
|
// set the liquid level and flow bit to 0
|
||||||
n0.param2 &= ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
|
n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
n0.setContent(new_node_content);
|
||||||
setNode(p0, n0);
|
setNode(p0, n0);
|
||||||
v3s16 blockpos = getNodeBlockPos(p0);
|
v3s16 blockpos = getNodeBlockPos(p0);
|
||||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||||
if(block != NULL)
|
if(block != NULL)
|
||||||
modified_blocks.insert(blockpos, block);
|
modified_blocks.insert(blockpos, block);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enqueue neighbors for update if neccessary
|
enqueue neighbors for update if neccessary
|
||||||
*/
|
*/
|
||||||
switch (content_features(n0.getContent()).liquid_type) {
|
switch (content_features(n0.getContent()).liquid_type) {
|
||||||
case LIQUID_SOURCE:
|
case LIQUID_SOURCE:
|
||||||
|
case LIQUID_FLOWING:
|
||||||
// make sure source flows into all neighboring nodes
|
// make sure source flows into all neighboring nodes
|
||||||
for (u16 i = 0; i < num_flows; i++)
|
for (u16 i = 0; i < num_flows; i++)
|
||||||
if (flows[i].t != NEIGHBOR_UPPER)
|
if (flows[i].t != NEIGHBOR_UPPER)
|
||||||
|
@ -1770,22 +1778,11 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
for (u16 i = 0; i < num_flows; i++)
|
for (u16 i = 0; i < num_flows; i++)
|
||||||
m_transforming_liquid.push_back(flows[i].p);
|
m_transforming_liquid.push_back(flows[i].p);
|
||||||
break;
|
break;
|
||||||
case LIQUID_FLOWING:
|
|
||||||
for (u16 i = 0; i < num_flows; i++) {
|
|
||||||
u8 flow_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
|
|
||||||
// liquid_level is still the ORIGINAL level of this node.
|
|
||||||
if (flows[i].t != NEIGHBOR_UPPER && ((flow_level < liquid_level || flow_level < new_node_level) ||
|
|
||||||
flow_down_enabled))
|
|
||||||
m_transforming_liquid.push_back(flows[i].p);
|
|
||||||
}
|
|
||||||
for (u16 i = 0; i < num_airs; i++) {
|
|
||||||
if (airs[i].t != NEIGHBOR_UPPER && (airs[i].t == NEIGHBOR_LOWER || new_node_level > 0))
|
|
||||||
m_transforming_liquid.push_back(airs[i].p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
|
//dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
|
||||||
|
while (must_reflow.size() > 0)
|
||||||
|
m_transforming_liquid.push_back(must_reflow.pop_front());
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeMetadata* Map::getNodeMetadata(v3s16 p)
|
NodeMetadata* Map::getNodeMetadata(v3s16 p)
|
||||||
|
|
|
@ -153,6 +153,10 @@ struct ContentFeatures
|
||||||
content_t liquid_alternative_flowing;
|
content_t liquid_alternative_flowing;
|
||||||
// If the content is liquid, this is the source version of the liquid.
|
// If the content is liquid, this is the source version of the liquid.
|
||||||
content_t liquid_alternative_source;
|
content_t liquid_alternative_source;
|
||||||
|
// Viscosity for fluid flow, ranging from 1 to 7, with
|
||||||
|
// 1 giving almost instantaneous propagation and 7 being
|
||||||
|
// the slowest possible
|
||||||
|
u8 liquid_viscosity;
|
||||||
// Used currently for flowing liquids
|
// Used currently for flowing liquids
|
||||||
u8 vertex_alpha;
|
u8 vertex_alpha;
|
||||||
// Special irrlicht material, used sometimes
|
// Special irrlicht material, used sometimes
|
||||||
|
@ -189,6 +193,7 @@ struct ContentFeatures
|
||||||
initial_metadata = NULL;
|
initial_metadata = NULL;
|
||||||
liquid_alternative_flowing = CONTENT_IGNORE;
|
liquid_alternative_flowing = CONTENT_IGNORE;
|
||||||
liquid_alternative_source = CONTENT_IGNORE;
|
liquid_alternative_source = CONTENT_IGNORE;
|
||||||
|
liquid_viscosity = 0;
|
||||||
vertex_alpha = 255;
|
vertex_alpha = 255;
|
||||||
special_material = NULL;
|
special_material = NULL;
|
||||||
special_atlas = NULL;
|
special_atlas = NULL;
|
||||||
|
@ -424,6 +429,10 @@ enum LightBank
|
||||||
#define LIQUID_LEVEL_MASK 0x07
|
#define LIQUID_LEVEL_MASK 0x07
|
||||||
#define LIQUID_FLOW_DOWN_MASK 0x08
|
#define LIQUID_FLOW_DOWN_MASK 0x08
|
||||||
|
|
||||||
|
/* maximum amount of liquid in a block */
|
||||||
|
#define LIQUID_LEVEL_MAX LIQUID_LEVEL_MASK
|
||||||
|
#define LIQUID_LEVEL_SOURCE (LIQUID_LEVEL_MAX+1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is the stuff what the whole world consists of.
|
This is the stuff what the whole world consists of.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue