From 5e0c284f3a8debdd9ebb080f80e36dceb7bc4ce2 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Wed, 1 Dec 2010 15:20:12 +0200 Subject: [PATCH] some work-in-progress water stuff --- Makefile | 4 +- src/main.cpp | 194 +++++++++++++++++++++++++++++++++++ src/mapnode.h | 22 +--- src/test.cpp | 55 ++++++++-- src/voxel.cpp | 278 +++++++++++++++++++++++++++++++++----------------- src/voxel.h | 119 +++++++++++++++------ 6 files changed, 517 insertions(+), 155 deletions(-) diff --git a/Makefile b/Makefile index 2b4e8dda3..102a3dcdb 100644 --- a/Makefile +++ b/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 diff --git a/src/main.cpp b/src/main.cpp index 677f03843..938eb14ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,6 +81,9 @@ SUGGESTION: Use same technique for sector heightmaps as what we're using for UnlimitedHeightmap? (getting all neighbors when generating) +TODO: Proper handling of spawning place (try to find something that + is not in the middle of an ocean (some land to stand on at + least) and save it in map config. SUGG: Set server to automatically find a good spawning place in some place where there is water and land. - Map to have a getWalkableNear(p) @@ -176,6 +179,197 @@ TODO: MovingObject::move and Player::move are basically the same. Doing now: ====================================================================== +Water dynamics pseudo-code (block = MapNode): +SUGG: Create separate flag table in VoxelManipulator to allow fast +clearing of "modified" flags + +neighborCausedPressure(pos): + pressure = 0 + dirs = {down, left, right, back, front, up} + for d in dirs: + pos2 = pos + d + p = block_at(pos2).pressure + if d.Y == 1 and p > min: + p -= 1 + if d.Y == -1 and p < max: + p += 1 + if p > pressure: + pressure = p + return pressure + +# This should somehow update all changed pressure values +# in an unknown body of water +updateWaterPressure(pos): + TODO + +FIXME: This goes in an indefinite loop when there is an underwater +chamber like this: + +#111###### +#222##22## +#33333333x<- block removed from here +########## + +#111###### +#222##22## +#3333333x1 +########## + +#111###### +#222##22## +#333333x11 +########## + +#111###### +#222##2x## +#333333333 +########## + +#111###### +#222##x2## +#333333333 +########## + +Now, consider moving to the last block not allowed. + +Consider it a 3D case with a depth of 2. We're now at this situation. +Note the additional blocking ## in the second depth plane. + +z=1 z=2 +#111###### #111###### +#222##x2## #222##22## +#333333333 #33333##33 +########## ########## + +#111###### #111###### +#222##22## #222##x2## +#333333333 #33333##33 +########## ########## + +#111###### #111###### +#222##22## #222##2x## +#333333333 #33333##33 +########## ########## + +Now there is nowhere to go, without going to an already visited block, +but the pressure calculated in here from neighboring blocks is >= 2, +so it is not the final ending. + +We will back up to a state where there is somewhere to go to. +It is this state: + +#111###### #111###### +#222##22## #222##22## +#333333x33 #33333##33 +########## ########## + +Then just go on, avoiding already visited blocks: + +#111###### #111###### +#222##22## #222##22## +#33333x333 #33333##33 +########## ########## + +#111###### #111###### +#222##22## #222##22## +#3333x3333 #33333##33 +########## ########## + +#111###### #111###### +#222##22## #222##22## +#333x33333 #33333##33 +########## ########## + +#111###### #111###### +#222##22## #222##22## +#33x333333 #33333##33 +########## ########## + +#111###### #111###### +#22x##22## #222##22## +#333333333 #33333##33 +########## ########## + +#11x###### #111###### +#222##22## #222##22## +#333333333 #33333##33 +########## ########## + +"Blob". the air bubble finally got out of the water. +Then return recursively to a state where there is air next to water, +clear the visit flags and feed the neighbor of the water recursively +to the algorithm. + +#11 ###### #111###### +#222##22## #222##22## +#333333333x #33333##33 +########## ########## + +#11 ###### #111###### +#222##22## #222##22## +#33333333x3 #33333##33 +########## ########## + +...and so on. + + +# removed_pos: a position that has been changed from something to air +flowWater(removed_pos): + dirs = {top, left, right, back, front, bottom} + selected_dir = None + for d in dirs: + b2 = removed_pos + d + + # Ignore positions that don't have water + if block_at(b2) != water: + continue + + # Ignore positions that have already been checked + if block_at(b2).checked: + continue + + # If block is at top, select it always. + if d.Y == 1: + selected_dir = d + break + + # If block is at bottom, select it if it has enough pressure. + # >= 3 needed for stability (and sanity) + if d.Y == -1: + if block_at(b2).pressure >= 3: + selected_dir = d + break + continue + + # Else block is at some side. select it if it has enough pressure. + if block_at(b2).pressure >= 2: + selected_dir = d + break + + # If there is nothing to do anymore, return. + if selected_dir == None + return + + b2 = removed_pos + selected_dir + + # Move block + set_block(removed_pos, block_at(b2)) + set_block(b2, air_block) + + # Update pressure + updateWaterPressure(removed_pos) + + # Flow water to the newly created empty position + flowWater(b2) + + # Check empty positions around and try flowing water to them + for d in dirs: + b3 = removed_pos + d + # Ignore positions that are not air + if block_at(b3) is not air: + continue + flowWater(b3) + ====================================================================== diff --git a/src/mapnode.h b/src/mapnode.h index 789cedb27..02abe4e52 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -35,9 +35,6 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Ignored node. - param is used for custom information in special containers, - like VoxelManipulator. - Anything that stores MapNodes doesn't have to preserve parameters associated with this material. @@ -67,27 +64,12 @@ enum Material MATERIAL_GRASS, - /* - For water, the param is water pressure. 0...127. - TODO: No, at least the lowest nibble is used for lighting. - - - Water will be a bit like light, but with different flow - behavior. - - Water blocks will fall down if there is empty space below. - - If there is water below, the pressure of the block below is - the pressure of the current block + 1, or higher. - - If there is any pressure in a horizontally neighboring - block, a water block will try to move away from it. - - If there is >=2 of pressure in a block below, water will - try to move upwards. - - NOTE: To keep large operations fast, we have to keep a - cache of the water-air-surfaces, just like with light - */ MATERIAL_WATER, MATERIAL_LIGHT, MATERIAL_TREE, + MATERIAL_LEAVES, MATERIAL_GRASS_FOOTSTEPS, @@ -216,6 +198,8 @@ struct MapNode */ s8 param; + u8 pressure; + MapNode(const MapNode & n) { *this = n; diff --git a/src/test.cpp b/src/test.cpp index 005db2d24..6b285e3a4 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -157,17 +157,16 @@ struct TestVoxelManipulator v.print(dstream); dstream<<"*** Setting (-1,0,-1)=2 ***"<=0; y--) + for(s16 x=0; x=m_area.MinEdge.Y; y--) + { + if(em.X >= 3 && em.Y >= 3) + { + if (y==m_area.MinEdge.Y+2) o<<"^ "; + else if(y==m_area.MinEdge.Y+1) o<<"| "; + else if(y==m_area.MinEdge.Y+0) o<<"y x-> "; + else o<<" "; + } + + for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++) + { + for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++) + { + u8 f = m_flags[m_area.index(x,y,z)]; + char c; + if(f & VOXELFLAG_NOT_LOADED) + c = 'N'; + else if(f & VOXELFLAG_INEXISTENT) + c = 'I'; + else + { + c = 'X'; + u8 m = m_data[m_area.index(x,y,z)].d; + if(m <= 9) + c = m + '0'; + } + o<= 3 && em.Y >= 3) - { - if(y==m_area.MinEdge.Y+0) o<<"y x-> "; - if(y==m_area.MinEdge.Y+1) o<<"| "; - if(y==m_area.MinEdge.Y+2) o<<"V "; - } + m_area = new_area; + + MapNode *old_data = m_data; + u8 *old_flags = m_flags; - for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++) - { - for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++) - { - u8 m = m_data[m_area.index(x,y,z)].d; - char c = 'X'; - if(m == MATERIAL_IGNORE) - c = 'I'; - else if(m <= 9) - c = m + '0'; - o<