summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2011-04-02 20:55:22 +0300
committerPerttu Ahola <celeron55@gmail.com>2011-04-02 20:55:22 +0300
commitbc66bb2d409f13554bdcec7386766af82a343cad (patch)
tree37376d220e421db8d567c2624fe977355fe6f832
parent2990f5d90bd556684c07d60872a707e649bd71ee (diff)
downloadminetest-bc66bb2d409f13554bdcec7386766af82a343cad.tar.gz
minetest-bc66bb2d409f13554bdcec7386766af82a343cad.tar.bz2
minetest-bc66bb2d409f13554bdcec7386766af82a343cad.zip
Mapgen is better now. Not a lot, but a bit!
-rw-r--r--data/water.pngbin548 -> 512 bytes
-rw-r--r--src/main.cpp8
-rw-r--r--src/map.cpp1050
-rw-r--r--src/map.h106
-rw-r--r--src/mapblock.cpp4
-rw-r--r--src/mapblock.h29
-rw-r--r--src/mapchunk.h66
-rw-r--r--src/materials.cpp4
-rw-r--r--src/server.cpp17
9 files changed, 1074 insertions, 210 deletions
diff --git a/data/water.png b/data/water.png
index 20f74edfe..9657dbed7 100644
--- a/data/water.png
+++ b/data/water.png
Binary files differ
diff --git a/src/main.cpp b/src/main.cpp
index ec4060868..fb1b2d8fd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -194,7 +194,7 @@ TODO: Copy the text of the last picked sign to inventory in creative
TODO: Check what goes wrong with caching map to disk (Kray)
- Nothing?
-FIXME: Server went into some infinite PeerNotFoundException loop
+FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
* Fix the problem with the server constantly saving one or a few
blocks? List the first saved block, maybe it explains.
@@ -259,7 +259,7 @@ FEATURE: Erosion simulation at map generation time
- Simulate rock falling from cliffs when water has removed
enough solid rock from the bottom
-Mapgen v2:
+Mapgen v2 (not doing):
* only_from_disk might not work anymore - check and fix it.
* Make the generator to run in background and not blocking block
placement and transfer
@@ -280,7 +280,7 @@ Mapgen v4 (not doing):
* Make chunks to be tiled vertically too
* MAKE IT FASTER
-Mapgen v3:
+Mapgen v3 (not doing):
* Generate trees better
- Add a "trees_added" flag to sector, or something
* How 'bout making turbulence controlled so that for a given 2d position
@@ -292,7 +292,7 @@ Mapgen v3:
Mapgen v4:
* This will be the final way.
-* Generate blocks in the same way as chunks, by copying a voxelmanipulator
+* Generate blocks in the same way as chunks, by copying a VoxelManipulator
from the map that is one block larger in all directions.
Misc. stuff:
diff --git a/src/map.cpp b/src/map.cpp
index aabe84067..651bece4f 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1710,13 +1710,6 @@ ServerMap::ServerMap(std::string savedir):
Map(dout_server),
m_seed(0)
{
-
- //m_chunksize = 64;
- //m_chunksize = 16; // Too slow
- //m_chunksize = 8; // Takes a few seconds
- m_chunksize = 4; // Too small?
- //m_chunksize = 2;
-
// TODO: Save to and load from a file
m_seed = (((u64)(myrand()%0xffff)<<0)
+ ((u64)(myrand()%0xffff)<<16)
@@ -1751,12 +1744,9 @@ ServerMap::ServerMap(std::string savedir):
}
else
{
- // Load map metadata (seed, chunksize)
+ // Load map metadata (seed)
loadMapMeta();
- // Load chunk metadata
- loadChunkMeta();
-
/*// Load sector (0,0) and throw and exception on fail
if(loadSectorFull(v2s16(0,0)) == false)
throw LoadError("Failed to load sector (0,0)");*/
@@ -1819,16 +1809,6 @@ ServerMap::~ServerMap()
dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
<<", exception: "<<e.what()<<std::endl;
}
-
- /*
- Free all MapChunks
- */
- core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapChunk *chunk = i.getNode()->getValue();
- delete chunk;
- }
}
/*
@@ -1883,6 +1863,7 @@ void make_tree(VoxelManipulator &vmanip, v3s16 p0)
{
MapNode treenode(CONTENT_TREE);
MapNode leavesnode(CONTENT_LEAVES);
+ leavesnode.setLight(LIGHTBANK_DAY, LIGHT_MAX-1);
vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2)));
@@ -1962,18 +1943,18 @@ double tree_amount_2d(u64 seed, v2s16 p)
double noise = noise2d_perlin(
0.5+(float)p.X/250, 0.5+(float)p.Y/250,
seed+2, 5, 0.7);
- double zeroval = -0.4;
+ double zeroval = -0.5;
if(noise < zeroval)
return 0;
else
- return 0.025 * (noise-zeroval) / (1.0-zeroval);
+ return 0.03 * (noise-zeroval) / (1.0-zeroval);
}
#define AVERAGE_MUD_AMOUNT 4.0
double get_mud_amount(u64 seed, v2f p)
{
- return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
+ return ((float)AVERAGE_MUD_AMOUNT + 2.5 * noise2d_perlin(
0.5+p.X/200, 0.5+p.Y/200,
seed+1, 5, 0.65));
}
@@ -2121,8 +2102,8 @@ double base_rock_level_2d(u64 seed, v2f p)
{
// Mountains
double m4 = 1.0 - 3.0 * noise2d_perlin_abs(
- 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
- (seed>>32)+65012102, 9, 0.57);
+ 0.324+(float)p.X/1000., 0.423+(float)p.Y/1000.,
+ (seed>>32)+65012102, 8, 0.57);
m4 *= 120;
if(m4 > h)
h = m4;
@@ -2365,7 +2346,7 @@ bool is_carved(u64 seed, v3f p)
#endif
double f = 10.0;
- double y_div = 1.5;
+ double y_div = 1.0;
double v4 = contour(f*noise3d_perlin(
0.5+p.X/200,
@@ -4082,6 +4063,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
}
#endif
+#if 0
MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
core::map<v3s16, MapBlock*> &changed_blocks,
bool force)
@@ -4813,6 +4795,7 @@ MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
MapChunk *chunk = getChunk(chunkpos1);
return chunk;
}
+#endif
ServerMapSector * ServerMap::createSector(v2s16 p2d)
{
@@ -4873,7 +4856,8 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
DSTACK("%s: p2d=(%d,%d)",
__FUNCTION_NAME,
p2d.X, p2d.Y);
-
+
+#if 0
/*
Check chunk status
*/
@@ -4892,7 +4876,8 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
// Generate chunk and neighbors
generateChunk(chunkpos, changed_blocks);
}
-
+#endif
+
/*
Return sector if it exists now
*/
@@ -4923,7 +4908,7 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
<<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
<<std::endl;
-#if 1
+#if 0
dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
// Generate chunk
@@ -4954,6 +4939,956 @@ MapSector * ServerMap::emergeSector(v2s16 p2d,
//return generateSector();
}
+enum BlockType{
+ BT_GROUND,
+ BT_SURFACE,
+ BT_SKY
+};
+
+MapBlock* ServerMap::generateBlockRaw(v3s16 blockpos0,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ bool force)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ /*
+ Don't generate if already fully generated
+ */
+ if(force == false)
+ {
+ MapBlock *block = getBlockNoCreateNoEx(blockpos0);
+ if(block != NULL && block->isFullyGenerated())
+ {
+ dstream<<"generateBlockRaw(): Block "
+ <<"("<<blockpos0.X<<","<<blockpos0.Y
+ <<","<<blockpos0.Z<<")"
+ <<" already generated (not forced)"<<std::endl;
+ return block;
+ }
+ }
+
+ /*dstream<<"generateBlockRaw(): Generating block "
+ <<"("<<blockpos0.X<<","<<blockpos0.Y
+ <<","<<blockpos0.Z<<")"
+ <<std::endl;*/
+
+ //TimeTaker timer("generateBlockRaw()");
+
+ /*
+ Calculate some simple values
+ */
+
+ v2s16 sectorpos0(blockpos0.X, blockpos0.Z);
+
+ /*
+ Fill in some variables for the code that was copied from
+ generateChunkRaw
+ */
+ s16 y_blocks_min = blockpos0.Y-1;
+ s16 y_blocks_max = blockpos0.Y+1;
+ s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
+ s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
+ v2s16 sectorpos_bigbase = sectorpos0 - v2s16(1,1);
+ s16 sectorpos_bigbase_size = 3;
+ v2s16 sectorpos_base = sectorpos0;
+ s16 sectorpos_base_size = 1;
+ s16 max_spread_amount = MAP_BLOCKSIZE;
+ s16 lighting_min_d = 0-max_spread_amount;
+ s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+
+ /*
+ Create the whole area of this and the neighboring blocks
+ */
+
+ core::list<v3s16> blocks_created;
+
+ {
+ //TimeTaker timer("generateBlockRaw() create area");
+
+ for(s16 x=-1; x<=1; x++)
+ for(s16 z=-1; z<=1; z++)
+ {
+ v2s16 sectorpos = sectorpos0 + v2s16(x,z);
+ ServerMapSector *sector = createSector(sectorpos);
+ assert(sector);
+
+ for(s16 y=blockpos0.Y-1; y<=blockpos0.Y+1; y++)
+ {
+ v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
+
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block && block->isDummy() == false)
+ continue;
+
+ block = createBlock(blockpos);
+ block->setFullyGenerated(false);
+
+ blocks_created.push_back(blockpos);
+
+ // Lighting won't be calculated
+ block->setLightingExpired(true);
+ // Lighting will be calculated
+ //block->setLightingExpired(false);
+
+ /*
+ 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.
+
+ This doesn't matter if the initial lighting is done
+ here.
+ */
+ //block->setIsUnderground(y != y_blocks_max);
+ block->setIsUnderground(false);
+ }
+ }
+ }
+
+ /*
+ Now we have a big empty area of (16x16x16)x27.
+
+ Make a ManualMapVoxelManipulator that contains the whole area.
+ */
+
+ ManualMapVoxelManipulator vmanip(this);
+ // Add the area we just generated
+ {
+ //TimeTaker timer("generateBlockRaw() initialEmerge");
+ vmanip.initialEmerge(blockpos0-v3s16(1,1,1), blockpos0+v3s16(1,1,1));
+ }
+
+ // Clear all flags
+ vmanip.clearFlag(0xff);
+
+ // Block type of blockpos0
+ BlockType center_block_type = BT_SURFACE;
+
+ /*
+ Generate general ground level to newly created blocks.
+ Only stone is used and it is converted to other stuff later on.
+ */
+ {
+ // 22ms @cs=8
+ //dstream<<"Generating base ground..."<<std::endl;
+ //TimeTaker timer1("ground level");
+
+ // Loop through created blocks
+ for(core::list<v3s16>::Iterator i = blocks_created.begin();
+ i != blocks_created.end(); i++)
+ {
+ v3s16 blockpos = *i;
+ v2s16 sectorpos(blockpos.X, blockpos.Z);
+
+ /*
+ Approximate whether this block is a surface block, an air
+ block or a ground block.
+
+ This shall never mark a surface block as non-surface.
+ */
+
+ BlockType block_type = BT_SURFACE;
+ v3s16 p_nodes = blockpos * MAP_BLOCKSIZE;
+ s32 lowest_ground_y = 32767;
+ s32 highest_ground_y = -32768;
+ u8 water_material = CONTENT_WATERSOURCE;
+
+ {
+ /*
+ Estimate surface at different positions of the block, to
+ try to accomodate the effect of turbulence.
+ */
+ v3f checklist[] = {
+ v3f(0,0,0),
+ v3f(0,1,0),
+ v3f(0,1,1),
+ v3f(0,0,1),
+ v3f(1,0,0),
+ v3f(1,1,0),
+ v3f(1,1,1),
+ v3f(1,0,1),
+ v3f(0.5,0.5,0.5),
+ };
+ v3f p_nodes_f = intToFloat(p_nodes, 1);
+ float surface_y_max = -1000000;
+ float surface_y_min = 1000000;
+ for(u32 i=0; i<sizeof(checklist)/sizeof(checklist[0]); i++)
+ {
+ v3f p_map_f = p_nodes_f + checklist[i]*MAP_BLOCKSIZE;
+
+ double depth_guess;
+ /*bool is_ground =*/ is_base_ground(m_seed, p_map_f, &depth_guess);
+
+ // Estimate the surface height
+ float surface_y_f = p_map_f.Y + depth_guess;
+
+ if(surface_y_f > surface_y_max)
+ surface_y_max = surface_y_f;
+ if(surface_y_f < surface_y_min)
+ surface_y_min = surface_y_f;
+ }
+
+ float block_low_y_f = p_nodes_f.Y;
+ float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
+
+ /*dstream<<"surface_y_max="<<surface_y_max
+ <<", surface_y_min="<<surface_y_min
+ <<", block_low_y_f="<<block_low_y_f
+ <<", block_high_y_f="<<block_high_y_f
+ <<std::endl;*/
+
+ // A fuzzyness value
+ // Must accomodate mud and turbulence holes
+ float d_down = 16;
+ // Must accomodate a bit less
+ float d_up = 5;
+
+ if(block_high_y_f < surface_y_min - d_down)
+ {
+ //dstream<<"BT_GROUND"<<std::endl;
+ // A ground block
+ block_type = BT_GROUND;
+ }
+ else if(block_low_y_f >= surface_y_max + d_up
+ && block_low_y_f > WATER_LEVEL + d_up)
+ {
+ //dstream<<"BT_SKY"<<std::endl;
+ // A sky block
+ block_type = BT_SKY;
+ }
+ else
+ {
+ //dstream<<"BT_SURFACE"<<std::endl;
+ // A surface block
+ block_type = BT_SURFACE;
+ }
+
+ if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
+ {
+ lowest_ground_y = surface_y_min;
+ highest_ground_y = surface_y_max;
+ }
+ }
+
+ if(blockpos == blockpos0)
+ center_block_type = block_type;
+
+ if(block_type == BT_GROUND)
+ {
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block)
+ block->setIsUnderground(true);
+ }
+
+ /*
+ If the block has ground, generate ground precisely.
+ */
+
+ if(block_type == BT_SURFACE || block_type == BT_GROUND)
+ {
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ {
+ v2s16 real_p2d = v2s16(x0,z0) + sectorpos*MAP_BLOCKSIZE;
+
+ v2f real_p2d_f(real_p2d.X,real_p2d.Y);
+
+ double tfxz = get_turbulence_factor_2d(m_seed, real_p2d_f);
+ bool turbulence_is_used = (tfxz > 0.001);
+
+ float surface_y_f = 0;
+ s16 surface_y = 0;
+
+ float noturb_surface_y_f = base_rock_level_2d(m_seed, real_p2d_f);
+ s16 noturb_surface_y = noturb_surface_y_f;
+
+ // Get some statistics of surface height
+ if(noturb_surface_y < lowest_ground_y)
+ lowest_ground_y = noturb_surface_y;
+ if(noturb_surface_y > highest_ground_y)
+ highest_ground_y = noturb_surface_y;
+
+ // Use fast index incrementing
+ v3s16 em = vmanip.m_area.getExtent();
+ u32 i = vmanip.m_area.index(v3s16(
+ real_p2d.X,
+ blockpos.Y*MAP_BLOCKSIZE,
+ real_p2d.Y));
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+ {
+ s16 real_y = blockpos.Y * MAP_BLOCKSIZE + y0;
+ v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
+ MapNode n;
+
+ /*
+ Calculate material
+ */
+
+ bool is_ground = false;
+ v3f real_pos_f = intToFloat(real_pos, 1);
+
+ bool turb_for_node = (turbulence_is_used
+ && real_y >= TURBULENCE_BOTTOM_CUTOFF_Y);
+
+ bool is_cavern = false;
+
+ if(is_carved(m_seed, real_pos_f))
+ {
+ is_ground = false;
+ if(real_y < noturb_surface_y)
+ is_cavern = true;
+ }
+ else
+ {
+ if(turb_for_node)
+ {
+ double depth_guess;
+ is_ground = is_base_ground(m_seed,
+ real_pos_f, &depth_guess);
+
+ // Estimate the surface height
+ surface_y_f = (float)real_y + depth_guess;
+ surface_y = real_y + depth_guess;
+
+ // Save some statistics of surface height
+ if(surface_y < lowest_ground_y)
+ lowest_ground_y = surface_y;
+ if(surface_y > highest_ground_y)
+ highest_ground_y = surface_y;
+ }
+ else
+ {
+ surface_y = noturb_surface_y;
+ }
+
+ is_ground = (real_y <= surface_y);
+ }
+
+ // If node is not ground, it's air or water
+ if(is_ground == false)
+ {
+ // If under water level, it's water
+ if(real_y < WATER_LEVEL && !is_cavern)
+ {
+ n.d = water_material;
+ u8 dist = 16;
+ if(real_y >= surface_y)
+ dist = WATER_LEVEL-real_y+1;
+ n.setLight(LIGHTBANK_DAY,
+ diminish_light(LIGHT_SUN, dist));
+ /*
+ Add to transforming liquid queue (in case it'd
+ start flowing)
+ */
+ m_transforming_liquid.push_back(real_pos);
+ }
+ // else air
+ else
+ {
+ n.d = CONTENT_AIR;
+
+ /*
+ Guess lighting
+ */
+ if(real_y > surface_y + 4)
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+ }
+ }
+ // Else it's ground
+ else
+ {
+ if(is_underground_mud(m_seed, real_pos_f))
+ n.d = CONTENT_MUD;
+ else
+ n.d = CONTENT_STONE;
+ }
+
+ vmanip.m_data[i] = n;
+ vmanip.m_area.add_y(em, i, 1);
+ }
+ }
+ }// BT_SURFACE
+ else // BT_SKY or anything else
+ {
+ MapNode n_fill;
+ if(block_type == BT_GROUND)
+ {
+ //n_fill.d = CONTENT_STONE;
+ }
+ else if(block_type == BT_SKY)
+ {
+ n_fill.d = CONTENT_AIR;
+ n_fill.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+ }
+ else // fallback
+ {
+ n_fill.d = CONTENT_MESE;
+ }
+
+ for(s16 x=0; x<MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<MAP_BLOCKSIZE; z++)
+ {
+ // Node position
+ v2s16 p2d = sectorpos*MAP_BLOCKSIZE + v2s16(x,z);
+
+ {
+ // Use fast index incrementing
+ v3s16 em = vmanip.m_area.getExtent();
+ s16 min = blockpos.Y*MAP_BLOCKSIZE;
+ s16 max = min + MAP_BLOCKSIZE-1;
+ u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
+ for(s16 y=min; y<=max; y++)
+ {
+ vmanip.m_data[i] = n_fill;
+ vmanip.m_area.add_y(em, i, 1);
+ }
+ }
+ }
+ }
+ }
+
+ }//timer1
+
+ /*
+ Convert surface ground to mud
+ */
+
+ if(center_block_type == BT_SURFACE)
+ {
+#if 1
+ for(s16 x=0; x<MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<MAP_BLOCKSIZE; z++)
+ {
+ // Node position
+ v2s16 p2d = sectorpos0*MAP_BLOCKSIZE + v2s16(x,z);
+ v2f real_p2d_f(p2d.X,p2d.Y);
+
+ {
+ // Use fast index incrementing
+ v3s16 em = vmanip.m_area.getExtent();
+ s16 min = blockpos0.Y*MAP_BLOCKSIZE;
+ // Start from one above the central block
+ s16 max = min + MAP_BLOCKSIZE-1+1;
+ u32 i = vmanip.m_area.index(v3s16(p2d.X, max, p2d.Y));
+ // If stone, there won't be mud
+ if(vmanip.m_data[i].d == CONTENT_STONE)
+ continue;
+ // Find top of ground
+ bool found = false;
+ s16 y;
+ for(y=max; y>=min; y--)
+ {
+ if(vmanip.m_data[i].d == CONTENT_STONE)
+ {
+ found = true;
+ break;
+ }
+ vmanip.m_area.add_y(em, i, -1);
+ }
+ if(found == false)
+ continue;
+ // Set mud
+ s16 mud_amount = get_mud_amount(m_seed, real_p2d_f);
+ for(s16 j=0; j<mud_amount; j++)
+ {
+ if(vmanip.m_data[i].d != CONTENT_STONE)
+ {
+ break;
+ }
+ if(j==0 && y >= WATER_LEVEL)
+ vmanip.m_data[i].d = CONTENT_GRASS;
+ else
+ vmanip.m_data[i].d = CONTENT_MUD;
+ vmanip.m_area.add_y(em, i, -1);
+ }
+ }
+ }
+#endif
+ }
+
+ /*
+ Convert mud to sand
+ */
+ if(center_block_type == BT_SURFACE)
+ {
+ for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
+ {
+ // Node position in 2d
+ v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ // Determine whether to have sand here
+ bool have_sand = get_have_sand_coast(m_seed, v2f(p2d.X,p2d.Y));
+
+ if(have_sand == false)
+ continue;
+
+ // Find ground level
+ s16 surface_y = find_ground_level_clever(vmanip, p2d);
+
+ if(surface_y >= WATER_LEVEL + 2)
+ continue;
+
+ {
+ v3s16 em = vmanip.m_area.getExtent();
+ s16 y_start = surface_y;
+ u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ u32 not_sand_counter = 0;
+ for(s16 y=y_start; y>=y_nodes_min; y--)
+ {
+ MapNode *n = &vmanip.m_data[i];
+ if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
+ {
+ n->d = CONTENT_SAND;
+ }
+ else
+ {
+ not_sand_counter++;
+ if(not_sand_counter > 3)
+ break;
+ }
+
+ vmanip.m_area.add_y(em, i, -1);
+ }
+ }
+ }
+ }
+
+ /*
+ Add some minerals
+ */
+
+ if(center_block_type == BT_SURFACE || center_block_type == BT_GROUND)
+ {
+ s16 underground_level = 1 - blockpos0.Y;
+
+ /*
+ Add meseblocks
+ */
+ for(s16 i=0; i<underground_level/4 + 1; i++)
+ {
+ if(myrand()%25 == 0)
+ {
+ v3s16 cp(
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1
+ );
+ cp += blockpos0*MAP_BLOCKSIZE;
+
+ MapNode n;
+ n.d = CONTENT_MESE;
+
+ for(u16 i=0; i<27; i++)
+ {
+ if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
+ if(myrand()%8 == 0)
+ vmanip.setNode(cp+g_27dirs[i], n);
+ }
+ }
+ }
+
+ /*
+ Add coal
+ */
+ u16 coal_amount = 60;
+ u16 coal_rareness = 120 / coal_amount;
+ if(coal_rareness == 0)
+ coal_rareness = 1;
+ if(myrand()%coal_rareness == 0)
+ {
+ u16 a = myrand() % 16;
+ u16 amount = coal_amount * a*a*a / 1000;
+ for(s16 i=0; i<amount; i++)
+ {
+ v3s16 cp(
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1
+ );
+ cp += blockpos0*MAP_BLOCKSIZE;
+
+ MapNode n;
+ n.d = CONTENT_STONE;
+ n.param = MINERAL_COAL;
+
+ for(u16 i=0; i<27; i++)
+ {
+ if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
+ if(myrand()%8 == 0)
+ vmanip.setNode(cp+g_27dirs[i], n);
+ }
+ }
+ }
+
+ /*
+ Add iron
+ */
+ u16 iron_amount = 40;
+ u16 iron_rareness = 80 / iron_amount;
+ if(iron_rareness == 0)
+ iron_rareness = 1;
+ if(myrand()%iron_rareness == 0)
+ {
+ u16 a = myrand() % 16;
+ u16 amount = iron_amount * a*a*a / 1000;
+ for(s16 i=0; i<amount; i++)
+ {
+ v3s16 cp(
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1,
+ (myrand()%(MAP_BLOCKSIZE-2))+1
+ );
+ cp += blockpos0*MAP_BLOCKSIZE;
+
+ MapNode n;
+ n.d = CONTENT_STONE;
+ n.param = MINERAL_IRON;
+
+ for(u16 i=0; i<27; i++)
+ {
+ if(vmanip.getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
+ if(myrand()%8 == 0)
+ vmanip.setNode(cp+g_27dirs[i], n);
+ }
+ }
+ }
+ }
+
+
+ /*
+ Generate some trees
+ */
+ if(center_block_type == BT_SURFACE)
+ {
+ // Divide area into this amount of parts
+ s16 div = 1;
+ s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
+ double area = sidelen * sidelen;
+ for(s16 x0=0; x0<div; x0++)
+ for(s16 z0=0; z0<div; z0++)
+ {
+ // Center position of part of division
+ v2s16 p2d_center(
+ sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
+ sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
+ );
+ // Minimum edge of part of division
+ v2s16 p2d_min(
+ sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
+ sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
+ );
+ // Maximum edge of part of division
+ v2s16 p2d_max(
+ sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
+ sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
+ );
+ // Amount of trees
+ u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
+ // Put trees in random places on part of division
+ for(u32 i=0; i<tree_count; i++)
+ {
+ s16 x = myrand_range(p2d_min.X, p2d_max.X);
+ s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
+ s16 y = find_ground_level(vmanip, v2s16(x,z));
+ // Don't make a tree under water level
+ if(y < WATER_LEVEL)
+ continue;
+ // Don't make a tree in other blocks
+ if(y < blockpos0.Y*MAP_BLOCKSIZE
+ || y >= (blockpos0.Y+1)*MAP_BLOCKSIZE)
+ continue;
+ v3s16 p(x,y,z);
+ /*
+ Trees grow only on mud and grass
+ */
+ {
+ u32 i = vmanip.m_area.index(v3s16(p));
+ MapNode *n = &vmanip.m_data[i];
+ if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+ continue;
+ }
+ p.Y++;
+ // Make a tree
+ make_tree(vmanip, p);
+ }
+ }
+ }
+
+#if 0
+ /*
+ Initial lighting (sunlight)
+ TODO: Do the lighting this way, with the VoxelManipulator
+ */
+
+ core::map<v3s16, bool> light_sources;
+
+ {
+ // 750ms @cs=8, can't optimize more
+ TimeTaker timer1("initial lighting");
+
+ /*
+ Go through the edges and apply sunlight to them, not caring
+ about neighbors
+ */
+
+ // Four edges
+ for(s16 i=0; i<4; i++)
+ // Edge length
+ for(s16 j=lighting_min_d;
+ j<=lighting_max_d;
+ j++)
+ {
+ s16 x;
+ s16 z;
+ // +-X
+ if(i == 0 || i == 1)
+ {
+ x = (i==0) ? lighting_min_d : lighting_max_d;
+ if(i == 0)
+ z = lighting_min_d;
+ else
+ z = lighting_max_d;
+ }
+ // +-Z
+ else
+ {
+ z = (i==0) ? lighting_min_d : lighting_max_d;
+ if(i == 0)
+ x = lighting_min_d;
+ else
+ x = lighting_max_d;
+ }
+
+ // Node position in 2d
+ v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ // Loop from top to down
+ {
+ u8 light = LIGHT_SUN;
+ v3s16 em = vmanip.m_area.getExtent();
+ s16 y_start = y_nodes_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];
+ if(light_propagates_content(n->d) == false)
+ {
+ light = 0;
+ }
+ else if(light != LIGHT_SUN
+ || sunlight_propagates_content(n->d) == false)
+ {
+ if(light > 0)
+ light--;
+ }
+
+ n->setLight(LIGHTBANK_DAY, light);
+ n->setLight(LIGHTBANK_NIGHT, 0);
+
+ if(light != 0)
+ {
+ // Insert light source
+ light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
+ }
+
+ // Increment index by y
+ vmanip.m_area.add_y(em, i, -1);
+ }
+ }
+ }
+
+ /*
+ This has to be 1 smaller than the actual area, because
+ neighboring nodes are checked.
+ */
+ for(s16 x=lighting_min_d+1;
+ x<=lighting_max_d-1;
+ x++)
+ for(s16 z=lighting_min_d+1;
+ z<=lighting_max_d-1;
+ z++)
+ {
+ // Node position in 2d
+ v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ /*
+ Apply initial sunlight
+ */
+ {
+ u8 light = LIGHT_SUN;
+ bool add_to_sources = false;
+ v3s16 em = vmanip.m_area.getExtent();
+ s16 y_start = y_nodes_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];
+
+ if(light_propagates_content(n->d) == false)
+ {
+ light = 0;
+ }
+ else if(light != LIGHT_SUN
+ || sunlight_propagates_content(n->d) == false)
+ {
+ if(light > 0)
+ light--;
+ }
+
+ // This doesn't take much time
+ if(add_to_sources == false)
+ {
+ /*
+ Check sides. If side is not air or water, start
+ adding to light_sources.
+ */
+ v3s16 dirs4[4] = {
+ v3s16(0,0,1), // back
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(-1,0,0), // left
+ };
+ for(u32 di=0; di<4; di++)
+ {
+ v3s16 dirp = dirs4[di];
+ u32 i2 = i;
+ vmanip.m_area.add_p(em, i2, dirp);
+ MapNode *n2 = &vmanip.m_data[i2];
+ if(
+ n2->d != CONTENT_AIR
+ && n2->d != CONTENT_WATERSOURCE
+ && n2->d != CONTENT_WATER
+ ){
+ add_to_sources = true;
+ break;
+ }
+ }
+ }
+
+ n->setLight(LIGHTBANK_DAY, light);
+ n->setLight(LIGHTBANK_NIGHT, 0);
+
+ // This doesn't take much time
+ if(light != 0 && add_to_sources)
+ {
+ // Insert light source
+ light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
+ }
+
+ // Increment index by y
+ vmanip.m_area.add_y(em, i, -1);
+ }
+ }
+ }
+
+ }//timer1
+
+ // Spread light around
+ {
+ TimeTaker timer("generateBlockRaw() spreadLight");
+ vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
+ }
+#endif
+
+ /*
+ Blit generated stuff to map
+ */
+ {
+ vmanip.blitBackAll(&changed_blocks);
+ }
+
+#if 0
+ /*
+ Update day/night difference cache of the MapBlocks
+ */
+ {
+ for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ MapBlock *block = i.getNode()->getValue();
+ block->updateDayNightDiff();
+ }
+ }
+#endif
+
+ /*for(core::map<v3s16, MapBlock*>::Iterator
+ i = changed_blocks*/
+
+ // Done!
+ MapBlock *block = getBlockNoCreate(blockpos0);
+ block->setFullyGenerated(true);
+
+ /*
+ TODO: Calculate lighting with the VoxelManipulator, not this way
+ */
+ // emergeBlock reads this
+ block->setLightingExpired(true);
+ // Also set the above one, trees often will be there
+ {
+ MapBlock *block = getBlockNoCreate(blockpos0+v3s16(0,1,0));
+ if(block)
+ block->setLightingExpired(true);
+ }
+
+ return block;
+}
+
+
+/*MapBlock* ServerMap::generateBlock(v3s16 blockpos1,
+ core::map<v3s16, MapBlock*> &changed_blocks)*/
+MapBlock * ServerMap::generateBlock(
+ v3s16 blockpos1,
+ MapBlock *original_dummy,
+ ServerMapSector *sector,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
+)
+{
+ dstream<<"generateBlock(): Generating block "
+ <<"("<<blockpos1.X<<","<<blockpos1.Y<<","<<blockpos1.Z<<")"
+ <<std::endl;
+
+ /*
+ The block at blockpos1 should be generated fully, so that it won't
+ change in the future anymore when more stuff is generated.
+
+ Now, a block can be generated with generateBlockRaw().
+ generateBlockRaw() accesses the block and all its neighbors.
+ Here is what generateBlockRaw() does:
+ - If the asked block has been marked fully generated, do nothing.
+ - Create the asked block and its neighbors and generate the base
+ ground in them (if they don't exist)
+ - In places where the ground level is in the asked block, convert
+ top layer of ground to mud or sand. Conversion is extended to
+ the block below as needed.
+ - Add trees and other objects to the asked block. Parts of them
+ can be located in the neighboring blocks.
+ - Mark the asked block as fully generated.
+
+ This means the block and all its neighbors have to be generated to
+ obtain a block that won't change in the future.
+ */
+ for(s16 x=-1; x<=1; x++)
+ for(s16 y=-1; y<=1; y++)
+ for(s16 z=-1; z<=1; z++)
+ {
+ v3s16 blockpos0 = blockpos1 + v3s16(x,y,z);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos0);
+ // Skip if already generated
+ if(block != NULL && block->isFullyGenerated())
+ continue;
+ generateBlockRaw(blockpos0, changed_blocks);
+ }
+
+ assert(blockNonVolatile(blockpos1));
+
+ MapBlock *block = getBlockNoCreate(blockpos1);
+
+ return block;
+}
+
+#if 0
/*
NOTE: This is not used for main map generation, only for blocks
that are very high or low.
@@ -5887,6 +6822,7 @@ continue_generating:
return block;
}
+#endif
MapBlock * ServerMap::createBlock(v3s16 p)
{
@@ -6019,6 +6955,7 @@ MapBlock * ServerMap::emergeBlock(
bool does_not_exist = false;
bool lighting_expired = false;
+ bool half_generated = false;
MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
if(block == NULL)
@@ -6033,6 +6970,10 @@ MapBlock * ServerMap::emergeBlock(
{
lighting_expired = true;
}
+ else if(block->isFullyGenerated() == false)
+ {
+ half_generated = true;
+ }
else
{
// Valid block
@@ -6040,24 +6981,27 @@ MapBlock * ServerMap::emergeBlock(
return block;
}
- /*
- If block was not found on disk and not going to generate a
- new one, make sure there is a dummy block in place.
- */
- if(only_from_disk && (does_not_exist || lighting_expired))
+ if(half_generated == false)
{
- //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
-
- if(block == NULL)
+ /*
+ If block was not found on disk and not going to generate a
+ new one, make sure there is a dummy block in place.
+ */
+ if(only_from_disk && (does_not_exist || lighting_expired))
{
- // Create dummy block
- block = new MapBlock(this, p, true);
+ //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
- // Add block to sector
- sector->insertBlock(block);
+ if(block == NULL)
+ {
+ // Create dummy block
+ block = new MapBlock(this, p, true);
+
+ // Add block to sector
+ sector->insertBlock(block);
+ }
+ // Done.
+ return block;
}
- // Done.
- return block;
}
//dstream<<"Not found on disk, generating."<<std::endl;
@@ -6069,7 +7013,7 @@ MapBlock * ServerMap::emergeBlock(
/*
If the block doesn't exist, generate the block.
*/
- if(does_not_exist)
+ if(does_not_exist || half_generated)
{
block = generateBlock(p, block, sector, changed_blocks,
lighting_invalidated_blocks);
@@ -6212,7 +7156,7 @@ void ServerMap::save(bool only_changed)
<<std::endl;
saveMapMeta();
- saveChunkMeta();
+ //saveChunkMeta();
u32 sector_meta_count = 0;
u32 block_count = 0;
@@ -6272,7 +7216,7 @@ void ServerMap::loadAll()
dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
loadMapMeta();
- loadChunkMeta();
+ //loadChunkMeta();
std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
@@ -6363,7 +7307,8 @@ void ServerMap::saveMapMeta()
DSTACK(__FUNCTION_NAME);
dstream<<"INFO: ServerMap::saveMapMeta(): "
- <<"seed="<<m_seed<<", chunksize="<<m_chunksize
+ <<"seed="<<m_seed
+ /*<<", chunksize="<<m_chunksize*/
<<std::endl;
createDir(m_savedir);
@@ -6379,7 +7324,7 @@ void ServerMap::saveMapMeta()
Settings params;
params.setU64("seed", m_seed);
- params.setS32("chunksize", m_chunksize);
+ //params.setS32("chunksize", m_chunksize);
params.writeLines(os);
@@ -6419,13 +7364,15 @@ void ServerMap::loadMapMeta()
}
m_seed = params.getU64("seed");
- m_chunksize = params.getS32("chunksize");
+ //m_chunksize = params.getS32("chunksize");
dstream<<"INFO: ServerMap::loadMapMeta(): "
- <<"seed="<<m_seed<<", chunksize="<<m_chunksize
+ <<"seed="<<m_seed
+ /*<<", chunksize="<<m_chunksize*/
<<std::endl;
}
+#if 0
void ServerMap::saveChunkMeta()
{
DSTACK(__FUNCTION_NAME);
@@ -6513,6 +7460,7 @@ void ServerMap::loadChunkMeta()
m_chunks.insert(p, chunk);
}
}
+#endif
void ServerMap::saveSectorMeta(ServerMapSector *sector)
{
diff --git a/src/map.h b/src/map.h
index 74088b291..39cd79f01 100644
--- a/src/map.h
+++ b/src/map.h
@@ -38,7 +38,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapsector.h"
#include "constants.h"
#include "voxel.h"
-#include "mapchunk.h"
/*
Some exposed functions
@@ -336,81 +335,29 @@ public:
Map generation
*/
- // Returns the position of the chunk where the sector is in
- v2s16 sector_to_chunk(v2s16 sectorpos)
- {
- sectorpos.X += m_chunksize / 2;
- sectorpos.Y += m_chunksize / 2;
- v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
- return chunkpos;
- }
-
- // Returns the position of the (0,0) sector of the chunk
- v2s16 chunk_to_sector(v2s16 chunkpos)
- {
- v2s16 sectorpos(
- chunkpos.X * m_chunksize,
- chunkpos.Y * m_chunksize
- );
- sectorpos.X -= m_chunksize / 2;
- sectorpos.Y -= m_chunksize / 2;
- return sectorpos;
- }
-
- /*
- Get a chunk.
- */
- MapChunk *getChunk(v2s16 chunkpos)
- {
- core::map<v2s16, MapChunk*>::Node *n;
- n = m_chunks.find(chunkpos);
- if(n == NULL)
- return NULL;
- return n->getValue();
- }
-
/*
- True if the chunk and its neighbors are fully generated.
- It means the chunk will not be touched in the future by the
- generator. If false, generateChunk will make it true.
+ True if the block and its neighbors are fully generated.
+ It means the block will not be touched in the future by the
+ generator. If false, generateBlock will make it true.
*/
- bool chunkNonVolatile(v2s16 chunkpos)
+ bool blockNonVolatile(v3s16 blockpos)
{
- /*for(s16 x=-1; x<=1; x++)
- for(s16 y=-1; y<=1; y++)*/
- s16 x=0;
- s16 y=0;
+ for(s16 x=-1; x<=1; x++)
+ for(s16 y=-1; y<=1; y++)
+ for(s16 z=-1; z<=1; z++)
{
- v2s16 chunkpos0 = chunkpos + v2s16(x,y);
- MapChunk *chunk = getChunk(chunkpos);
- if(chunk == NULL)
+ v3s16 blockpos0 = blockpos + v3s16(x,y,z);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
return false;
- if(chunk->getGenLevel() != GENERATED_FULLY)
+ if(block->isFullyGenerated() == false)
return false;
}
return true;
}
/*
- Generate a chunk.
-
- All chunks touching this one can be altered also.
- */
- MapChunk* generateChunkRaw(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks,
- bool force=false);
-
- /*
- Generate a chunk and its neighbors so that it won't be touched
- anymore.
- */
- MapChunk* generateChunk(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks);
-
- /*
Generate a sector.
-
- This is mainly called by generateChunkRaw.
*/
//ServerMapSector * generateSector(v2s16 p);
@@ -437,6 +384,27 @@ public:
return emergeSector(p, changed_blocks);
}
+ /*MapBlock * generateBlock(
+ v3s16 p,
+ MapBlock *original_dummy,
+ ServerMapSector *sector,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
+ );*/
+
+ /*
+ Generate a block.
+
+ All blocks touching this one can be altered also.
+ */
+ MapBlock* generateBlockRaw(v3s16 blockpos,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ bool force=false);
+
+ /*
+ Generate a block and its neighbors so that it won't be touched
+ anymore.
+ */
MapBlock * generateBlock(
v3s16 p,
MapBlock *original_dummy,
@@ -444,6 +412,8 @@ public:
core::map<v3s16, MapBlock*> &changed_blocks,
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
);
+ /*MapBlock* generateBlock(v3s16 blockpos,
+ core::map<v3s16, MapBlock*> &changed_blocks);*/
/*
Get a block from somewhere.
@@ -516,9 +486,6 @@ public:
void saveMapMeta();
void loadMapMeta();
- void saveChunkMeta();
- void loadChunkMeta();
-
// The sector mutex should be locked when calling most of these
// This only saves sector-specific data such as the heightmap
@@ -551,11 +518,6 @@ private:
std::string m_savedir;
bool m_map_saving_enabled;
-
- // Chunk size in MapSectors
- s16 m_chunksize;
- // Chunks
- core::map<v2s16, MapChunk*> m_chunks;
};
/*
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 9594b2961..94c6ad909 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -36,6 +36,7 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
is_underground(false),
m_lighting_expired(true),
m_day_night_differs(false),
+ m_not_fully_generated(false),
m_objects(this)
{
data = NULL;
@@ -1762,6 +1763,8 @@ void MapBlock::serialize(std::ostream &os, u8 version)
flags |= 0x02;
if(m_lighting_expired)
flags |= 0x04;
+ if(m_not_fully_generated)
+ flags |= 0x08;
os.write((char*)&flags, 1);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
@@ -1884,6 +1887,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
is_underground = (flags & 0x01) ? true : false;
m_day_night_differs = (flags & 0x02) ? true : false;
m_lighting_expired = (flags & 0x04) ? true : false;
+ m_not_fully_generated = (flags & 0x08) ? true : false;
// Uncompress data
std::ostringstream os(std::ios_base::binary);
diff --git a/src/mapblock.h b/src/mapblock.h
index 02c072895..97129bd34 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -244,6 +244,17 @@ public:
return m_lighting_expired;
}
+ bool isFullyGenerated()
+ {
+ return !m_not_fully_generated;
+ }
+
+ void setFullyGenerated(bool b)
+ {
+ setChangedFlag();
+ m_not_fully_generated = !b;
+ }
+
bool isValid()
{
if(m_lighting_expired)
@@ -655,12 +666,28 @@ private:
// Whether day and night lighting differs
bool m_day_night_differs;
+ /*
+ Whether everything that is mainly located on this block has
+ been added to the world.
+
+ While this is false, a block can still be changed a bit when
+ stuff is added to the neighboring blocks that extends to this
+ one.
+
+ When this is false on every one of a 3x3x3 chunk of blocks, the
+ central one will not be changed by the map generator in the
+ future.
+
+ TODO: Save in file
+ */
+ bool m_not_fully_generated;
+
MapBlockObjectList m_objects;
// Object spawning stuff
float m_spawn_timer;
-#ifndef SERVER
+#ifndef SERVER // Only on client
/*
Set to true if the mesh has been ordered to be updated
sometime in the background.
diff --git a/src/mapchunk.h b/src/mapchunk.h
deleted file mode 100644
index 1819fa13e..000000000
--- a/src/mapchunk.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#ifndef MAPCHUNK_HEADER
-#define MAPCHUNK_HEADER
-
-/*
- MapChunk contains map-generation-time metadata for an area of
- some MapSectors. (something like 16x16)
-*/
-
-// These should fit in 8 bits, as they are saved as such.
-enum{
- GENERATED_FULLY = 0,
- GENERATED_PARTLY = 10,
- GENERATED_NOT = 20
-};
-
-class MapChunk
-{
-public:
- MapChunk():
- m_generation_level(GENERATED_NOT)
- {
- }
-
- /*
- Generation level. Possible values:
- GENERATED_FULLY = 0 = fully generated
- GENERATED_PARTLY = partly generated
- GENERATED_NOT = not generated
- */
- u16 getGenLevel(){ return m_generation_level; }
- void setGenLevel(u16 lev){ m_generation_level = lev; }
-
- void serialize(std::ostream &os, u8 version)
- {
- os.write((char*)&m_generation_level, 1);
- }
- void deSerialize(std::istream &is, u8 version)
- {
- is.read((char*)&m_generation_level, 1);
- }
-
-private:
- u8 m_generation_level;
-};
-
-#endif
-
diff --git a/src/materials.cpp b/src/materials.cpp
index f56b024b2..0558a5e39 100644
--- a/src/materials.cpp
+++ b/src/materials.cpp
@@ -13,9 +13,9 @@ void setStoneLikeDiggingProperties(u8 material, float toughness)
DiggingProperties(true, 15.0*toughness, 0));
g_material_properties[material].setDiggingProperties("WPick",
- DiggingProperties(true, 1.5*toughness, 65535./30.*toughness));
+ DiggingProperties(true, 1.3*toughness, 65535./30.*toughness));
g_material_properties[material].setDiggingProperties("STPick",
- DiggingProperties(true, 0.7*toughness, 65535./100.*toughness));
+ DiggingProperties(true, 0.65*toughness, 65535./100.*toughness));
/*g_material_properties[material].setDiggingProperties("MesePick",
DiggingProperties(true, 0.0*toughness, 65535./20.*toughness));*/
diff --git a/src/server.cpp b/src/server.cpp
index 61f354173..abdbd975d 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -544,11 +544,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
block_is_invalid = true;
}
- v2s16 p2d(p.X, p.Z);
- ServerMap *map = (ServerMap*)(&server->m_env.getMap());
- v2s16 chunkpos = map->sector_to_chunk(p2d);
- if(map->chunkNonVolatile(chunkpos) == false)
+ if(block->isFullyGenerated() == false)
+ {
block_is_invalid = true;
+ }
}
/*
@@ -3420,16 +3419,6 @@ Player *Server::emergePlayer(const char *name, const char *password,
nodepos = v2s16(-range + (myrand()%(range*2)),
-range + (myrand()%(range*2)));
v2s16 sectorpos = getNodeSectorPos(nodepos);
- /*
- Ignore position if it is near a chunk edge.
- Otherwise it would cause excessive loading time at
- initial generation
- */
- {
- if(m_env.getServerMap().sector_to_chunk(sectorpos+v2s16(1,1))
- != m_env.getServerMap().sector_to_chunk(sectorpos+v2s16(-1,-1)))
- continue;
- }
// Get sector (NOTE: Don't get because it's slow)
//m_env.getMap().emergeSector(sectorpos);
// Get ground height at point (fallbacks to heightmap function)