From 6e196c2ce4285c0aea2a5c714e842d90c1b84b43 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 1 Feb 2011 03:06:02 +0200 Subject: partly working chunk-based map generator (doesn't save properly, spawn is pretty random) --- src/map.cpp | 1321 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 1203 insertions(+), 118 deletions(-) (limited to 'src/map.cpp') diff --git a/src/map.cpp b/src/map.cpp index cc1a6d638..63fccc432 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -133,6 +133,18 @@ MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d) } } +/*MapBlock * Map::getBlockCreate(v3s16 p3d) +{ + v2s16 p2d(p3d.X, p3d.Z); + MapSector * sector = getSectorCreate(p2d); + assert(sector); + MapBlock *block = sector->getBlockNoCreate(p3d.Y); + if(block) + return block; + block = sector->createBlankBlock(p3d.Y); + return block; +}*/ + f32 Map::getGroundHeight(v2s16 p, bool generate) { try{ @@ -1724,7 +1736,8 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): //m_chunksize = 64; //m_chunksize = 16; //m_chunksize = 8; - m_chunksize = 2; + m_chunksize = 4; + //m_chunksize = 2; /* Experimental and debug stuff @@ -1739,6 +1752,7 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): PointAttributeList *list_plants_amount = m_padb.getList("plants_amount"); PointAttributeList *list_caves_amount = m_padb.getList("caves_amount"); +#if 0 /* NOTE: BEWARE: Too big amount of these will make map generation slow. Especially those that are read by every block emerge. @@ -1749,13 +1763,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): 15000 points: 40ms */ - for(u32 i=0; i<5000; i++) + for(u32 i=0; i<500; i++) { /*u32 lim = MAP_GENERATION_LIMIT; if(i < 400) lim = 2000;*/ - u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000; + u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500; v3s16 p( -lim + myrand()%(lim*2), @@ -1788,13 +1802,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): list_plants_amount->addPoint(p, Attribute(plants_amount)); } - for(u32 i=0; i<1000; i++) + for(u32 i=0; i<500; i++) { /*u32 lim = MAP_GENERATION_LIMIT; if(i < 400) lim = 2000;*/ - u32 lim = 500 + MAP_GENERATION_LIMIT * i / 1000; + u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500; v3s16 p( -lim + myrand()%(lim*2), @@ -1819,13 +1833,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): list_caves_amount->addPoint(p, Attribute(caves_amount)); } - for(u32 i=0; i<5000; i++) + for(u32 i=0; i<500; i++) { /*u32 lim = MAP_GENERATION_LIMIT; if(i < 400) lim = 2000;*/ - u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000; + u32 lim = 500 + MAP_GENERATION_LIMIT * i / 500; v3s16 p( -lim + (myrand()%(lim*2)), @@ -1896,10 +1910,12 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp): list_randmax->addPoint(p, Attribute(randmax)); list_randfactor->addPoint(p, Attribute(randfactor)); } - - /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5)); - list_randmax->addPoint(v3s16(0,0,0), Attribute(20)); - list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/ +#endif + + // Add only one entry + list_baseheight->addPoint(v3s16(0,0,0), Attribute(0)); + list_randmax->addPoint(v3s16(0,0,0), Attribute(30)); + list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.45)); // Easy spawn point /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0)); @@ -2010,6 +2026,7 @@ ServerMap::~ServerMap() } } +#if 0 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos) { // Return if chunk already exists @@ -2054,58 +2071,998 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos) <<"("<getBlockNoCreateNoEx(y2)) + continue; + + generateBlock(p, NULL, sector, changed_blocks, + lighting_invalidated_blocks); + + generated_block_count++; + } + } + } + + dstream<<"generateChunkRaw generated "< lighting_modified_blocks; + updateLighting(lighting_invalidated_blocks, lighting_modified_blocks); + }*/ + + // Add chunk meta information + chunk = new MapChunk(); + m_chunks.insert(chunkpos, chunk); + return chunk; +} + +MapChunk* ServerMap::generateChunk(v2s16 chunkpos) +{ + /* + Generate chunk and neighbors + */ + for(s16 x=-1; x<=1; x++) + for(s16 y=-1; y<=1; y++) + { + generateChunkRaw(chunkpos + v2s16(x,y)); + } + + /* + Get chunk + */ + MapChunk *chunk = getChunk(chunkpos); + assert(chunk); + // Set non-volatile + chunk->setIsVolatile(false); + // Return it + return chunk; +} +#endif + +MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos) +{ + dstream<<"WARNING: No-op "<<__FUNCTION_NAME<<" called"<=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + if(content_walkable(n.d)) + break; + + vmanip.m_area.add_y(em, i, -1); + } + if(y >= y_nodes_min) + return y; + else + return y_nodes_min; +} + +void make_tree(VoxelManipulator &vmanip, v3s16 p0) +{ + MapNode treenode(CONTENT_TREE); + MapNode leavesnode(CONTENT_LEAVES); + + s16 trunk_h = myrand_range(2, 6); + v3s16 p1 = p0; + for(s16 ii=0; ii leaves_d(new u8[leaves_a.getVolume()]); + for(s32 i=0; isetLightingExpired(true); + // Lighting will be calculated + block->setLightingExpired(false); + + /* + TODO: Do this better. + Block gets sunlight if this is true. + + This should be set to true when the top side of a block + is completely exposed to the sky. + */ + block->setIsUnderground(y != y_blocks_max); + } + } + } + + /* + Now we have a big empty area. + + Make a ManualMapVoxelManipulator that contains this and the + neighboring chunks + */ + + ManualMapVoxelManipulator vmanip(this); + // Add the area we just generated + { + TimeTaker timer("generateChunk() initialEmerge"); + vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max); + } + + TimeTaker timer_generate("generateChunk() generate"); + + /* + Generate general ground level to full area + */ + + for(s16 x=0; xgetGroundHeight(sector_relpos); + if(h > GROUNDHEIGHT_VALID_MINVALUE) + surface_y_f = h; + else + dstream<<"WARNING: "<<__FUNCTION_NAME + <<": sector->getGroundHeight returned bad height"<=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + /*if(content_walkable(n.d) + && n.d != CONTENT_MUD + && n.d != CONTENT_GRASS) + break;*/ + if(n.d == CONTENT_STONE) + break; + + if(n.d == CONTENT_MUD || n.d == CONTENT_GRASS) + mud_amount++; + + vmanip.m_area.add_y(em, i, -1); + } + if(y >= y_nodes_min) + surface_y = y; + else + surface_y = y_nodes_min; + } + + + /* + Add stone on ground + */ + { + v3s16 em = vmanip.m_area.getExtent(); + s16 y_start = surface_y+1; + u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); + s16 y; + // Add stone + s16 count = 0; + for(y=y_start; y<=y_nodes_max; y++) + { + MapNode &n = vmanip.m_data[i]; + n.d = CONTENT_STONE; + count++; + if(count >= ob_size.Y) + break; + + vmanip.m_area.add_y(em, i, 1); + } + // Add mud + count = 0; + for(; y<=y_nodes_max; y++) + { + MapNode &n = vmanip.m_data[i]; + n.d = CONTENT_MUD; + count++; + if(count >= mud_amount) + break; + + vmanip.m_area.add_y(em, i, 1); + } + } + + } + } + + /* + Make dungeons + */ + for(u32 jj=0; jj<2; jj++) + { + s16 max_tunnel_diameter = 8; + + // Allowed route area size in nodes + v3s16 ar( + sectorpos_base_size*MAP_BLOCKSIZE, + h_blocks*MAP_BLOCKSIZE, + sectorpos_base_size*MAP_BLOCKSIZE + ); + + // Area starting point in nodes + v3s16 of( + sectorpos_base.X*MAP_BLOCKSIZE, + y_blocks_min*MAP_BLOCKSIZE, + sectorpos_base.Y*MAP_BLOCKSIZE + ); + + // Allow a bit more + //(this should be more than the maximum radius of the tunnel) + s16 more = max_spread_amount - max_tunnel_diameter/2 - 1; + ar += v3s16(1,0,1) * more * 2; + of -= v3s16(1,0,1) * more; + + // Randomize starting position + v3f orp( + (float)(myrand()%ar.X)+0.5, + (float)(myrand()%ar.Y)+0.5, + (float)(myrand()%ar.Z)+0.5 + ); + + MapNode airnode(CONTENT_AIR); + + /* + Generate some tunnel starting from orp + */ + + for(u16 j=0; j<10; j++) + { + /*v3f rp( + (float)(myrand()%ar.X)+0.5, + (float)(myrand()%ar.Y)+0.5, + (float)(myrand()%ar.Z)+0.5 + ); + v3f vec = rp - orp;*/ + + v3s16 maxlen(60, 10, 60); + v3f vec( + (float)(myrand()%(maxlen.X*2))-(float)maxlen.X, + (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y, + (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z + ); + v3f rp = orp + vec; + if(rp.X < 0) + rp.X = 0; + else if(rp.X >= ar.X) + rp.X = ar.X; + if(rp.Y < 0) + rp.Y = 0; + else if(rp.Y >= ar.Y) + rp.Y = ar.Y; + if(rp.Z < 0) + rp.Z = 0; + else if(rp.Z >= ar.Z) + rp.Z = ar.Z; + vec = rp - orp; + + // Randomize size + s16 min_d = 0; + s16 max_d = max_tunnel_diameter; + s16 rs = myrand_range(min_d, max_d); + + for(float f=0; f<1.0; f+=1.0/vec.getLength()) + { + v3f fp = orp + vec * f; + v3s16 cp(fp.X, fp.Y, fp.Z); + s16 d0 = -rs/2; + s16 d1 = d0 + rs - 1; + for(s16 z0=d0; z0<=d1; z0++) + { + s16 si = rs - abs(z0); + for(s16 x0=-si; x0<=si-1; x0++) + { + s16 si2 = rs - abs(x0); + for(s16 y0=-si2+1; y0<=si2-1; y0++) + { + s16 z = cp.Z + z0; + s16 y = cp.Y + y0; + s16 x = cp.X + x0; + v3s16 p(x,y,z); + /*if(isInArea(p, ar) == false) + continue;*/ + // Check only height + if(y < 0 || y >= ar.Y) + continue; + p += of; + + assert(vmanip.m_area.contains(p)); + + // Just set it to air, it will be changed to + // water afterwards + u32 i = vmanip.m_area.index(p); + vmanip.m_data[i] = airnode; + } + } + } + } + + orp = rp; + } + + } + + /* + Make ore veins + */ + for(u32 jj=0; jj<1000; jj++) + { + s16 max_vein_diameter = 3; + + // Allowed route area size in nodes + v3s16 ar( + sectorpos_base_size*MAP_BLOCKSIZE, + h_blocks*MAP_BLOCKSIZE, + sectorpos_base_size*MAP_BLOCKSIZE + ); + + // Area starting point in nodes + v3s16 of( + sectorpos_base.X*MAP_BLOCKSIZE, + y_blocks_min*MAP_BLOCKSIZE, + sectorpos_base.Y*MAP_BLOCKSIZE + ); + + // Allow a bit more + //(this should be more than the maximum radius of the tunnel) + s16 more = max_spread_amount - max_vein_diameter/2 - 1; + ar += v3s16(1,0,1) * more * 2; + of -= v3s16(1,0,1) * more; + + // Randomize starting position + v3f orp( + (float)(myrand()%ar.X)+0.5, + (float)(myrand()%ar.Y)+0.5, + (float)(myrand()%ar.Z)+0.5 + ); + + // Randomize mineral + u8 mineral = myrand_range(1, MINERAL_COUNT-1); + + /* + Generate some vein starting from orp + */ + + for(u16 j=0; j<2; j++) + { + /*v3f rp( + (float)(myrand()%ar.X)+0.5, + (float)(myrand()%ar.Y)+0.5, + (float)(myrand()%ar.Z)+0.5 + ); + v3f vec = rp - orp;*/ + + v3s16 maxlen(10, 10, 10); + v3f vec( + (float)(myrand()%(maxlen.X*2))-(float)maxlen.X, + (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y, + (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z + ); + v3f rp = orp + vec; + if(rp.X < 0) + rp.X = 0; + else if(rp.X >= ar.X) + rp.X = ar.X; + if(rp.Y < 0) + rp.Y = 0; + else if(rp.Y >= ar.Y) + rp.Y = ar.Y; + if(rp.Z < 0) + rp.Z = 0; + else if(rp.Z >= ar.Z) + rp.Z = ar.Z; + vec = rp - orp; + + // Randomize size + s16 min_d = 0; + s16 max_d = max_vein_diameter; + s16 rs = myrand_range(min_d, max_d); + + for(float f=0; f<1.0; f+=1.0/vec.getLength()) + { + v3f fp = orp + vec * f; + v3s16 cp(fp.X, fp.Y, fp.Z); + s16 d0 = -rs/2; + s16 d1 = d0 + rs - 1; + for(s16 z0=d0; z0<=d1; z0++) + { + s16 si = rs - abs(z0); + for(s16 x0=-si; x0<=si-1; x0++) + { + s16 si2 = rs - abs(x0); + for(s16 y0=-si2+1; y0<=si2-1; y0++) + { + // Don't put mineral to every place + if(myrand()%5 != 0) + continue; + + s16 z = cp.Z + z0; + s16 y = cp.Y + y0; + s16 x = cp.X + x0; + v3s16 p(x,y,z); + /*if(isInArea(p, ar) == false) + continue;*/ + // Check only height + if(y < 0 || y >= ar.Y) + continue; + p += of; + + assert(vmanip.m_area.contains(p)); + + // Just set it to air, it will be changed to + // water afterwards + u32 i = vmanip.m_area.index(p); + MapNode *n = &vmanip.m_data[i]; + if(n->d == CONTENT_STONE) + n->param = mineral; + } + } + } + } + + orp = rp; + } + + } + + /* + Add mud to the central chunk + */ + + for(s16 x=0; x= 3) + break; + + vmanip.m_area.add_y(em, i, 1); + } + } + + } + + /* + Flow mud away from steep edges + */ + + // Iterate a few times + for(s16 k=0; k<4; k++) + { + + for(s16 x=0-max_spread_amount+1; + x=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + //if(n.d != CONTENT_AIR) + if(content_walkable(n.d)) + break; + + vmanip.m_area.add_y(em, i, -1); + } + + // If not mud, do nothing to it + MapNode *n = &vmanip.m_data[i]; + if(n->d != CONTENT_MUD) + continue; + + v3s16 dirs4[4] = { + v3s16(0,0,1), // back + v3s16(1,0,0), // right + v3s16(0,0,-1), // front + v3s16(-1,0,0), // left + }; + + // Drop mud on side + + for(u32 di=0; di<4; di++) + { + v3s16 dirp = dirs4[di]; + u32 i2 = i; + // Check that side is air + vmanip.m_area.add_p(em, i2, dirp); + MapNode *n2 = &vmanip.m_data[i2]; + if(content_walkable(n2->d)) + continue; + // Check that under side is air + vmanip.m_area.add_y(em, i2, -1); + n2 = &vmanip.m_data[i2]; + if(content_walkable(n2->d)) + continue; + // Loop further down until not air + do{ + vmanip.m_area.add_y(em, i2, -1); + n2 = &vmanip.m_data[i2]; + }while(content_walkable(n2->d) == false); + // Loop one up so that we're in air + vmanip.m_area.add_y(em, i2, 1); + n2 = &vmanip.m_data[i2]; + + // Move mud to new place + *n2 = *n; + // Set old place to be air + *n = MapNode(CONTENT_AIR); + + #if 0 + // Switch mud and other and change mud source to air + //MapNode tempnode = *n2; + *n2 = *n; + //*n = tempnode; + // Force old mud position to be air + n->d = CONTENT_AIR; + #endif + + // Done + break; + } + } + + } + + /* + Add water to the central chunk (and a bit more) + */ + + for(s16 x=0-max_spread_amount; + x WATER_LEVEL) + continue; + + /* + Add water on ground + */ + { + v3s16 em = vmanip.m_area.getExtent(); + s16 y_start = WATER_LEVEL; + u8 light = LIGHT_MAX; + u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y)); + for(s16 y=y_start; y>=y_nodes_min; y--) + { + MapNode *n = &vmanip.m_data[i]; + + // Fill gaps inside water, too + if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE + && n->d != CONTENT_WATER) + break; + + n->d = CONTENT_WATERSOURCE; + n->setLight(LIGHTBANK_DAY, light); + + /* + Add to transforming liquid queue (in case it'd + start flowing) + */ + v3s16 p = v3s16(p2d.X, y, p2d.Y); + m_transforming_liquid.push_back(p); + + // Next one + vmanip.m_area.add_y(em, i, -1); + if(light > 0) + light--; + } + } + + } + + /* + Plant some trees + */ + { + u32 tree_max = 100; + + u32 count = myrand_range(0, tree_max); + for(u32 i=0; i=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + if(n.d != CONTENT_AIR + && n.d != CONTENT_LEAVES) + break; + vmanip.m_area.add_y(em, i, -1); + } + if(y >= y_nodes_min) + surface_y = y; + else + surface_y = y_nodes_min; + } + + u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y); + MapNode *n = &vmanip.m_data[i]; + if(n->d == CONTENT_MUD) + n->d = CONTENT_GRASS; + } + + /* + Handle lighting + */ + + core::map light_sources; + + /*for(s16 x=0; x=y_nodes_min; y--) + { + MapNode *n = &vmanip.m_data[i]; + + if(light_propagates_content(n->d) == false) + { + light = 0; + } + else if(light != LIGHT_SUN + || sunlight_propagates_content(n->d) == false) + { + if(light > 0) + light--; + } - /* - Generate main blocks of sector - */ - s16 d = 8; - for(s16 y2=-d/2; y2setLight(LIGHTBANK_DAY, light); + n->setLight(LIGHTBANK_NIGHT, 0); - // Check that the block doesn't exist already - if(sector->getBlockNoCreateNoEx(y2)) - continue; + if(light != 0) + { + // Insert light source + light_sources.insert(v3s16(p2d.X, y, p2d.Y), true); + } - generateBlock(p, NULL, sector, changed_blocks, - lighting_invalidated_blocks); - - generated_block_count++; + // Increment index by y + vmanip.m_area.add_y(em, i, -1); } } } - dstream<<"generateChunkRaw generated "< lighting_modified_blocks; - updateLighting(lighting_invalidated_blocks, lighting_modified_blocks); + TimeTaker timer("generateChunk() spreadLight"); + vmanip.spreadLight(LIGHTBANK_DAY, light_sources); } - // Add chunk meta information - chunk = new MapChunk(); - m_chunks.insert(chunkpos, chunk); - return chunk; -} + /* + Generation ended + */ + + timer_generate.stop(); -MapChunk* ServerMap::generateChunk(v2s16 chunkpos) -{ /* - Generate chunk and neighbors + Blit generated stuff to map + */ + core::map modified_blocks; + { + TimeTaker timer("generateChunk() blitBackAll"); + vmanip.blitBackAll(&modified_blocks); + } + /* + Update day/night difference cache of the MapBlocks + */ + { + for(core::map::Iterator i = modified_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + block->updateDayNightDiff(); + } + } + + + /* + Create chunks and set them volatile */ + for(s16 x=-1; x<=1; x++) for(s16 y=-1; y<=1; y++) { - generateChunkRaw(chunkpos + v2s16(x,y)); + v2s16 chunkpos0 = chunkpos + v2s16(x,y); + // Add chunk meta information + MapChunk *chunk = getChunk(chunkpos); + if(chunk == NULL) + { + chunk = new MapChunk(); + m_chunks.insert(chunkpos0, chunk); + } + chunk->setIsVolatile(true); } /* - Get chunk + Set central chunk non-volatile and return it */ MapChunk *chunk = getChunk(chunkpos); assert(chunk); @@ -2115,6 +3072,7 @@ MapChunk* ServerMap::generateChunk(v2s16 chunkpos) return chunk; } +#if 0 ServerMapSector * ServerMap::generateSector(v2s16 p2d) { DSTACK("%s: p2d=(%d,%d)", @@ -2131,7 +3089,7 @@ ServerMapSector * ServerMap::generateSector(v2s16 p2d) */ if(m_heightmap == NULL) { - throw InvalidPositionException("emergeSector(): no heightmap"); + throw InvalidPositionException("generateSector(): no heightmap"); } /* @@ -2141,7 +3099,7 @@ ServerMapSector * ServerMap::generateSector(v2s16 p2d) || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) - throw InvalidPositionException("emergeSector(): pos. over limit"); + throw InvalidPositionException("generateSector(): pos. over limit"); /* Generate sector and heightmaps @@ -2209,8 +3167,8 @@ ServerMapSector * ServerMap::generateSector(v2s16 p2d) #if 0 { - //dstream<<"emergeSector(): Reading point attribute lists"< MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + throw InvalidPositionException("createSector(): pos. over limit"); + + /* + Generate blank sector + */ + + // Number of heightmaps in sector in each direction + u16 hm_split = SECTOR_HEIGHTMAP_SPLIT; + + // Heightmap side width + s16 hm_d = MAP_BLOCKSIZE / hm_split; + + sector = new ServerMapSector(this, p2d, hm_split); + + // Sector position on map in nodes + v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; + + /*dstream<<"Generating sector ("<getGroundHeight(mhm_p+v2s16(0,0)*hm_split), + m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split), + m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split), + m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split), + };*/ + + // Loop through sub-heightmaps + for(s16 y=0; ygetGroundHeight(mhm_p+v2s16(0,0)), + m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)), + m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)), + m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)), + }; + + /*dstream<<"p_in_sector=("<setHeightmap(p_in_sector, hm); + + //hm->generateContinued(1.0, 0.5, corners); + hm->generateContinued(0.5, 0.5, corners); + + //hm->print(); + } + + // Add dummy objects + core::map *objects = new core::map; + sector->setObjects(objects); + + /* + Insert to container + */ + m_sectors.insert(p2d, sector); + + return sector; +} + +MapSector * ServerMap::emergeSector(v2s16 p2d) +{ + DSTACK("%s: p2d=(%d,%d)", + __FUNCTION_NAME, + p2d.X, p2d.Y); + /* Check chunk status */ @@ -2383,7 +3434,7 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) chunk_exists = true; /* - If chunk is not generated, generate chunk + If chunk is not fully generated, generate chunk */ if(chunk_exists == false) { @@ -2394,10 +3445,24 @@ MapSector * ServerMap::emergeSector(v2s16 p2d) /* Return sector if it exists now */ - sector = getSectorNoGenerateNoEx(p2d); + MapSector *sector = getSectorNoGenerateNoEx(p2d); if(sector != NULL) return sector; + /* + Try to load it from disk + */ + if(loadSectorFull(p2d) == true) + { + MapSector *sector = getSectorNoGenerateNoEx(p2d); + if(sector == NULL) + { + dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<getId() == MAPSECTOR_SERVER); + } + /*catch(InvalidPositionException &e) + { + dstream<<"createBlock: createSector() failed"<getBlockNoCreateNoEx(block_y); + if(block) + return block; + // Create blank + block = sector->createBlankBlock(block_y); + return block; +} + MapBlock * ServerMap::emergeBlock( v3s16 p, bool only_from_disk, @@ -3299,10 +4407,6 @@ MapBlock * ServerMap::emergeBlock( __FUNCTION_NAME, p.X, p.Y, p.Z, only_from_disk); - /*dstream<<"emergeBlock(): " - <<"("<getNode(a.MinEdge + p); - m_data[i] = n; - m_flags[i] = 0; - } - catch(InvalidPositionException &e) - { - m_flags[i] = VOXELFLAG_INEXISTENT; - } - } -} -#endif - /* SUGG: Add an option to only update eg. water and air nodes. @@ -4620,23 +5683,8 @@ ManualMapVoxelManipulator::~ManualMapVoxelManipulator() void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) { - // Just create the area to avoid segfaults + // Just create the area so that it can be pointed to VoxelManipulator::emerge(a, caller_id); - - /* - Just create the area to avoid segfaults - */ - /*addArea(a); - for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) - for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) - for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++) - { - s32 i = m_area.index(x,y,z); - // Don't touch nodes that have already been loaded - if(!(m_flags[i] & VOXELFLAG_NOT_LOADED)) - continue; - m_flags[i] = VOXELFLAG_INEXISTENT; - }*/ } void ManualMapVoxelManipulator::initialEmerge( @@ -4681,6 +5729,9 @@ void ManualMapVoxelManipulator::initialEmerge( if(block_data_inexistent) { + /* + Mark area inexistent + */ VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); // Fill with VOXELFLAG_INEXISTENT for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) @@ -4691,7 +5742,41 @@ void ManualMapVoxelManipulator::initialEmerge( } } - m_loaded_blocks.insert(p, true); + m_loaded_blocks.insert(p, !block_data_inexistent); + } +} + +void ManualMapVoxelManipulator::blitBackAll( + core::map * modified_blocks) +{ + if(m_area.getExtent() == v3s16(0,0,0)) + return; + + /* + Copy data of all blocks + */ + for(core::map::Iterator + i = m_loaded_blocks.getIterator(); + i.atEnd() == false; i++) + { + bool existed = i.getNode()->getValue(); + if(existed == false) + continue; + v3s16 p = i.getNode()->getKey(); + MapBlock *block = m_map->getBlockNoCreateNoEx(p); + if(block == NULL) + { + dstream<<"WARNING: "<<__FUNCTION_NAME + <<": got NULL block " + <<"("<copyFrom(*this); + + if(modified_blocks) + modified_blocks->insert(p, block); } } -- cgit v1.2.3