From 708f1c336ef8214e380791b69213a3e3ddd873e2 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 06:00:40 +0200 Subject: [PATCH 1/8] transformLiquid: small optimization and whitespace cleanup --- src/map.cpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 9d67c8282..a540860bc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1575,7 +1575,7 @@ void Map::transformLiquids(core::map & modified_blocks) v3s16 p0 = m_transforming_liquid.pop_front(); MapNode n0 = getNodeNoEx(p0); - + /* Collect information about current node */ @@ -1599,18 +1599,11 @@ void Map::transformLiquids(core::map & modified_blocks) liquid_kind = CONTENT_AIR; break; } - + /* Collect information about the environment */ - v3s16 dirs[6] = { - 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 - }; + const v3s16 *dirs = g_6dirs; NodeNeighbor sources[6]; // surrounding sources int num_sources = 0; NodeNeighbor flows[6]; // surrounding flowing liquid nodes @@ -1623,10 +1616,10 @@ void Map::transformLiquids(core::map & modified_blocks) for (u16 i = 0; i < 6; i++) { NeighborType nt = NEIGHBOR_SAME_LEVEL; switch (i) { - case 0: + case 1: nt = NEIGHBOR_UPPER; break; - case 1: + case 4: nt = NEIGHBOR_LOWER; break; } @@ -1667,7 +1660,7 @@ void Map::transformLiquids(core::map & modified_blocks) break; } } - + /* decide on the type (and possibly level) of the current node */ @@ -1717,13 +1710,13 @@ void Map::transformLiquids(core::map & modified_blocks) if (!at_wall) new_node_level -= 1; } - + if (new_node_level >= 0) new_node_content = liquid_kind; else new_node_content = CONTENT_AIR; } - + /* check if anything has changed. if not, just continue with the next node. */ @@ -1732,8 +1725,8 @@ void Map::transformLiquids(core::map & modified_blocks) ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) == flowing_down))) continue; - - + + /* update the current node */ @@ -1751,7 +1744,7 @@ void Map::transformLiquids(core::map & modified_blocks) MapBlock *block = getBlockNoCreateNoEx(blockpos); if(block != NULL) modified_blocks.insert(blockpos, block); - + /* enqueue neighbors for update if neccessary */ From 5fce673a569747960dbe5befec8e2c42b87ce7f6 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 08:31:33 +0200 Subject: [PATCH 2/8] Use defines for liquid levels --- src/map.cpp | 8 ++++---- src/mapnode.h | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index a540860bc..94cf2e864 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1584,7 +1584,7 @@ void Map::transformLiquids(core::map & modified_blocks) LiquidType liquid_type = content_features(n0.getContent()).liquid_type; switch (liquid_type) { case LIQUID_SOURCE: - liquid_level = 8; + liquid_level = LIQUID_LEVEL_SOURCE; liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing; break; case LIQUID_FLOWING: @@ -1674,7 +1674,7 @@ void Map::transformLiquids(core::map & modified_blocks) } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) { // liquid_kind is set properly, see above new_node_content = liquid_kind; - new_node_level = 7; + new_node_level = LIQUID_LEVEL_MAX; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { @@ -1682,8 +1682,8 @@ void Map::transformLiquids(core::map & modified_blocks) switch (flows[i].t) { case NEIGHBOR_UPPER: if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) { - new_node_level = 7; - if (nb_liquid_level + WATER_DROP_BOOST < 7) + new_node_level = LIQUID_LEVEL_MAX; + if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX) new_node_level = nb_liquid_level + WATER_DROP_BOOST; } break; diff --git a/src/mapnode.h b/src/mapnode.h index 3101a9fc1..77f6b321f 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -424,6 +424,10 @@ enum LightBank #define LIQUID_LEVEL_MASK 0x07 #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. */ From 7024b4519746f267144482a47136a32f9a697546 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 16:46:55 +0200 Subject: [PATCH 3/8] Ensure param2 is set correctly in transformLiquids --- src/map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 94cf2e864..6092538fe 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1731,14 +1731,14 @@ void Map::transformLiquids(core::map & modified_blocks) update the current node */ bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK)); - n0.setContent(new_node_content); - if (content_features(n0.getContent()).liquid_type == LIQUID_FLOWING) { + if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) { // 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 { // 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); v3s16 blockpos = getNodeBlockPos(p0); MapBlock *block = getBlockNoCreateNoEx(blockpos); From d0711821f3a4ec2d2e41c7baae37329972781ef3 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 07:24:01 +0200 Subject: [PATCH 4/8] Ensure air neighbors to liquids that can flow are enqueued for transformation --- src/map.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 6092538fe..fa88e846f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1629,9 +1629,15 @@ void Map::transformLiquids(core::map & modified_blocks) case LIQUID_NONE: if (nb.n.getContent() == CONTENT_AIR) { 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 (nb.t == NEIGHBOR_LOWER) + if (nb.t == NEIGHBOR_LOWER) { flowing_down = true; + } } else { neutrals[num_neutrals++] = nb; } From 774faf4e85c08bb4c78404fb0af4eebfad5720cb Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 17:42:28 +0200 Subject: [PATCH 5/8] Let the liquids flow in the open No need to curb their spread artificially. --- src/map.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index fa88e846f..17bca82db 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1703,19 +1703,6 @@ void Map::transformLiquids(core::map & modified_blocks) 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. - if (!flowing_down && new_node_level >= 1) { - bool at_wall = false; - for (u16 i = 0; i < num_neutrals; i++) { - if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) { - at_wall = true; - break; - } - } - if (!at_wall) - new_node_level -= 1; - } if (new_node_level >= 0) new_node_content = liquid_kind; From 56e9f97294ebc39967a3d029fe07e7c74849c1a1 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 18:05:28 +0200 Subject: [PATCH 6/8] Make sure all neighbors of changed fluids are activated This should fix the remaining cases of fluid not advancing or not retreating. --- src/map.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 17bca82db..3aff00c94 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1743,6 +1743,7 @@ void Map::transformLiquids(core::map & modified_blocks) */ switch (content_features(n0.getContent()).liquid_type) { case LIQUID_SOURCE: + case LIQUID_FLOWING: // make sure source flows into all neighboring nodes for (u16 i = 0; i < num_flows; i++) if (flows[i].t != NEIGHBOR_UPPER) @@ -1756,19 +1757,6 @@ void Map::transformLiquids(core::map & modified_blocks) for (u16 i = 0; i < num_flows; i++) m_transforming_liquid.push_back(flows[i].p); 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="< Date: Tue, 16 Aug 2011 19:56:57 +0200 Subject: [PATCH 7/8] Viscous fluids --- src/content_mapnode.cpp | 7 +++++++ src/map.cpp | 35 +++++++++++++++++++++++++++++------ src/mapnode.h | 5 +++++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index 7174a8a4b..f45853c4a 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -26,6 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define WATER_ALPHA 160 +#define WATER_VISC 1 +#define LAVA_VISC 7 + // TODO: Get rid of these and set up some attributes like toughness, // fluffyness, and a funciton to calculate time and durability loss // (and sound? and whatever else) from them @@ -374,6 +377,7 @@ void content_mapnode_init() f->liquid_type = LIQUID_FLOWING; f->liquid_alternative_flowing = CONTENT_WATER; f->liquid_alternative_source = CONTENT_WATERSOURCE; + f->liquid_viscosity = WATER_VISC; f->vertex_alpha = WATER_ALPHA; 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->liquid_alternative_flowing = CONTENT_WATER; f->liquid_alternative_source = CONTENT_WATERSOURCE; + f->liquid_viscosity = WATER_VISC; f->vertex_alpha = WATER_ALPHA; if(f->special_material == NULL && g_texturesource) { @@ -451,6 +456,7 @@ void content_mapnode_init() f->liquid_type = LIQUID_FLOWING; f->liquid_alternative_flowing = CONTENT_LAVA; f->liquid_alternative_source = CONTENT_LAVASOURCE; + f->liquid_viscosity = LAVA_VISC; f->damage_per_second = 4*2; 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->liquid_alternative_flowing = CONTENT_LAVA; f->liquid_alternative_source = CONTENT_LAVASOURCE; + f->liquid_viscosity = LAVA_VISC; f->damage_per_second = 4*2; if(f->special_material == NULL && g_texturesource) { diff --git a/src/map.cpp b/src/map.cpp index 3aff00c94..6331055aa 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1562,6 +1562,9 @@ void Map::transformLiquids(core::map & modified_blocks) /*if(initial_size != 0) dstream<<"transformLiquids(): initial_size="< must_reflow; + while(m_transforming_liquid.size() != 0) { // This should be done here so that it is done when continue is used @@ -1672,6 +1675,7 @@ void Map::transformLiquids(core::map & modified_blocks) */ content_t new_node_content; s8 new_node_level = -1; + s8 max_node_level = -1; 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) // or the flowing alternative of the first of the surrounding sources (if it's air), so @@ -1680,34 +1684,51 @@ void Map::transformLiquids(core::map & modified_blocks) } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) { // liquid_kind is set properly, see above new_node_content = liquid_kind; - new_node_level = LIQUID_LEVEL_MAX; + max_node_level = new_node_level = LIQUID_LEVEL_MAX; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); switch (flows[i].t) { case NEIGHBOR_UPPER: - if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) { - new_node_level = LIQUID_LEVEL_MAX; + if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) { + max_node_level = LIQUID_LEVEL_MAX; 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; case NEIGHBOR_LOWER: break; case NEIGHBOR_SAME_LEVEL: if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && - nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) { - new_node_level = nb_liquid_level - 1; + nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) { + max_node_level = nb_liquid_level - 1; } break; } } + if (max_node_level != liquid_level) { + // amount to gain, limited by viscosity + // must be at least 1 in absolute value + s8 level_inc = max_node_level - liquid_level; + u8 viscosity = content_features(liquid_kind).liquid_viscosity; + if (level_inc < -viscosity || level_inc > viscosity) + new_node_level = liquid_level + level_inc/viscosity; + else if (level_inc < 0) + new_node_level = liquid_level - 1; + else if (level_inc > 0) + 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) new_node_content = liquid_kind; else new_node_content = CONTENT_AIR; + } /* @@ -1760,6 +1781,8 @@ void Map::transformLiquids(core::map & modified_blocks) } } //dstream<<"Map::transformLiquids(): loopcount="< 0) + m_transforming_liquid.push_back(must_reflow.pop_front()); } NodeMetadata* Map::getNodeMetadata(v3s16 p) diff --git a/src/mapnode.h b/src/mapnode.h index 77f6b321f..4c2b92853 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -153,6 +153,10 @@ struct ContentFeatures content_t liquid_alternative_flowing; // If the content is liquid, this is the source version of the liquid. 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 u8 vertex_alpha; // Special irrlicht material, used sometimes @@ -189,6 +193,7 @@ struct ContentFeatures initial_metadata = NULL; liquid_alternative_flowing = CONTENT_IGNORE; liquid_alternative_source = CONTENT_IGNORE; + liquid_viscosity = 0; vertex_alpha = 255; special_material = NULL; special_atlas = NULL; From c51564ab5b97e0b603de5413bd28aa1f729de5ba Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 16 Aug 2011 20:38:44 +0200 Subject: [PATCH 8/8] Optimize for viscosity 1 --- src/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 6331055aa..f5c4a5e02 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1708,11 +1708,11 @@ void Map::transformLiquids(core::map & modified_blocks) } } - if (max_node_level != liquid_level) { + u8 viscosity = content_features(liquid_kind).liquid_viscosity; + if (viscosity > 1 && max_node_level != liquid_level) { // amount to gain, limited by viscosity // must be at least 1 in absolute value s8 level_inc = max_node_level - liquid_level; - u8 viscosity = content_features(liquid_kind).liquid_viscosity; if (level_inc < -viscosity || level_inc > viscosity) new_node_level = liquid_level + level_inc/viscosity; else if (level_inc < 0)