diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 215 | ||||
-rw-r--r-- | src/map.cpp | 81 | ||||
-rw-r--r-- | src/map.h | 11 | ||||
-rw-r--r-- | src/mapblock.cpp | 64 | ||||
-rw-r--r-- | src/mapnode.h | 62 | ||||
-rw-r--r-- | src/server.cpp | 81 | ||||
-rw-r--r-- | src/test.cpp | 4 | ||||
-rw-r--r-- | src/voxel.cpp | 199 | ||||
-rw-r--r-- | src/voxel.h | 8 |
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); /* @@ -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); |