#max_simultaneous_block_sends_per_client = 1
#max_simultaneous_block_sends_server_total = 4
+#max_block_send_distance = 8
+#max_block_generate_distance = 5
+
TODO: Transfer sign texts as metadata of block and not as data of\r
object\r
\r
-Doing now:\r
-======================================================================\r
+SUGG: Implement a "Fast check queue" (a queue with a map for checking\r
+ if something is already in it)\r
+ - TODO: Use it in active block queue in water flowing\r
\r
-Water dynamics pseudo-code (block = MapNode):\r
-SUGG: Create separate flag table in VoxelManipulator to allow fast\r
-clearing of "modified" flags\r
-\r
-neighborCausedPressure(pos):\r
- pressure = 0\r
- dirs = {down, left, right, back, front, up}\r
- for d in dirs:\r
- pos2 = pos + d\r
- p = block_at(pos2).pressure\r
- if d.Y == 1 and p > min:\r
- p -= 1\r
- if d.Y == -1 and p < max:\r
- p += 1\r
- if p > pressure:\r
- pressure = p\r
- return pressure\r
-\r
-# This should somehow update all changed pressure values\r
-# in an unknown body of water\r
-updateWaterPressure(pos):\r
- TODO\r
-\r
-FIXME: This goes in an indefinite loop when there is an underwater\r
-chamber like this:\r
-\r
-#111######\r
-#222##22##\r
-#33333333x<- block removed from here\r
-##########\r
-\r
-#111######\r
-#222##22##\r
-#3333333x1\r
-##########\r
-\r
-#111######\r
-#222##22##\r
-#333333x11\r
-##########\r
-\r
-#111######\r
-#222##2x##\r
-#333333333\r
-##########\r
-\r
-#111######\r
-#222##x2##\r
-#333333333\r
-##########\r
-\r
-Now, consider moving to the last block not allowed.\r
-\r
-Consider it a 3D case with a depth of 2. We're now at this situation.\r
-Note the additional blocking ## in the second depth plane.\r
-\r
-z=1 z=2\r
-#111###### #111######\r
-#222##x2## #222##22##\r
-#333333333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#222##22## #222##x2##\r
-#333333333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#222##22## #222##2x##\r
-#333333333 #33333##33 \r
-########## ##########\r
-\r
-Now there is nowhere to go, without going to an already visited block,\r
-but the pressure calculated in here from neighboring blocks is >= 2,\r
-so it is not the final ending.\r
-\r
-We will back up to a state where there is somewhere to go to.\r
-It is this state:\r
-\r
-#111###### #111######\r
-#222##22## #222##22##\r
-#333333x33 #33333##33\r
-########## ##########\r
-\r
-Then just go on, avoiding already visited blocks:\r
-\r
-#111###### #111######\r
-#222##22## #222##22##\r
-#33333x333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#222##22## #222##22##\r
-#3333x3333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#222##22## #222##22##\r
-#333x33333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#222##22## #222##22##\r
-#33x333333 #33333##33\r
-########## ##########\r
-\r
-#111###### #111######\r
-#22x##22## #222##22##\r
-#333333333 #33333##33\r
-########## ##########\r
-\r
-#11x###### #111######\r
-#222##22## #222##22##\r
-#333333333 #33333##33\r
-########## ##########\r
-\r
-"Blob". the air bubble finally got out of the water.\r
-Then return recursively to a state where there is air next to water,\r
-clear the visit flags and feed the neighbor of the water recursively\r
-to the algorithm.\r
-\r
-#11 ###### #111######\r
-#222##22## #222##22##\r
-#333333333x #33333##33\r
-########## ##########\r
-\r
-#11 ###### #111######\r
-#222##22## #222##22##\r
-#33333333x3 #33333##33\r
-########## ##########\r
-\r
-...and so on.\r
-\r
-\r
-# removed_pos: a position that has been changed from something to air\r
-flowWater(removed_pos):\r
- dirs = {top, left, right, back, front, bottom}\r
- selected_dir = None\r
- for d in dirs:\r
- b2 = removed_pos + d\r
-\r
- # Ignore positions that don't have water\r
- if block_at(b2) != water:\r
- continue\r
-\r
- # Ignore positions that have already been checked\r
- if block_at(b2).checked:\r
- continue\r
-\r
- # If block is at top, select it always.\r
- if d.Y == 1:\r
- selected_dir = d\r
- break\r
-\r
- # If block is at bottom, select it if it has enough pressure.\r
- # >= 3 needed for stability (and sanity)\r
- if d.Y == -1:\r
- if block_at(b2).pressure >= 3:\r
- selected_dir = d\r
- break\r
- continue\r
- \r
- # Else block is at some side. select it if it has enough pressure.\r
- if block_at(b2).pressure >= 2:\r
- selected_dir = d\r
- break\r
- \r
- # If there is nothing to do anymore, return.\r
- if selected_dir == None\r
- return\r
- \r
- b2 = removed_pos + selected_dir\r
- \r
- # Move block\r
- set_block(removed_pos, block_at(b2))\r
- set_block(b2, air_block)\r
- \r
- # Update pressure\r
- updateWaterPressure(removed_pos)\r
- \r
- # Flow water to the newly created empty position\r
- flowWater(b2)\r
+TODO: Proper looking torches.\r
+ - Signs could be done in the same way?\r
\r
- # Check empty positions around and try flowing water to them\r
- for d in dirs:\r
- b3 = removed_pos + d\r
- # Ignore positions that are not air\r
- if block_at(b3) is not air:\r
- continue\r
- flowWater(b3)\r
+Doing now:\r
+======================================================================\r
\r
+TODO: A system for showing some nodes in some other way than cubes\r
+ - Needed for torches\r
+ - Also for signs, stairs, etc\r
\r
======================================================================\r
\r
"../data/leaves.png",\r
"../data/grass_footsteps.png",\r
"../data/mese.png",\r
- "../data/mud.png"\r
+ "../data/mud.png",\r
+ "../data/water.png", // ocean\r
};\r
\r
video::SMaterial g_materials[MATERIALS_COUNT];\r
g_settings.set("name", "");\r
g_settings.set("random_input", "false");\r
g_settings.set("client_delete_unused_sectors_timeout", "1200");\r
+ g_settings.set("max_block_send_distance", "8");\r
+ g_settings.set("max_block_generate_distance", "5");\r
\r
// Server stuff\r
g_settings.set("creative_mode", "false");\r
g_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);\r
//g_materials[i].setFlag(video::EMF_ANISOTROPIC_FILTER, false);\r
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);\r
- if(i == MATERIAL_WATER)\r
- {\r
- g_materials[i].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
- //g_materials[i].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
- }\r
}\r
\r
+ g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
+ //g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
+ g_materials[MATERIAL_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
+\r
/*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));\r
g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));\r
g_mesh_materials[2].setTexture(0, driver->getTexture("../data/stone.png"));\r
// 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
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.
<<std::endl;
}
-void MapVoxelManipulator::emerge(VoxelArea a)
+#if 1
+void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
{
TimeTaker timer1("emerge", g_device, &emerge_time);
{
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())
//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.
void MapVoxelManipulator::blitBack
(core::map<v3s16, MapBlock*> & modified_blocks)
{
+ if(m_area.getExtent() == v3s16(0,0,0))
+ return;
+
TimeTaker timer1("blitBack", g_device);
/*
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;
};
u8 alpha = 255;
- if(material == MATERIAL_WATER)
+ if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
{
alpha = 128;
}
/*
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)
{
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);
<<"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++)
fastfaces_new->clear();
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
*/
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
MATERIAL_MESE,
MATERIAL_MUD,
+
+ MATERIAL_OCEAN,
// This is set to the number of the actual values in this enum
USEFUL_MATERIAL_COUNT
*/
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);
}
/*
{
if(m == MATERIAL_AIR)
return 0;
- if(m == MATERIAL_WATER)
+ if(m == MATERIAL_WATER || m == MATERIAL_OCEAN)
return 1;
return 2;
}
// 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
+ );
}
/*
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
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()
{
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()
// 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();
- }*/
}
}
//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;
{
static float counter = 0.0;
counter += dtime;
- if(counter >= 1.0)
+ if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
{
counter = 0.0;
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);
}
}
- }
+ } // interval counter
}
// Periodically print some info
}
catch(ProcessingLimitException &e)
{
- dstream<<"Processing limit reached"<<std::endl;
+ dstream<<"Processing limit reached (1)"<<std::endl;
}
v.blitBack(modified_blocks);
*/
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
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);
}
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);
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++)
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)
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;
};
// 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++)
// If block is at top
if(i == 0)
{
+ //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
if(pr >= 3)
pressure_causes_flow = true;
}
// If block is at side
else
{
+ //if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
if(pr >= 2)
pressure_causes_flow = true;
}
}
// 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;
TimeTaker timer("updateAreaWaterPressure", g_device,
&updateareawaterpressure_time);
- emerge(a);
+ emerge(a, 3);
bool checked2_clear = false;
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;
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
{
// 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;
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;
}
}//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--)
// 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)
{
}
}
- 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;
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
#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++)
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);
}
}
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
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
);
/*
void flowWater(core::map<v3s16, u8> &active_nodes,
int recursion_depth=0,
bool debugprint=false,
- int counterlimit=-1
+ u32 timelimit=50
);
/*
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);