aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mapgen.cpp87
-rw-r--r--src/mapgen.h4
2 files changed, 77 insertions, 14 deletions
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 32f7e29eb..b5c48a471 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -213,27 +213,86 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
//printf("updateHeightmap: %dus\n", t.stop());
}
+inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
+{
+ u32 vi_neg_x = vi;
+ vm->m_area.add_x(em, vi_neg_x, -1);
+ if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
+ const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
+ if (c_nx.floodable && !c_nx.isLiquid())
+ return true;
+ }
+ u32 vi_pos_x = vi;
+ vm->m_area.add_x(em, vi_pos_x, +1);
+ if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
+ const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
+ if (c_px.floodable && !c_px.isLiquid())
+ return true;
+ }
+ u32 vi_neg_z = vi;
+ vm->m_area.add_z(em, vi_neg_z, -1);
+ if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
+ const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
+ if (c_nz.floodable && !c_nz.isLiquid())
+ return true;
+ }
+ u32 vi_pos_z = vi;
+ vm->m_area.add_z(em, vi_pos_z, +1);
+ if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
+ const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
+ if (c_pz.floodable && !c_pz.isLiquid())
+ return true;
+ }
+ return false;
+}
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
{
- bool isliquid, wasliquid;
+ bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
v3s16 em = vm->m_area.getExtent();
- for (s16 z = nmin.Z; z <= nmax.Z; z++) {
- for (s16 x = nmin.X; x <= nmax.X; x++) {
- wasliquid = true;
-
- u32 i = vm->m_area.index(x, nmax.Y, z);
- for (s16 y = nmax.Y; y >= nmin.Y; y--) {
- isliquid = ndef->get(vm->m_data[i]).isLiquid();
-
- // there was a change between liquid and nonliquid, add to queue.
- if (isliquid != wasliquid)
+ for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
+ for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
+ wasignored = true;
+ wasliquid = false;
+ waschecked = false;
+ waspushed = false;
+
+ u32 vi = vm->m_area.index(x, nmax.Y, z);
+ for (s16 y = nmax.Y; y >= nmin.Y; y--) {
+ isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
+ isliquid = ndef->get(vm->m_data[vi]).isLiquid();
+
+ if (isignored || wasignored || isliquid == wasliquid) {
+ // Neither topmost node of liquid column nor topmost node below column
+ waschecked = false;
+ waspushed = false;
+ } else if (isliquid) {
+ // This is the topmost node in the column
+ bool ispushed = false;
+ if (isLiquidHorizontallyFlowable(vi, em)) {
trans_liquid->push_back(v3s16(x, y, z));
-
- wasliquid = isliquid;
- vm->m_area.add_y(em, i, -1);
+ ispushed = true;
+ }
+ // Remember waschecked and waspushed to avoid repeated
+ // checks/pushes in case the column consists of only this node
+ waschecked = true;
+ waspushed = ispushed;
+ } else {
+ // This is the topmost node below a liquid column
+ u32 vi_above = vi;
+ vm->m_area.add_y(em, vi_above, 1);
+ if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
+ (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
+ // Push back the lowest node in the column which is one
+ // node above this one
+ trans_liquid->push_back(v3s16(x, y + 1, z));
+ }
}
+
+ wasliquid = isliquid;
+ wasignored = isignored;
+ vm->m_area.add_y(em, vi, -1);
}
}
}
diff --git a/src/mapgen.h b/src/mapgen.h
index f673007b5..90ac84bd8 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -199,6 +199,10 @@ public:
virtual int getSpawnLevelAtPoint(v2s16 p) { return 0; }
private:
+ // isLiquidHorizontallyFlowable() is a helper function for updateLiquid()
+ // that checks whether there are floodable nodes without liquid beneath
+ // the node at index vi.
+ inline bool isLiquidHorizontallyFlowable(u32 vi, v3s16 em);
DISABLE_CLASS_COPY(Mapgen);
};