Liquids: Flow into and destroy 'floodable' nodes
Add new node property 'floodable', default false Define "air" as floodable = true in C++ and luamaster
parent
bd40ee2b95
commit
0bbbc6e13d
|
@ -574,6 +574,7 @@ core.nodedef_default = {
|
||||||
diggable = true,
|
diggable = true,
|
||||||
climbable = false,
|
climbable = false,
|
||||||
buildable_to = false,
|
buildable_to = false,
|
||||||
|
floodable = false,
|
||||||
liquidtype = "none",
|
liquidtype = "none",
|
||||||
liquid_alternative_flowing = "",
|
liquid_alternative_flowing = "",
|
||||||
liquid_alternative_source = "",
|
liquid_alternative_source = "",
|
||||||
|
|
|
@ -289,6 +289,7 @@ core.register_node(":air", {
|
||||||
pointable = false,
|
pointable = false,
|
||||||
diggable = false,
|
diggable = false,
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
|
floodable = true,
|
||||||
air_equivalent = true,
|
air_equivalent = true,
|
||||||
drop = "",
|
drop = "",
|
||||||
groups = {not_in_creative_inventory=1},
|
groups = {not_in_creative_inventory=1},
|
||||||
|
|
|
@ -3396,6 +3396,7 @@ Definition tables
|
||||||
diggable = true, -- If false, can never be dug
|
diggable = true, -- If false, can never be dug
|
||||||
climbable = false, -- If true, can be climbed on (ladder)
|
climbable = false, -- If true, can be climbed on (ladder)
|
||||||
buildable_to = false, -- If true, placed nodes can replace this node
|
buildable_to = false, -- If true, placed nodes can replace this node
|
||||||
|
floodable = false, -- If true, liquids flow into and replace this node
|
||||||
liquidtype = "none", -- "none"/"source"/"flowing"
|
liquidtype = "none", -- "none"/"source"/"flowing"
|
||||||
liquid_alternative_flowing = "", -- Flowing version of source liquid
|
liquid_alternative_flowing = "", -- Flowing version of source liquid
|
||||||
liquid_alternative_source = "", -- Source version of flowing liquid
|
liquid_alternative_source = "", -- Source version of flowing liquid
|
||||||
|
|
70
src/map.cpp
70
src/map.cpp
|
@ -1654,10 +1654,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
loop_max *= m_transforming_liquid_loop_count_multiplier;
|
loop_max *= m_transforming_liquid_loop_count_multiplier;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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
|
||||||
if(loopcount >= initial_size || loopcount >= loop_max)
|
if (loopcount >= initial_size || loopcount >= loop_max)
|
||||||
break;
|
break;
|
||||||
loopcount++;
|
loopcount++;
|
||||||
|
|
||||||
|
@ -1674,21 +1674,24 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
*/
|
*/
|
||||||
s8 liquid_level = -1;
|
s8 liquid_level = -1;
|
||||||
content_t liquid_kind = CONTENT_IGNORE;
|
content_t liquid_kind = CONTENT_IGNORE;
|
||||||
LiquidType liquid_type = nodemgr->get(n0).liquid_type;
|
content_t floodable_node = CONTENT_AIR;
|
||||||
|
ContentFeatures cf = nodemgr->get(n0);
|
||||||
|
LiquidType liquid_type = cf.liquid_type;
|
||||||
switch (liquid_type) {
|
switch (liquid_type) {
|
||||||
case LIQUID_SOURCE:
|
case LIQUID_SOURCE:
|
||||||
liquid_level = LIQUID_LEVEL_SOURCE;
|
liquid_level = LIQUID_LEVEL_SOURCE;
|
||||||
liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
|
liquid_kind = nodemgr->getId(cf.liquid_alternative_flowing);
|
||||||
break;
|
break;
|
||||||
case LIQUID_FLOWING:
|
case LIQUID_FLOWING:
|
||||||
liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
|
liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
|
||||||
liquid_kind = n0.getContent();
|
liquid_kind = n0.getContent();
|
||||||
break;
|
break;
|
||||||
case LIQUID_NONE:
|
case LIQUID_NONE:
|
||||||
// if this is an air node, it *could* be transformed into a liquid. otherwise,
|
// if this node is 'floodable', it *could* be transformed
|
||||||
// continue with the next node.
|
// into a liquid, otherwise, continue with the next node.
|
||||||
if (n0.getContent() != CONTENT_AIR)
|
if (!cf.floodable)
|
||||||
continue;
|
continue;
|
||||||
|
floodable_node = n0.getContent();
|
||||||
liquid_kind = CONTENT_AIR;
|
liquid_kind = CONTENT_AIR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1718,9 +1721,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
}
|
}
|
||||||
v3s16 npos = p0 + dirs[i];
|
v3s16 npos = p0 + dirs[i];
|
||||||
NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
|
NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
|
||||||
|
ContentFeatures cfnb = nodemgr->get(nb.n);
|
||||||
switch (nodemgr->get(nb.n.getContent()).liquid_type) {
|
switch (nodemgr->get(nb.n.getContent()).liquid_type) {
|
||||||
case LIQUID_NONE:
|
case LIQUID_NONE:
|
||||||
if (nb.n.getContent() == CONTENT_AIR) {
|
if (cfnb.floodable) {
|
||||||
airs[num_airs++] = nb;
|
airs[num_airs++] = nb;
|
||||||
// if the current node is a water source the neighbor
|
// if the current node is a water source the neighbor
|
||||||
// should be enqueded for transformation regardless of whether the
|
// should be enqueded for transformation regardless of whether the
|
||||||
|
@ -1738,8 +1742,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
case LIQUID_SOURCE:
|
case LIQUID_SOURCE:
|
||||||
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
|
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
|
||||||
if (liquid_kind == CONTENT_AIR)
|
if (liquid_kind == CONTENT_AIR)
|
||||||
liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
|
liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
|
||||||
if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
|
if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
|
||||||
neutrals[num_neutrals++] = nb;
|
neutrals[num_neutrals++] = nb;
|
||||||
} else {
|
} else {
|
||||||
// Do not count bottom source, it will screw things up
|
// Do not count bottom source, it will screw things up
|
||||||
|
@ -1750,8 +1754,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
case LIQUID_FLOWING:
|
case LIQUID_FLOWING:
|
||||||
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
|
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
|
||||||
if (liquid_kind == CONTENT_AIR)
|
if (liquid_kind == CONTENT_AIR)
|
||||||
liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
|
liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
|
||||||
if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
|
if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
|
||||||
neutrals[num_neutrals++] = nb;
|
neutrals[num_neutrals++] = nb;
|
||||||
} else {
|
} else {
|
||||||
flows[num_flows++] = nb;
|
flows[num_flows++] = nb;
|
||||||
|
@ -1770,8 +1774,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
s8 max_node_level = -1;
|
s8 max_node_level = -1;
|
||||||
|
|
||||||
u8 range = nodemgr->get(liquid_kind).liquid_range;
|
u8 range = nodemgr->get(liquid_kind).liquid_range;
|
||||||
if (range > LIQUID_LEVEL_MAX+1)
|
if (range > LIQUID_LEVEL_MAX + 1)
|
||||||
range = LIQUID_LEVEL_MAX+1;
|
range = LIQUID_LEVEL_MAX + 1;
|
||||||
|
|
||||||
if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
|
if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || 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)
|
||||||
|
@ -1780,10 +1784,11 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
|
new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
|
||||||
} 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;
|
|
||||||
max_node_level = new_node_level = LIQUID_LEVEL_MAX;
|
max_node_level = new_node_level = LIQUID_LEVEL_MAX;
|
||||||
if (new_node_level < (LIQUID_LEVEL_MAX+1-range))
|
if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
|
||||||
new_node_content = CONTENT_AIR;
|
new_node_content = liquid_kind;
|
||||||
|
else
|
||||||
|
new_node_content = floodable_node;
|
||||||
} 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++) {
|
||||||
|
@ -1794,16 +1799,16 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
max_node_level = LIQUID_LEVEL_MAX;
|
max_node_level = LIQUID_LEVEL_MAX;
|
||||||
if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
|
if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
|
||||||
max_node_level = nb_liquid_level + WATER_DROP_BOOST;
|
max_node_level = nb_liquid_level + WATER_DROP_BOOST;
|
||||||
} else if (nb_liquid_level > max_node_level)
|
} else if (nb_liquid_level > max_node_level) {
|
||||||
max_node_level = nb_liquid_level;
|
max_node_level = nb_liquid_level;
|
||||||
|
}
|
||||||
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 > max_node_level) {
|
nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
|
||||||
max_node_level = nb_liquid_level - 1;
|
max_node_level = nb_liquid_level - 1;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1821,23 +1826,25 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
new_node_level = liquid_level + 1;
|
new_node_level = liquid_level + 1;
|
||||||
if (new_node_level != max_node_level)
|
if (new_node_level != max_node_level)
|
||||||
must_reflow.push_back(p0);
|
must_reflow.push_back(p0);
|
||||||
} else
|
} else {
|
||||||
new_node_level = max_node_level;
|
new_node_level = max_node_level;
|
||||||
|
}
|
||||||
|
|
||||||
if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
|
if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
|
||||||
new_node_content = liquid_kind;
|
new_node_content = liquid_kind;
|
||||||
else
|
else
|
||||||
new_node_content = CONTENT_AIR;
|
new_node_content = floodable_node;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
|
if (new_node_content == n0.getContent() &&
|
||||||
((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
|
(nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
|
||||||
((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
|
((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
|
||||||
== flowing_down)))
|
((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
|
||||||
|
== flowing_down)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1857,11 +1864,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
|
|
||||||
// Find out whether there is a suspect for this action
|
// Find out whether there is a suspect for this action
|
||||||
std::string suspect;
|
std::string suspect;
|
||||||
if(m_gamedef->rollback()) {
|
if (m_gamedef->rollback())
|
||||||
suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
|
suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
|
||||||
}
|
|
||||||
|
|
||||||
if(m_gamedef->rollback() && !suspect.empty()){
|
if (m_gamedef->rollback() && !suspect.empty()) {
|
||||||
// Blame suspect
|
// Blame suspect
|
||||||
RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
|
RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
|
||||||
// Get old node for rollback
|
// Get old node for rollback
|
||||||
|
@ -1880,10 +1886,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
|
|
||||||
v3s16 blockpos = getNodeBlockPos(p0);
|
v3s16 blockpos = getNodeBlockPos(p0);
|
||||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||||
if(block != NULL) {
|
if (block != NULL) {
|
||||||
modified_blocks[blockpos] = block;
|
modified_blocks[blockpos] = block;
|
||||||
// If new or old node emits light, MapBlock requires lighting update
|
// If new or old node emits light, MapBlock requires lighting update
|
||||||
if(nodemgr->get(n0).light_source != 0 ||
|
if (nodemgr->get(n0).light_source != 0 ||
|
||||||
nodemgr->get(n00).light_source != 0)
|
nodemgr->get(n00).light_source != 0)
|
||||||
lighting_modified_blocks[block->getPos()] = block;
|
lighting_modified_blocks[block->getPos()] = block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,6 +233,7 @@ void ContentFeatures::reset()
|
||||||
diggable = true;
|
diggable = true;
|
||||||
climbable = false;
|
climbable = false;
|
||||||
buildable_to = false;
|
buildable_to = false;
|
||||||
|
floodable = false;
|
||||||
rightclickable = true;
|
rightclickable = true;
|
||||||
leveled = 0;
|
leveled = 0;
|
||||||
liquid_type = LIQUID_NONE;
|
liquid_type = LIQUID_NONE;
|
||||||
|
@ -318,6 +319,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
|
||||||
// the protocol version
|
// the protocol version
|
||||||
os<<serializeString(mesh);
|
os<<serializeString(mesh);
|
||||||
collision_box.serialize(os, protocol_version);
|
collision_box.serialize(os, protocol_version);
|
||||||
|
writeU8(os, floodable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentFeatures::deSerialize(std::istream &is)
|
void ContentFeatures::deSerialize(std::istream &is)
|
||||||
|
@ -388,6 +390,7 @@ void ContentFeatures::deSerialize(std::istream &is)
|
||||||
// otherwise changes the protocol version
|
// otherwise changes the protocol version
|
||||||
mesh = deSerializeString(is);
|
mesh = deSerializeString(is);
|
||||||
collision_box.deSerialize(is);
|
collision_box.deSerialize(is);
|
||||||
|
floodable = readU8(is);
|
||||||
}catch(SerializationError &e) {};
|
}catch(SerializationError &e) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +523,7 @@ void CNodeDefManager::clear()
|
||||||
f.pointable = false;
|
f.pointable = false;
|
||||||
f.diggable = false;
|
f.diggable = false;
|
||||||
f.buildable_to = true;
|
f.buildable_to = true;
|
||||||
|
f.floodable = true;
|
||||||
f.is_ground_content = true;
|
f.is_ground_content = true;
|
||||||
// Insert directly into containers
|
// Insert directly into containers
|
||||||
content_t c = CONTENT_AIR;
|
content_t c = CONTENT_AIR;
|
||||||
|
|
|
@ -229,6 +229,8 @@ struct ContentFeatures
|
||||||
bool climbable;
|
bool climbable;
|
||||||
// Player can build on these
|
// Player can build on these
|
||||||
bool buildable_to;
|
bool buildable_to;
|
||||||
|
// Liquids flow into and replace node
|
||||||
|
bool floodable;
|
||||||
// Player cannot build to these (placement prediction disabled)
|
// Player cannot build to these (placement prediction disabled)
|
||||||
bool rightclickable;
|
bool rightclickable;
|
||||||
// Flowing liquid or snow, value = default level
|
// Flowing liquid or snow, value = default level
|
||||||
|
|
|
@ -481,6 +481,8 @@ ContentFeatures read_content_features(lua_State *L, int index)
|
||||||
getboolfield(L, index, "climbable", f.climbable);
|
getboolfield(L, index, "climbable", f.climbable);
|
||||||
// Player can build on these
|
// Player can build on these
|
||||||
getboolfield(L, index, "buildable_to", f.buildable_to);
|
getboolfield(L, index, "buildable_to", f.buildable_to);
|
||||||
|
// Liquids flow into and replace node
|
||||||
|
getboolfield(L, index, "floodable", f.floodable);
|
||||||
// Whether the node is non-liquid, source liquid or flowing liquid
|
// Whether the node is non-liquid, source liquid or flowing liquid
|
||||||
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
|
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
|
||||||
ScriptApiNode::es_LiquidType, LIQUID_NONE);
|
ScriptApiNode::es_LiquidType, LIQUID_NONE);
|
||||||
|
|
Loading…
Reference in New Issue