From 47a593b5197393d8f8cdfe18b1aa46b8bc1f3fb6 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 12 Dec 2010 14:33:13 +0200 Subject: [PATCH] starting to separate "material" to "content" and "tile" --- minetest.conf.example | 3 + src/main.cpp | 215 ++++-------------------------------------- src/map.cpp | 81 +++++++++------- src/map.h | 11 ++- src/mapblock.cpp | 64 ++++--------- src/mapnode.h | 62 +++++++----- src/server.cpp | 81 ++++++++++------ src/test.cpp | 4 +- src/voxel.cpp | 199 +++++++++++++++++++++++++++----------- src/voxel.h | 8 +- 10 files changed, 340 insertions(+), 388 deletions(-) diff --git a/minetest.conf.example b/minetest.conf.example index e6c9832a5..1d2606ec2 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -53,3 +53,6 @@ #max_simultaneous_block_sends_per_client = 1 #max_simultaneous_block_sends_server_total = 4 +#max_block_send_distance = 8 +#max_block_generate_distance = 5 + 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 +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 + +TODO: Proper looking torches. + - Signs could be done in the same way? + 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) - +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; igetMeshBuffer(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() <getBlockNoCreate(p); if(block->isDummy()) @@ -3221,6 +3198,43 @@ void MapVoxelManipulator::emerge(VoxelArea a) //dstream<<"emerge done"<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 & 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 & 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 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::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 - 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 "<getMeshBufferCount() <<" materials (meshbuffers)"<::Iterator i; i = fastfaces_new->begin(); for(; i != fastfaces_new->end(); i++) @@ -528,6 +492,18 @@ void MapBlock::updateMesh() fastfaces_new->clear(); delete fastfaces_new; + /* + Add special graphics: + - torches + */ + + for(s16 z=0; zgetValue(); 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)"<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 "<= 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"< 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)"<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:"< 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 &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=(" + < &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:"<getTimer()->getRealTime(); + if(timenow >= stoptime || + (stoptime < 0x80000000 && timenow > 0x80000000)) + { + dstream<<"flowWater: stoptime reached"<=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" - < counterlimit) - { - dstream<<"Counter limit reached; returning"< &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"<::Iterator i = active_nodes.getIterator().getNode(); for(s32 j=0; j::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 "< &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 &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=("<