summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp215
-rw-r--r--src/map.cpp81
-rw-r--r--src/map.h11
-rw-r--r--src/mapblock.cpp64
-rw-r--r--src/mapnode.h62
-rw-r--r--src/server.cpp81
-rw-r--r--src/test.cpp4
-rw-r--r--src/voxel.cpp199
-rw-r--r--src/voxel.h8
9 files changed, 337 insertions, 388 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 73ef37951..fd91ab35c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -179,200 +179,19 @@ SUGG: MovingObject::move and Player::move are basically the same.
TODO: Transfer sign texts as metadata of block and not as data of
object
-Doing now:
-======================================================================
+SUGG: Implement a "Fast check queue" (a queue with a map for checking
+ if something is already in it)
+ - TODO: Use it in active block queue in water flowing
-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)
+TODO: Proper looking torches.
+ - Signs could be done in the same way?
- # 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)
+Doing now:
+======================================================================
+TODO: A system for showing some nodes in some other way than cubes
+ - Needed for torches
+ - Also for signs, stairs, etc
======================================================================
@@ -448,7 +267,8 @@ const char *g_material_filenames[MATERIALS_COUNT] =
"../data/leaves.png",
"../data/grass_footsteps.png",
"../data/mese.png",
- "../data/mud.png"
+ "../data/mud.png",
+ "../data/water.png", // ocean
};
video::SMaterial g_materials[MATERIALS_COUNT];
@@ -499,6 +319,8 @@ void set_default_settings()
g_settings.set("name", "");
g_settings.set("random_input", "false");
g_settings.set("client_delete_unused_sectors_timeout", "1200");
+ g_settings.set("max_block_send_distance", "8");
+ g_settings.set("max_block_generate_distance", "5");
// Server stuff
g_settings.set("creative_mode", "false");
@@ -1489,13 +1311,12 @@ int main(int argc, char *argv[])
g_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);
//g_materials[i].setFlag(video::EMF_ANISOTROPIC_FILTER, false);
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
- if(i == MATERIAL_WATER)
- {
- g_materials[i].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- //g_materials[i].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
- }
}
+ g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ //g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
+ g_materials[MATERIAL_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+
/*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));
g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));
g_mesh_materials[2].setTexture(0, driver->getTexture("../data/stone.png"));
diff --git a/src/map.cpp b/src/map.cpp
index 88cb0f3f7..1a7cd9bb9 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1819,7 +1819,8 @@ MapBlock * ServerMap::emergeBlock(
// If under water level, it's water
if(real_y < WATER_LEVEL)
{
- n.d = MATERIAL_WATER;
+ //n.d = MATERIAL_WATER;
+ n.d = MATERIAL_OCEAN;
n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
}
// else air
@@ -2731,34 +2732,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver,
DSTACK(__FUNCTION_NAME);
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
-#if 0
- /*
- Draw master heightmap mesh
- */
-
- {
- JMutexAutoLock lock(mesh_mutex);
- if(mesh != NULL)
- {
- u32 c = mesh->getMeshBufferCount();
-
- for(u32 i=0; i<c; i++)
- {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
- const video::SMaterial& material = buf->getMaterial();
- video::IMaterialRenderer* rnd =
- driver->getMaterialRenderer(material.MaterialType);
- bool transparent = (rnd && rnd->isTransparent());
- // Render transparent on transparent pass and likewise.
- if(transparent == is_transparent_pass)
- {
- driver->setMaterial(buf->getMaterial());
- driver->drawMeshBuffer(buf);
- }
- }
- }
- }
-#endif
/*
Get time for measuring timeout.
@@ -3162,7 +3135,8 @@ MapVoxelManipulator::~MapVoxelManipulator()
<<std::endl;
}
-void MapVoxelManipulator::emerge(VoxelArea a)
+#if 1
+void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
{
TimeTaker timer1("emerge", g_device, &emerge_time);
@@ -3190,8 +3164,11 @@ void MapVoxelManipulator::emerge(VoxelArea a)
{
TimeTaker timer1("emerge load", g_device, &emerge_load_time);
- dstream<<"Loading block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
- <<std::endl;
+ /*dstream<<"Loading block (caller_id="<<caller_id<<")"
+ <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+ <<" wanted area: ";
+ a.print(dstream);
+ dstream<<std::endl;*/
MapBlock *block = m_map->getBlockNoCreate(p);
if(block->isDummy())
@@ -3221,6 +3198,43 @@ void MapVoxelManipulator::emerge(VoxelArea a)
//dstream<<"emerge done"<<std::endl;
}
+#endif
+
+#if 0
+void MapVoxelManipulator::emerge(VoxelArea a)
+{
+ TimeTaker timer1("emerge", g_device, &emerge_time);
+
+ v3s16 size = a.getExtent();
+
+ VoxelArea padded = a;
+ padded.pad(m_area.getExtent() / 4);
+ addArea(padded);
+
+ for(s16 z=0; z<size.Z; z++)
+ for(s16 y=0; y<size.Y; y++)
+ for(s16 x=0; x<size.X; x++)
+ {
+ v3s16 p(x,y,z);
+ s32 i = m_area.index(a.MinEdge + p);
+ // Don't touch nodes that have already been loaded
+ if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
+ continue;
+ try
+ {
+ TimeTaker timer1("emerge load", g_device, &emerge_load_time);
+ MapNode n = m_map->getNode(a.MinEdge + p);
+ m_data[i] = n;
+ m_flags[i] = 0;
+ }
+ catch(InvalidPositionException &e)
+ {
+ m_flags[i] = VOXELFLAG_INEXISTENT;
+ }
+ }
+}
+#endif
+
/*
TODO: Add an option to only update eg. water and air nodes.
@@ -3230,6 +3244,9 @@ void MapVoxelManipulator::emerge(VoxelArea a)
void MapVoxelManipulator::blitBack
(core::map<v3s16, MapBlock*> & modified_blocks)
{
+ if(m_area.getExtent() == v3s16(0,0,0))
+ return;
+
TimeTaker timer1("blitBack", g_device);
/*
diff --git a/src/map.h b/src/map.h
index 62d1f8aee..6944107df 100644
--- a/src/map.h
+++ b/src/map.h
@@ -603,15 +603,18 @@ public:
m_loaded_blocks.clear();
}
- virtual void emerge(VoxelArea a);
+ virtual void emerge(VoxelArea a, s32 caller_id=-1);
void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
private:
Map *m_map;
- // bool is dummy value
- // SUGG: How 'bout an another VoxelManipulator for storing the
- // information about which block is loaded?
+ /*
+ NOTE: This might be used or not
+ bool is dummy value
+ SUGG: How 'bout an another VoxelManipulator for storing the
+ information about which block is loaded?
+ */
core::map<v3s16, bool> m_loaded_blocks;
};
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index d2c323291..0f2eba856 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -111,7 +111,7 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p,
u8 alpha = 255;
- if(material == MATERIAL_WATER)
+ if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
{
alpha = 128;
}
@@ -173,13 +173,14 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
/*
Gets node material from any place relative to block.
- Returns MATERIAL_AIR if doesn't exist.
+ Returns MATERIAL_IGNORE if doesn't exist or should not be drawn.
*/
u8 MapBlock::getNodeMaterial(v3s16 p)
{
try{
MapNode n = getNodeParent(p);
- return n.d;
+
+ return content_cube_material(n.d);
}
catch(InvalidPositionException &e)
{
@@ -470,46 +471,6 @@ void MapBlock::updateMesh()
collector.fillMesh(mesh_new);
-#if 0
- scene::IMeshBuffer *buf = NULL;
-
- core::list<FastFace*>::Iterator i = fastfaces_new->begin();
-
- // MATERIAL_AIR shouldn't be used by any face
- u8 material_in_use = MATERIAL_AIR;
-
- for(; i != fastfaces_new->end(); i++)
- {
- FastFace *f = *i;
-
- if(f->material != material_in_use || buf == NULL)
- {
- // Try to get a meshbuffer associated with the material
- buf = mesh_new->getMeshBuffer(g_materials[f->material]);
- // If not found, create one
- if(buf == NULL)
- {
- // This is a "Standard MeshBuffer",
- // it's a typedeffed CMeshBuffer<video::S3DVertex>
- buf = new scene::SMeshBuffer();
- // Set material
- ((scene::SMeshBuffer*)buf)->Material = g_materials[f->material];
- // Use VBO
- //buf->setHardwareMappingHint(scene::EHM_STATIC);
- // Add to mesh
- mesh_new->addMeshBuffer(buf);
- // Mesh grabbed it
- buf->drop();
- }
- material_in_use = f->material;
- }
-
- u16 new_indices[] = {0,1,2,2,3,0};
-
- //buf->append(f->vertices, 4, indices, 6);
- }
-#endif
-
// Use VBO for mesh (this just would set this for ever buffer)
//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
@@ -517,8 +478,11 @@ void MapBlock::updateMesh()
<<"and uses "<<mesh_new->getMeshBufferCount()
<<" materials (meshbuffers)"<<std::endl;*/
}
+
+ /*
+ Clear temporary FastFaces
+ */
- // TODO: Get rid of the FastFace stage
core::list<FastFace*>::Iterator i;
i = fastfaces_new->begin();
for(; i != fastfaces_new->end(); i++)
@@ -529,6 +493,18 @@ void MapBlock::updateMesh()
delete fastfaces_new;
/*
+ Add special graphics:
+ - torches
+ */
+
+ for(s16 z=0; z<MAP_BLOCKSIZE; z++)
+ for(s16 y=0; y<MAP_BLOCKSIZE; y++)
+ for(s16 x=0; x<MAP_BLOCKSIZE; x++)
+ {
+ v3s16 p(x,y,z);
+ }
+
+ /*
Replace the mesh
*/
diff --git a/src/mapnode.h b/src/mapnode.h
index 7502c42d7..0d65f30a4 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -56,6 +56,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
GRAVEL
- Dynamics of gravel: if there is a drop of more than two
blocks on any side, it will drop in there. Is this doable?
+
+ TODO: These should be named to "content" or something like that
*/
enum Material
@@ -77,6 +79,8 @@ enum Material
MATERIAL_MESE,
MATERIAL_MUD,
+
+ MATERIAL_OCEAN,
// This is set to the number of the actual values in this enum
USEFUL_MATERIAL_COUNT
@@ -88,7 +92,7 @@ enum Material
*/
inline bool light_propagates_material(u8 m)
{
- return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER);
+ return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
}
/*
@@ -110,7 +114,7 @@ inline u8 material_solidness(u8 m)
{
if(m == MATERIAL_AIR)
return 0;
- if(m == MATERIAL_WATER)
+ if(m == MATERIAL_WATER || m == MATERIAL_OCEAN)
return 1;
return 2;
}
@@ -118,29 +122,54 @@ inline u8 material_solidness(u8 m)
// Objects collide with walkable materials
inline bool material_walkable(u8 m)
{
- return (m != MATERIAL_AIR && m != MATERIAL_WATER);
+ return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN && m != MATERIAL_LIGHT);
}
// A liquid resists fast movement
inline bool material_liquid(u8 m)
{
- return (m == MATERIAL_WATER);
+ return (m == MATERIAL_WATER || m == MATERIAL_OCEAN);
}
// Pointable materials can be pointed to in the map
inline bool material_pointable(u8 m)
{
- return (m != MATERIAL_AIR && m != MATERIAL_WATER);
+ return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
}
inline bool material_diggable(u8 m)
{
- return (m != MATERIAL_AIR && m != MATERIAL_WATER);
+ return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
}
inline bool material_buildable_to(u8 m)
{
- return (m == MATERIAL_AIR || m == MATERIAL_WATER);
+ return (m == MATERIAL_AIR || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
+}
+
+/*
+ As of now, input is a "material" and the output is a "material"
+*/
+inline u8 content_cube_material(u8 c)
+{
+ if(c == MATERIAL_IGNORE || c == MATERIAL_LIGHT)
+ return MATERIAL_AIR;
+ return c;
+}
+
+/*
+ Returns true for materials that form the base ground that
+ follows the main heightmap
+*/
+inline bool is_ground_material(u8 m)
+{
+ return(
+ m == MATERIAL_STONE ||
+ m == MATERIAL_GRASS ||
+ m == MATERIAL_GRASS_FOOTSTEPS ||
+ m == MATERIAL_MESE ||
+ m == MATERIAL_MUD
+ );
}
/*
@@ -168,21 +197,6 @@ inline u8 face_materials(u8 m1, u8 m2)
return 2;
}
-/*
- Returns true for materials that form the base ground that
- follows the main heightmap
-*/
-inline bool is_ground_material(u8 m)
-{
- return(
- m == MATERIAL_STONE ||
- m == MATERIAL_GRASS ||
- m == MATERIAL_GRASS_FOOTSTEPS ||
- m == MATERIAL_MESE ||
- m == MATERIAL_MUD
- );
-}
-
struct MapNode
{
//TODO: block type to differ from material
@@ -214,7 +228,9 @@ struct MapNode
bool operator==(const MapNode &other)
{
- return (d == other.d && param == other.param);
+ return (d == other.d
+ && param == other.param
+ && pressure == other.pressure);
}
bool light_propagates()
diff --git a/src/server.cpp b/src/server.cpp
index 8bcfe5216..e343d5947 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -196,6 +196,28 @@ void * EmergeThread::Thread()
{
MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block);
+
+ /*
+ Update water pressure.
+ This also adds suitable nodes to active_nodes.
+ */
+
+ MapVoxelManipulator v(&map);
+
+ VoxelArea area(block->getPosRelative(),
+ block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
+
+ try
+ {
+ v.updateAreaWaterPressure(area, m_server->m_flow_active_nodes);
+ }
+ catch(ProcessingLimitException &e)
+ {
+ dstream<<"Processing limit reached (1)"<<std::endl;
+ }
+
+ v.blitBack(modified_blocks);
+
}
/*dstream<<"lighting "<<lighting_invalidated_blocks.size()
@@ -244,12 +266,6 @@ void * EmergeThread::Thread()
// Remove block from sent history
client->SetBlocksNotSent(modified_blocks);
}
-
- /*if(q->peer_ids.find(client->peer_id) != NULL)
- {
- // Decrement emerge queue count of client
- client->BlockEmerged();
- }*/
}
}
@@ -348,14 +364,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
//bool has_incomplete_blocks = false;
- /*
- TODO: Get this from somewhere
- */
- //s16 d_max = 7;
- s16 d_max = 8;
-
- //TODO: Get this from somewhere (probably a bigger value)
- s16 d_max_gen = 5;
+ s16 d_max = g_settings.getS16("max_block_send_distance");
+ s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
//dstream<<"Starting from "<<d_start<<std::endl;
@@ -998,7 +1008,7 @@ void Server::AsyncRunStep()
{
static float counter = 0.0;
counter += dtime;
- if(counter >= 1.0)
+ if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
{
counter = 0.0;
@@ -1011,16 +1021,7 @@ void Server::AsyncRunStep()
MapVoxelManipulator v(&m_env.getMap());
- /*try{
- v.flowWater(m_flow_active_nodes, 0, false, 20);
- //v.flowWater(p_under, 0, true, 100);
- }
- catch(ProcessingLimitException &e)
- {
- dstream<<"Processing limit reached"<<std::endl;
- }*/
-
- v.flowWater(m_flow_active_nodes, 0, false, 20);
+ v.flowWater(m_flow_active_nodes, 0, false, 50);
v.blitBack(modified_blocks);
@@ -1059,7 +1060,7 @@ void Server::AsyncRunStep()
}
}
- }
+ } // interval counter
}
// Periodically print some info
@@ -1547,7 +1548,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
catch(ProcessingLimitException &e)
{
- dstream<<"Processing limit reached"<<std::endl;
+ dstream<<"Processing limit reached (1)"<<std::endl;
}
v.blitBack(modified_blocks);
@@ -1624,6 +1625,28 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
core::map<v3s16, MapBlock*> modified_blocks;
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
+
+ /*
+ Update water
+ */
+
+ // Update water pressure around modification
+ // This also adds it to m_flow_active_nodes if appropriate
+
+ MapVoxelManipulator v(&m_env.getMap());
+
+ VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1));
+
+ try
+ {
+ v.updateAreaWaterPressure(area, m_flow_active_nodes);
+ }
+ catch(ProcessingLimitException &e)
+ {
+ dstream<<"Processing limit reached (1)"<<std::endl;
+ }
+
+ v.blitBack(modified_blocks);
}
/*
Handle block object items
@@ -2019,6 +2042,10 @@ void Server::peerAdded(con::Peer *peer)
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++)
{
+ // Skip some materials
+ if(i == MATERIAL_OCEAN)
+ continue;
+
InventoryItem *item = new MaterialItem(i, 1);
player->inventory.addItem(item);
}
diff --git a/src/test.cpp b/src/test.cpp
index ebefb8e32..829aec8c1 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -264,11 +264,13 @@ struct TestVoxelManipulator
s16 highest_y = -32768;
assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == -1);
assert(highest_y == 3);
+ /*assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == 3);
+ //assert(highest_y == 3);*/
active_nodes.clear();
active_nodes[v3s16(9,1,0)] = 1;
//v.flowWater(active_nodes, 0, false);
- v.flowWater(active_nodes, 0, true);
+ v.flowWater(active_nodes, 0, true, 1000);
dstream<<"Final result of flowWater:"<<std::endl;
v.print(dstream, VOXELPRINT_WATERPRESSURE);
diff --git a/src/voxel.cpp b/src/voxel.cpp
index b85ba8666..cdd41a14f 100644
--- a/src/voxel.cpp
+++ b/src/voxel.cpp
@@ -335,23 +335,26 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
if(p.Y > highest_y)
highest_y = p.Y;
- recur_count++;
- if(recur_count > 30)
+ /*if(recur_count > 1000)
throw ProcessingLimitException
- ("getWaterPressure recur_count limit reached");
+ ("getWaterPressure recur_count limit reached");*/
+
+ if(recur_count > 10000)
+ return -1;
+
+ recur_count++;
v3s16 dirs[6] = {
v3s16(0,1,0), // top
- v3s16(-1,0,0), // left
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
v3s16(0,0,1), // back
+ v3s16(0,0,-1), // front
+ v3s16(1,0,0), // right
+ v3s16(-1,0,0), // left
v3s16(0,-1,0), // bottom
};
// Load neighboring nodes
- // TODO: A bigger area would be better
- emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
+ emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
s32 i;
for(i=0; i<6; i++)
@@ -367,14 +370,14 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
continue;
int pr;
-
- // If at surface
- /*if(n.pressure == 1)
+
+ // If at ocean surface
+ if(n.pressure == 1 && n.d == MATERIAL_OCEAN)
{
pr = 1;
}
// Otherwise recurse more
- else*/
+ else
{
pr = getWaterPressure(p2, highest_y, recur_count);
if(pr == -1)
@@ -410,10 +413,21 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
core::map<v3s16, u8> &active_nodes,
int recur_count)
{
+ //if(recur_count > 10000)
+ /*throw ProcessingLimitException
+ ("spreadWaterPressure recur_count limit reached");*/
+ if(recur_count > 10)
+ return;
recur_count++;
- if(recur_count > 10000)
- throw ProcessingLimitException
- ("spreadWaterPressure recur_count limit reached");
+
+ /*dstream<<"spreadWaterPressure: p=("
+ <<p.X<<","<<p.Y<<","<<p.Z<<")"
+ <<", oldpr="<<(int)m_data[m_area.index(p)].pressure
+ <<", pr="<<pr
+ <<", recur_count="<<recur_count
+ <<", request_area=";
+ request_area.print(dstream);
+ dstream<<std::endl;*/
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
m_data[m_area.index(p)].pressure = pr;
@@ -428,7 +442,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
};
// Load neighboring nodes
- emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
+ emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
s32 i;
for(i=0; i<6; i++)
@@ -455,6 +469,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
// If block is at top
if(i == 0)
{
+ //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
if(pr >= 3)
pressure_causes_flow = true;
}
@@ -466,6 +481,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
// If block is at side
else
{
+ //if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
if(pr >= 2)
pressure_causes_flow = true;
}
@@ -497,7 +513,10 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
}
// Ignore if correct pressure is already set and is not on
- // request_area
+ // request_area.
+ // Thus, request_area can be used for updating as much
+ // pressure info in some area as possible to possibly
+ // make some calls to getWaterPressure unnecessary.
if(n.pressure == pr2 && request_area.contains(p2) == false)
continue;
@@ -512,7 +531,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
TimeTaker timer("updateAreaWaterPressure", g_device,
&updateareawaterpressure_time);
- emerge(a);
+ emerge(a, 3);
bool checked2_clear = false;
@@ -596,20 +615,21 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
bool VoxelManipulator::flowWater(v3s16 removed_pos,
core::map<v3s16, u8> &active_nodes,
int recursion_depth, bool debugprint,
- int *counter, int counterlimit)
+ u32 stoptime)
{
v3s16 dirs[6] = {
v3s16(0,1,0), // top
- v3s16(-1,0,0), // left
- v3s16(1,0,0), // right
v3s16(0,0,-1), // front
v3s16(0,0,1), // back
+ v3s16(-1,0,0), // left
+ v3s16(1,0,0), // right
v3s16(0,-1,0), // bottom
};
recursion_depth++;
v3s16 p;
+ bool from_ocean = false;
// Randomize horizontal order
static s32 cs = 0;
@@ -625,7 +645,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
// Load neighboring nodes
- emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
+ emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
// Ignore incorrect removed_pos
{
@@ -660,11 +680,13 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
// If block is at bottom, select it if it has enough pressure
if(i == 5)
{
+ //if(n.pressure >= PRESERVE_WATER_VOLUME ? 3 : 2)
if(n.pressure >= 3)
break;
continue;
}
// Else block is at some side. Select it if it has enough pressure
+ //if(n.pressure >= PRESERVE_WATER_VOLUME ? 2 : 1)
if(n.pressure >= 2)
{
break;
@@ -675,22 +697,47 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
if(i==6)
return false;
- // Switch nodes at p and removed_pos
+ /*
+ Move water and bubble
+ */
+
u8 m = m_data[m_area.index(p)].d;
u8 f = m_flags[m_area.index(p)];
- m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
- m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
+
+ if(m == MATERIAL_OCEAN)
+ from_ocean = true;
+
+ // Move air bubble if not taking water from ocean
+ if(from_ocean == false)
+ {
+ m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
+ m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
+ }
+
m_data[m_area.index(removed_pos)].d = m;
m_flags[m_area.index(removed_pos)] = f;
// Mark removed_pos checked
m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
+
// If block was dropped from surface, increase pressure
if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
{
m_data[m_area.index(removed_pos)].pressure = 2;
}
+ /*
+ NOTE: This does not work as-is
+ if(m == MATERIAL_OCEAN)
+ {
+ // If block was raised to surface, increase pressure of
+ // source node
+ if(i == 5 && m_data[m_area.index(p)].pressure == 1)
+ {
+ m_data[m_area.index(p)].pressure = 2;
+ }
+ }*/
+
/*if(debugprint)
{
dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
@@ -720,12 +767,30 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
}
}//timer1
-
- // Flow water to the newly created empty position
- flowWater(p, active_nodes, recursion_depth,
- debugprint, counter, counterlimit);
+
+ //if(PRESERVE_WATER_VOLUME)
+ if(from_ocean == false)
+ {
+ // Flow water to the newly created empty position
+ /*flowWater(p, active_nodes, recursion_depth,
+ debugprint, counter, counterlimit);*/
+ flowWater(p, active_nodes, recursion_depth,
+ debugprint, stoptime);
+ }
+
+ if(stoptime != 0 && g_device != NULL)
+ {
+ u32 timenow = g_device->getTimer()->getRealTime();
+ if(timenow >= stoptime ||
+ (stoptime < 0x80000000 && timenow > 0x80000000))
+ {
+ dstream<<"flowWater: stoptime reached"<<std::endl;
+ throw ProcessingLimitException("flowWater stoptime reached");
+ }
+ }
find_again:
+
// Try flowing water to empty positions around removed_pos.
// They are checked in reverse order compared to the previous loop.
for(s32 i=5; i>=0; i--)
@@ -745,7 +810,9 @@ find_again:
// Flow water to node
bool moved =
flowWater(p, active_nodes, recursion_depth,
- debugprint, counter, counterlimit);
+ debugprint, stoptime);
+ /*flowWater(p, active_nodes, recursion_depth,
+ debugprint, counter, counterlimit);*/
if(moved)
{
@@ -754,27 +821,13 @@ find_again:
}
}
- if(counter != NULL)
- {
- (*counter)++;
- if((*counter) % 10 == 0)
- dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
- <<std::endl;
-
- if(counterlimit != -1 && (*counter) > counterlimit)
- {
- dstream<<"Counter limit reached; returning"<<std::endl;
- throw ProcessingLimitException("flowWater counterlimit reached");
- }
- }
-
return true;
}
void VoxelManipulator::flowWater(
core::map<v3s16, u8> &active_nodes,
int recursion_depth, bool debugprint,
- int counterlimit)
+ u32 timelimit)
{
addarea_time = 0;
emerge_time = 0;
@@ -783,25 +836,53 @@ void VoxelManipulator::flowWater(
updateareawaterpressure_time = 0;
flowwater_pre_time = 0;
+ if(active_nodes.size() == 0)
+ {
+ dstream<<"flowWater: no active nodes"<<std::endl;
+ return;
+ }
+
TimeTaker timer1("flowWater (active_nodes)", g_device);
dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
- int counter = 0;
+ //int counter = 0;
+
+ u32 stoptime = 0;
+ if(g_device != NULL)
+ {
+ stoptime = g_device->getTimer()->getRealTime() + timelimit;
+ }
+
+ // Count of handled active nodes
+ u32 handled_count = 0;
try
{
+ /*
+ Take random one at first
+
+ This is randomized only at the first time so that all
+ subsequent nodes will be taken at roughly the same position
+ */
+ s32 k = 0;
+ if(active_nodes.size() != 0)
+ k = (s32)rand() % (s32)active_nodes.size();
+
// Flow water to active nodes
for(;;)
+ //for(s32 h=0; h<1; h++)
{
- // Clear check flags
- clearFlag(VOXELFLAG_CHECKED);
-
if(active_nodes.size() == 0)
break;
- dstream<<"Selecting a new active_node"<<std::endl;
+ handled_count++;
+
+ // Clear check flags
+ clearFlag(VOXELFLAG_CHECKED);
+
+ //dstream<<"Selecting a new active_node"<<std::endl;
#if 0
// Take first one
@@ -810,9 +891,7 @@ void VoxelManipulator::flowWater(
#endif
#if 1
- // Take random one
- s32 k = (s32)rand() % (s32)active_nodes.size();
- //s32 k = 0;
+
core::map<v3s16, u8>::Iterator
i = active_nodes.getIterator().getNode();
for(s32 j=0; j<k; j++)
@@ -820,12 +899,17 @@ void VoxelManipulator::flowWater(
i++;
}
core::map<v3s16, u8>::Node *n = i.getNode();
+
+ // Decrement index if less than 0.
+ // This keeps us in existing indices always.
+ if(k > 0)
+ k--;
#endif
v3s16 p = n->getKey();
active_nodes.remove(p);
flowWater(p, active_nodes, recursion_depth,
- debugprint, &counter, counterlimit);
+ debugprint, stoptime);
}
}
@@ -836,11 +920,14 @@ void VoxelManipulator::flowWater(
v3s16 e = m_area.getExtent();
s32 v = m_area.getVolume();
- dstream<<"flowWater (active): moved "<<counter<<" nodes, "
+ //dstream<<"flowWater (active): moved "<<counter<<" nodes, "
+ dstream<<"flowWater (active): "
<<"area ended up as "
<<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
+ <<", handled a_node count: "<<handled_count
+ <<", active_nodes.size() = "<<active_nodes.size()
<<std::endl;
-
+
dstream<<"addarea_time: "<<addarea_time
<<", emerge_time: "<<emerge_time
<<", emerge_load_time: "<<emerge_load_time
diff --git a/src/voxel.h b/src/voxel.h
index 74c0a00e5..411cf4376 100644
--- a/src/voxel.h
+++ b/src/voxel.h
@@ -428,8 +428,8 @@ public:
bool flowWater(v3s16 removed_pos,
core::map<v3s16, u8> &active_nodes,
int recursion_depth=0,
- bool debugprint=false, int *counter=NULL,
- int counterlimit=-1
+ bool debugprint=false,
+ u32 stoptime=0
);
/*
@@ -446,7 +446,7 @@ public:
void flowWater(core::map<v3s16, u8> &active_nodes,
int recursion_depth=0,
bool debugprint=false,
- int counterlimit=-1
+ u32 timelimit=50
);
/*
@@ -460,7 +460,7 @@ public:
If not found from source, add with VOXELFLAG_INEXISTENT
*/
- virtual void emerge(VoxelArea a)
+ virtual void emerge(VoxelArea a, s32 caller_id=-1)
{
//dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
addArea(a);