/*
Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 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
#include "porting.h"
#include "mineral.h"
#include "noise.h"
+#include "serverobject.h"
/*
Map
m_dout(dout),
m_sector_cache(NULL)
{
- m_sector_mutex.Init();
- assert(m_sector_mutex.IsInitialized());
+ /*m_sector_mutex.Init();
+ assert(m_sector_mutex.IsInitialized());*/
}
Map::~Map()
MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
return getSectorNoGenerateNoExNoLock(p);
}
light_sources to re-light the area without the removed light.
values of from_nodes are lighting values.
-
- There is a duplicate implementation of this in VoxelManipulator,
- which is faster for large volumes
*/
void Map::unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
/*
Lights neighbors of from_nodes, collects all them and then
goes on recursively.
-
- There is a duplicate implementation of this in VoxelManipulator,
- which is faster for large volumes
*/
void Map::spreadLight(enum LightBank bank,
core::map<v3s16, bool> & from_nodes,
This is called after changing a node from transparent to opaque.
The lighting value of the node should be left as-is after changing
other values. This sets the lighting value to 0.
-
- NOTE: This takes almost no time, the slow one is updateMeshes.
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks)
n.setLight(bank, 0);
}
+ /*
+ If node lets sunlight through and is under sunlight, it has
+ sunlight too.
+ */
+ if(node_under_sunlight && content_features(n.d).sunlight_propagates)
+ {
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
+ }
+
/*
Set the node on the map
*/
setNode(p, n);
+
+ /*
+ Add intial metadata
+ */
+
+ NodeMetadata *meta_proto = content_features(n.d).initial_metadata;
+ if(meta_proto)
+ {
+ NodeMetadata *meta = meta_proto->clone();
+ setNodeMetadata(p, meta);
+ }
/*
- If node is under sunlight, take all sunlighted nodes under
- it and clear light from them and from where the light has
- been spread.
+ If node is under sunlight and doesn't let sunlight through,
+ take all sunlighted nodes under it and clear light from them
+ and from where the light has been spread.
TODO: This could be optimized by mass-unlighting instead
of looping
*/
- if(node_under_sunlight)
+ if(node_under_sunlight && !content_features(n.d).sunlight_propagates)
{
s16 y = p.Y - 1;
for(;; y--){
break;
}
}
-
+
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
}
/*
- NOTE: This takes almost no time, the slow one is updateMeshes.
*/
void Map::removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks)
light_sources, modified_blocks);
}
+ /*
+ Remove node metadata
+ */
+
+ removeNodeMetadata(p);
+
/*
Remove the node.
This also clears the lighting.
*/
void Map::timerUpdate(float dtime)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator si;
u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
core::list<v3s16> *deleted_blocks)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::list<v2s16> sector_deletion_queue;
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
while(m_transforming_liquid.size() != 0)
{
- try
- {
-
/*
Get a queued transforming liquid node
*/
}
loopcount++;
- if(loopcount >= initial_size * 1 || loopcount >= 1000)
+ //if(loopcount >= 100000)
+ if(loopcount >= initial_size * 1)
break;
-
- }catch(InvalidPositionException &e)
+ }
+ //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
+}
+
+NodeMetadata* Map::getNodeMetadata(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ {
+ dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
+ <<std::endl;
+ return NULL;
+ }
+ NodeMetadata *meta = block->m_node_metadata.get(p_rel);
+ return meta;
+}
+
+void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ {
+ dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
+ <<std::endl;
+ return;
+ }
+ block->m_node_metadata.set(p_rel, meta);
+}
+
+void Map::removeNodeMetadata(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ {
+ dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
+ <<std::endl;
+ return;
+ }
+ block->m_node_metadata.remove(p_rel);
+}
+
+void Map::nodeMetadataStep(float dtime,
+ core::map<v3s16, MapBlock*> &changed_blocks)
+{
+ /*
+ NOTE:
+ Currently there is no way to ensure that all the necessary
+ blocks are loaded when this is run. (They might get unloaded)
+ NOTE: ^- Actually, that might not be so. In a quick test it
+ reloaded a block with a furnace when I walked back to it from
+ a distance.
+ */
+ core::map<v2s16, MapSector*>::Iterator si;
+ si = m_sectors.getIterator();
+ for(; si.atEnd() == false; si++)
+ {
+ MapSector *sector = si.getNode()->getValue();
+ core::list< MapBlock * > sectorblocks;
+ sector->getBlocks(sectorblocks);
+ core::list< MapBlock * >::Iterator i;
+ for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
{
+ MapBlock *block = *i;
+ bool changed = block->m_node_metadata.step(dtime);
+ if(changed)
+ changed_blocks[block->getPos()] = block;
}
}
- //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
}
/*
ServerMap::ServerMap(std::string savedir):
Map(dout_server),
- m_seed(0)
+ m_seed(0),
+ m_map_metadata_changed(true)
{
+ dstream<<__FUNCTION_NAME<<std::endl;
//m_chunksize = 64;
//m_chunksize = 16; // Too slow
- //m_chunksize = 8; // Takes a few seconds
- m_chunksize = 4; // Too small?
+ m_chunksize = 8; // Takes a few seconds
+ //m_chunksize = 4;
//m_chunksize = 2;
- // TODO: Save to and load from a file
m_seed = (((u64)(myrand()%0xffff)<<0)
+ ((u64)(myrand()%0xffff)<<16)
+ ((u64)(myrand()%0xffff)<<32)
}
else
{
- // Load map metadata (seed, chunksize)
- loadMapMeta();
-
- // Load chunk metadata
- loadChunkMeta();
+ try{
+ // Load map metadata (seed, chunksize)
+ loadMapMeta();
+
+ // Load chunk metadata
+ loadChunkMeta();
+ }
+ catch(FileNotGoodException &e){
+ dstream<<DTIME<<"WARNING: Server: Could not load "
+ <<"metafile(s). Disabling chunk-based "
+ <<"generation."<<std::endl;
+ m_chunksize = 0;
+ }
/*// Load sector (0,0) and throw and exception on fail
if(loadSectorFull(v2s16(0,0)) == false)
ServerMap::~ServerMap()
{
+ dstream<<__FUNCTION_NAME<<std::endl;
+
try
{
if(m_map_saving_enabled)
MapNode treenode(CONTENT_TREE);
MapNode leavesnode(CONTENT_LEAVES);
- vmanip.emerge(VoxelArea(p0-v3s16(2,0,2),p0+v3s16(2,7+2,2)));
-
- s16 trunk_h = myrand_range(4, 7);
+ s16 trunk_h = myrand_range(3, 6);
v3s16 p1 = p0;
for(s16 ii=0; ii<trunk_h; ii++)
{
{
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;
+ seed+2, 5, 0.66);
+ double zeroval = -0.3;
if(noise < zeroval)
return 0;
else
- return 0.025 * (noise-zeroval) / (1.0-zeroval);
+ return 0.04 * (noise-zeroval) / (1.0-zeroval);
}
-#define AVERAGE_MUD_AMOUNT 4.0
+#define AVERAGE_MUD_AMOUNT 4
-double get_mud_amount(u64 seed, v2f p)
+double base_rock_level_2d(u64 seed, v2s16 p)
{
- return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
- 0.5+p.X/200, 0.5+p.Y/200,
- seed+1, 5, 0.65));
-}
+ // The base ground level
+ double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
+ + 20. * noise2d_perlin(
+ 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
+ (seed>>32)+654879876, 6, 0.6);
+
+ /*// A bit hillier one
+ double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
+ 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+ (seed>>27)+90340, 6, 0.69);
+ if(base2 > base)
+ base = base2;*/
+#if 1
+ // Higher ground level
+ double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
+ 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+ seed+85039, 5, 0.69);
+ //higher = 30; // For debugging
-bool get_have_sand_coast(u64 seed, v2f p)
-{
- double sandnoise = noise2d_perlin(
- 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
- seed+59420, 3, 0.50);
- return (sandnoise > -0.25);
-}
+ // Limit higher to at least base
+ if(higher < base)
+ higher = base;
+
+ // Steepness factor of cliffs
+ double b = 1.0 + 1.0 * noise2d_perlin(
+ 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+ seed-932, 7, 0.7);
+ b = rangelim(b, 0.0, 1000.0);
+ b = pow(b, 5);
+ b *= 7;
+ b = rangelim(b, 3.0, 1000.0);
+ //dstream<<"b="<<b<<std::endl;
+ //double b = 20;
+
+ // Offset to more low
+ double a_off = -0.2;
+ // High/low selector
+ /*double a = 0.5 + b * (a_off + noise2d_perlin(
+ 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
+ seed-359, 6, 0.7));*/
+ double a = (double)0.5 + b * (a_off + noise2d_perlin(
+ 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+ seed-359, 5, 0.60));
+ // Limit
+ a = rangelim(a, 0.0, 1.0);
-bool get_have_sand_ground(u64 seed, v2f p)
-{
- double sandnoise = noise2d_perlin(
- 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
- seed+54290232, 6, 0.65);
- return (sandnoise > 1.0);
+ //dstream<<"a="<<a<<std::endl;
+
+ double h = base*(1.0-a) + higher*a;
+#else
+ double h = base;
+#endif
+ return h;
}
-// -1->0, 0->1, 1->0
-double contour(double v)
+double get_mud_add_amount(u64 seed, v2s16 p)
{
- v = fabs(v);
- if(v >= 1.0)
- return 0.0;
- return (1.0-v);
+ return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
+ 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
+ seed+91013, 3, 0.55));
}
-// -1->0, -r->1, 0->1, r->1, 1->0
-double contour_flat_top(double v, double r)
+/*
+ Adds random objects to block, depending on the content of the block
+*/
+void addRandomObjects(MapBlock *block)
{
- v = fabs(v);
- if(v >= 1.0)
- return 0.0;
- double rmax = 0.999;
- if(r >= rmax)
- r = rmax;
- if(v <= r)
- return 1.0;
- v -= r;
- return ((1.0-r)-v) / (1.0-r);
- //return easeCurve(((1.0-r)-v) / (1.0-r));
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ {
+ bool last_node_walkable = false;
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+ {
+ v3s16 p(x0,y0,z0);
+ MapNode n = block->getNodeNoEx(p);
+ if(n.d == CONTENT_IGNORE)
+ continue;
+ if(content_features(n.d).liquid_type != LIQUID_NONE)
+ continue;
+ if(content_features(n.d).walkable)
+ {
+ last_node_walkable = true;
+ continue;
+ }
+ if(last_node_walkable)
+ {
+ // If block contains light information
+ if(content_features(n.d).param_type == CPT_LIGHT)
+ {
+ if(n.getLight(LIGHTBANK_DAY) <= 3)
+ {
+ if(myrand() % 300 == 0)
+ {
+ v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+ pos_f.Y -= BS*0.4;
+ ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
+ std::string data = obj->getStaticData();
+ StaticObject s_obj(obj->getType(),
+ obj->getBasePosition(), data);
+ // Add some
+ block->m_static_objects.insert(0, s_obj);
+ block->m_static_objects.insert(0, s_obj);
+ block->m_static_objects.insert(0, s_obj);
+ block->m_static_objects.insert(0, s_obj);
+ block->m_static_objects.insert(0, s_obj);
+ block->m_static_objects.insert(0, s_obj);
+ delete obj;
+ }
+ if(myrand() % 300 == 0)
+ {
+ v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+ pos_f.Y -= BS*0.4;
+ ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
+ std::string data = obj->getStaticData();
+ StaticObject s_obj(obj->getType(),
+ obj->getBasePosition(), data);
+ // Add one
+ block->m_static_objects.insert(0, s_obj);
+ delete obj;
+ }
+ }
+ }
+ }
+ last_node_walkable = false;
+ }
+ }
+ block->setChangedFlag();
}
-double base_rock_level_2d(u64 seed, v2f p)
+#define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
+
+/*
+ This is the main map generation method
+*/
+
+void makeChunk(ChunkMakeData *data)
{
- // The ground level (return value)
- double h = WATER_LEVEL-1.5;
-
- // Raises from 0 when parameter is -1...1
- /*double m2 = contour_flat_top(-0.8 + 2.0 * noise2d_perlin(
- 0.0+(float)p.X/1500., 0.0+(float)p.Y/1500.,
- (seed>>32)+34758, 5, 0.55), 0.10);*/
- /*double m2 = 1.0;
- if(m2 > 0.0001)
- {
- // HUGE mountains
- double m1 = 200.0 + 300.0 * noise2d_perlin(
- 0.0+(float)p.X/1000., 0.0+(float)p.Y/1000.,
- (seed>>32)+98525, 8, 0.5);
- h += m1 * m2;
- //h += 30 * m2;
- }*/
+ if(data->no_op)
+ return;
+
+ s16 y_nodes_min = data->y_blocks_min * MAP_BLOCKSIZE;
+ s16 y_nodes_max = data->y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
+ s16 h_blocks = data->y_blocks_max - data->y_blocks_min + 1;
+ u32 relative_volume = (u32)data->sectorpos_base_size*MAP_BLOCKSIZE
+ *(u32)data->sectorpos_base_size*MAP_BLOCKSIZE
+ *(u32)h_blocks*MAP_BLOCKSIZE;
+ v3s16 bigarea_blocks_min(
+ data->sectorpos_bigbase.X,
+ data->y_blocks_min,
+ data->sectorpos_bigbase.Y
+ );
+ v3s16 bigarea_blocks_max(
+ data->sectorpos_bigbase.X + data->sectorpos_bigbase_size - 1,
+ data->y_blocks_max,
+ data->sectorpos_bigbase.Y + data->sectorpos_bigbase_size - 1
+ );
+ s16 lighting_min_d = 0-data->max_spread_amount;
+ s16 lighting_max_d = data->sectorpos_base_size*MAP_BLOCKSIZE
+ + data->max_spread_amount-1;
- /*double tm2 = contour_flat_top(-1.0 + 3.0 * noise2d_perlin(
- 0.0+(float)p.X/300., 0.0+(float)p.Y/300.,
- (seed>>32)+78593, 5, 0.55), 0.15);
- h += 30 * tm2;*/
+ // Clear all flags
+ data->vmanip.clearFlag(0xff);
-#if 0
- {
- // Large mountains
- double m3 = 100.0 - 600.0 * noise2d_perlin_abs(
- 0.324+(float)p.X/2000., 0.423+(float)p.Y/2000.,
- (seed>>32)+985251, 9, 0.55);
- if(m3 > h)
- h = m3;
- }
-#endif
+ TimeTaker timer_generate("makeChunk() generate");
-#if 0
+ // Maximum height of the stone surface and obstacles.
+ // This is used to disable cave generation from going too high.
+ s16 stone_surface_max_y = 0;
+
+ /*
+ Generate general ground level to full area
+ */
{
- // More mountain ranges
- double d = 100;
- double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
- 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
- seed+850342, 7, 0.55);
- /*if(a1 > d)
- a1 = d + sqrt(a1-d);*/
- a1 = (1.0 - exp(-a1/d))*d;
- /*if(a1 > h)
- h = a1;*/
- if(a1 > 0)
- h += a1;
- }
-#endif
+ // 22ms @cs=8
+ TimeTaker timer1("Generating ground level");
#if 0
+ NoiseBuffer noisebuf1;
+ //NoiseBuffer noisebuf2;
{
- // More mountain ranges
- double d = 60;
- double a1 = d*2.0 - d*7 * noise2d_perlin_abs(
- 0.5+(float)p.X/1000., 0.5+(float)p.Y/1000.,
- seed+850342, 7, 0.55);
- /*if(a1 > d)
- a1 = d + sqrt(a1-d);*/
- a1 = (1.0 - exp(-a1/d))*d;
- /*if(a1 > h)
- h = a1;*/
- if(a1 > 0)
- h += a1;
- }
-#endif
+ v3f minpos_f(
+ data->sectorpos_bigbase.X*MAP_BLOCKSIZE,
+ y_nodes_min,
+ data->sectorpos_bigbase.Y*MAP_BLOCKSIZE
+ );
+ v3f maxpos_f = minpos_f + v3f(
+ data->sectorpos_bigbase_size*MAP_BLOCKSIZE,
+ y_nodes_max-y_nodes_min,
+ data->sectorpos_bigbase_size*MAP_BLOCKSIZE
+ );
+ v3f samplelength_f = v3f(4.0, 4.0, 4.0);
-#if 0
+ TimeTaker timer("noisebuf.create");
+
+ noisebuf1.create(data->seed+25104, 6, 0.60, 200.0,
+ minpos_f.X, minpos_f.Y, minpos_f.Z,
+ maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
+ samplelength_f.X, samplelength_f.Y, samplelength_f.Z);
+ /*noisebuf1.create(data->seed+25104, 3, 0.60, 25.0,
+ minpos_f.X, minpos_f.Y, minpos_f.Z,
+ maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
+ samplelength_f.X, samplelength_f.Y, samplelength_f.Z);
+ noisebuf2.create(data->seed+25105, 4, 0.50, 200.0,
+ minpos_f.X, minpos_f.Y, minpos_f.Z,
+ maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
+ samplelength_f.X, samplelength_f.Y, samplelength_f.Z);*/
+ }
+
+ for(s16 x=0; x<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
{
- // Very steep mountain ranges
- double d = 120;
- double a1 = d*2 - d*6.5 * noise2d_perlin_abs(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+850342, 6, 0.6);
- /*if(a1 > d)
- a1 = d + sqrt(a1-d);*/
- a1 = (1.0 - exp(-a1/d))*d;
- /*if(a1 > h)
- h = a1;*/
- if(a1 > 0)
- h += a1;
- /*double a = noise2d_perlin_abs(
- 0.94+(float)p.X/2000., 0.26+(float)p.Y/2000.,
- (seed>>32)+65012102, 8, 0.50);
- double m4 = 100.0 - 400.0 * a;
- if(m4 > h)
- h = m4;*/
+ // Node position
+ v2s16 p2d = data->sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
+
+ // Ground height at this point
+ float surface_y_f = 0.0;
+
+ // Use perlin noise for ground height
+ surface_y_f = base_rock_level_2d(data->seed, p2d);
+ //surface_y_f = base_rock_level_2d(data->seed, p2d);
+
+ // Convert to integer
+ s16 surface_y = (s16)surface_y_f;
+
+ // Log it
+ if(surface_y > stone_surface_max_y)
+ stone_surface_max_y = surface_y;
+
+ /*
+ Fill ground with stone
+ */
+ {
+ // Use fast index incrementing
+ v3s16 em = data->vmanip.m_area.getExtent();
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
+ for(s16 y=y_nodes_min; y<=y_nodes_max; y++)
+ {
+ // Skip if already generated.
+ // This is done here because there might be a cave at
+ // any point in ground, which could look like it
+ // wasn't generated.
+ if(data->vmanip.m_data[i].d != CONTENT_AIR)
+ break;
+
+ /*s16 noiseval = 50.0 * noise3d_perlin(
+ 0.5+(float)p2d.X/100.0,
+ 0.5+(float)y/100.0,
+ 0.5+(float)p2d.Y/100.0,
+ data->seed+123, 5, 0.5);*/
+ double noiseval = 64.0 * noisebuf1.get(p2d.X, y, p2d.Y);
+ /*double noiseval = 30.0 * noisebuf1.get(p2d.X, y, p2d.Y);
+ noiseval *= MYMAX(0, -0.2 + noisebuf2.get(p2d.X, y, p2d.Y));*/
+
+ //if(y < surface_y + noiseval)
+ if(noiseval > 0)
+ //if(noiseval > y)
+ data->vmanip.m_data[i].d = CONTENT_STONE;
+
+ data->vmanip.m_area.add_y(em, i, 1);
+ }
+ }
}
#endif
- /*
- The stuff before this comment is usually not used.
- The stuff after this comment is usually used.
- */
-
#if 1
+ for(s16 x=0; x<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<data->sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
{
- // 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);
- m4 *= 120;
- if(m4 > h)
- h = m4;
- }
-#endif
+ // Node position
+ v2s16 p2d = data->sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
+
+ /*
+ Skip of already generated
+ */
+ /*{
+ v3s16 p(p2d.X, y_nodes_min, p2d.Y);
+ if(data->vmanip.m_data[data->vmanip.m_area.index(p)].d != CONTENT_AIR)
+ continue;
+ }*/
-#if 1
- // Some kind of hill chains or something
- {
- double a1 = 1.0 - 2.5 * noise2d_perlin_abs(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+850342, 5, 0.6);
- a1 *= 30;
- double d = 15;
- if(a1 > d)
- a1 = d + sqrt(a1-d);
- /*if(a1 > h)
- h = a1;*/
- if(a1 > 0)
- h += a1;
- }
-#endif
+ // Ground height at this point
+ float surface_y_f = 0.0;
-#if 1
- double base = -2. + 25. * noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- (seed>>32)+653876, 7, 0.65);
-#else
- double base = 0;
+ // Use perlin noise for ground height
+ surface_y_f = base_rock_level_2d(data->seed, p2d);
+
+ /*// Experimental stuff
+ {
+ float a = highlands_level_2d(data->seed, p2d);
+ if(a > surface_y_f)
+ surface_y_f = a;
+ }*/
+
+ // Convert to integer
+ s16 surface_y = (s16)surface_y_f;
+
+ // Log it
+ if(surface_y > stone_surface_max_y)
+ stone_surface_max_y = surface_y;
+
+ /*
+ Fill ground with stone
+ */
+ {
+ // Use fast index incrementing
+ v3s16 em = data->vmanip.m_area.getExtent();
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
+ for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
+ {
+ // Skip if already generated.
+ // This is done here because there might be a cave at
+ // any point in ground, which could look like it
+ // wasn't generated.
+ if(data->vmanip.m_data[i].d != CONTENT_AIR)
+ break;
+
+ data->vmanip.m_data[i].d = CONTENT_STONE;
+
+ data->vmanip.m_area.add_y(em, i, 1);
+ }
+ }
+ }
#endif
-#if 1
- /*
- Combined with turbulence, this thing here is able to make very
- awesome terrain, albeit rarely.
+ }//timer1
- This is also responsible for small islands.
+ /*
+ Randomize some parameters
*/
+
+ //s32 stone_obstacle_count = 0;
+ /*s32 stone_obstacle_count =
+ rangelim((1.0+noise2d(data->seed+897,
+ data->sectorpos_base.X, data->sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
+
+ //s16 stone_obstacle_max_height = 0;
+ /*s16 stone_obstacle_max_height =
+ rangelim((1.0+noise2d(data->seed+5902,
+ data->sectorpos_base.X, data->sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
- double higher = 40. * noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+39292, 6, 0.50);
- /*double higher = 50. * noise2d_perlin_abs(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+85039, 5, 0.63);*/
- //higher = 25;
+ /*
+ Loop this part, it will make stuff look older and newer nicely
+ */
+ const u32 age_loops = 2;
+ for(u32 i_age=0; i_age<age_loops; i_age++)
+ { // Aging loop
+ /******************************
+ BEGINNING OF AGING LOOP
+ ******************************/
- if(higher > base)
- {
- // Steepness factor of cliffs
- double b = 1.0 + 1.0 * noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed-932, 6, 0.7);
- b = rangelim(b, 0.0, 1000.0);
#if 1
- b = pow(b, 5);
- b *= 16;
- b = rangelim(b, 3.0, 1000.0);
- //dstream<<"b="<<b<<std::endl;
- //double b = 20;
- // Offset to more low
- //double a_off = -0.30;
- double a_off = -0.20;
- // High/low selector
- double a = (double)0.5 + b * (a_off + noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed-359, 7, 0.70));
-#endif
-#if 0
- /*b = pow(b, 5);
- b *= 2;
- b = rangelim(b, 3.0, 20.0);*/
- //b = 10.0;
- double a = -1.5 + 5.0 * (noise2d_perlin_abs(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed-359, 6, 0.6));
- a *= 3.0;
- /*double a = 5.0 * (noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed-359, 5, 0.6));*/
- //a = contour_flat_top(a, 0.2);
-#endif
- // Limit
- a = rangelim(a, 0.0, 1.0);
- a = easeCurve(a);
-
- //dstream<<"a="<<a<<std::endl;
+ {
+ // 24ms @cs=8
+ //TimeTaker timer1("caves");
- /*double h2 = higher * a;
- if(h2 > h)
- h = h2;*/
-
- h += base*(1.0-a) + higher*a;
- }
- else
+ /*
+ Make caves
+ */
+ u32 caves_count = relative_volume / 400000;
+ u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
+ if(stone_surface_max_y < WATER_LEVEL)
+ bruises_count = 0;
+ /*u32 caves_count = 0;
+ u32 bruises_count = 0;*/
+ for(u32 jj=0; jj<caves_count+bruises_count; jj++)
{
- h += base;
- }
-#else
- h += base;
-#endif
+ s16 min_tunnel_diameter = 3;
+ s16 max_tunnel_diameter = 5;
+ u16 tunnel_routepoints = 20;
+
+ v3f main_direction(0,0,0);
- return h;
-}
+ bool bruise_surface = (jj > caves_count);
-double base_rock_level_2d(u64 seed, v2s16 p)
-{
- return base_rock_level_2d(seed, v2f((float)p.X, (float)p.Y));
-}
+ if(bruise_surface)
+ {
+ min_tunnel_diameter = 5;
+ max_tunnel_diameter = myrand_range(10, 20);
+ /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
+ max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
+
+ /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
+ data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
-double get_turbulence_factor_2d(u64 seed, v2f p)
-{
- double vv = -0.50 + 2.0 * noise2d_perlin(
- 0.5+p.X/100,
- 0.5+p.Y/100,
- seed+85498783983, 4, 0.5);
- vv = rangelim(vv, 0.0, 1.0);
- return vv;
-}
+ tunnel_routepoints = 5;
+ }
+ else
+ {
+ }
-#define TURBULENCE_BOTTOM_CUTOFF_Y (WATER_LEVEL-7)
+ // Allowed route area size in nodes
+ v3s16 ar(
+ data->sectorpos_base_size*MAP_BLOCKSIZE,
+ h_blocks*MAP_BLOCKSIZE,
+ data->sectorpos_base_size*MAP_BLOCKSIZE
+ );
-double get_turbulence_factor_y(u64 seed, f32 y)
-{
- double d = 14;
- double min = TURBULENCE_BOTTOM_CUTOFF_Y;
- if(y < min)
- return 0.0;
- else if(y < min + d)
- return ((y-min)/d);
- return 1.0;
-}
+ // Area starting point in nodes
+ v3s16 of(
+ data->sectorpos_base.X*MAP_BLOCKSIZE,
+ data->y_blocks_min*MAP_BLOCKSIZE,
+ data->sectorpos_base.Y*MAP_BLOCKSIZE
+ );
-v2f get_raw_turbulence(u64 seed, v3f p)
-{
- double f = 8;
+ // Allow a bit more
+ //(this should be more than the maximum radius of the tunnel)
+ //s16 insure = 5; // Didn't work with max_d = 20
+ s16 insure = 10;
+ s16 more = data->max_spread_amount - max_tunnel_diameter/2 - insure;
+ ar += v3s16(1,0,1) * more * 2;
+ of -= v3s16(1,0,1) * more;
+
+ s16 route_y_min = 0;
+ // Allow half a diameter + 7 over stone surface
+ s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
- double v1 = f * noise3d_perlin(
- 0.5+p.X/100,
- 0.5+p.Y/100,
- 0.5+p.Z/100,
- seed+4045, 5, 0.65);
+ /*// If caves, don't go through surface too often
+ if(bruise_surface == false)
+ route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
- double v2 = f * noise3d_perlin(
- 0.5+p.X/100,
- 0.5+p.Y/100,
- 0.5+p.Z/100,
- seed+9495, 5, 0.65);
-
- return v2f(v1, v2);
-}
+ // Limit maximum to area
+ route_y_max = rangelim(route_y_max, 0, ar.Y-1);
-// Shouldn't be used, provided for compatibility.
-v2f base_ground_turbulence(u64 seed, v3f p)
-{
- double tfxz = get_turbulence_factor_2d(seed, v2f(p.X,p.Z));
- double tfy = get_turbulence_factor_y(seed, p.Y);
- v2f t = get_raw_turbulence(seed, p);
- return t*tfxz*tfy;
-}
+ if(bruise_surface)
+ {
+ /*// Minimum is at y=0
+ route_y_min = -of.Y - 0;*/
+ // Minimum is at y=max_tunnel_diameter/4
+ //route_y_min = -of.Y + max_tunnel_diameter/4;
+ //s16 min = -of.Y + max_tunnel_diameter/4;
+ s16 min = -of.Y + 0;
+ route_y_min = myrand_range(min, min + max_tunnel_diameter);
+ route_y_min = rangelim(route_y_min, 0, route_y_max);
+ }
-#if 0
-v2f base_ground_turbulence(u64 seed, v3f p)
-{
-#if 1
- double f = 8;
+ /*dstream<<"route_y_min = "<<route_y_min
+ <<", route_y_max = "<<route_y_max<<std::endl;*/
-#if 1
- // Cut off at a minimum height
- {
- double d = 15;
- double min = WATER_LEVEL-5;
- if(p.Y < min)
- return v2f(0,0);
- else if(p.Y < min + d)
- f *= ((p.Y-min)/d);
- }
-#endif
+ s16 route_start_y_min = route_y_min;
+ s16 route_start_y_max = route_y_max;
-#if 1
- double vv = 0.50 + 1.0 * noise3d_perlin(
- 0.5+p.X/250,
- 0.5+p.Y/250,
- 0.5+p.Z/250,
- seed+1324381, 4, 0.5);
- double vve = rangelim(vv, 0.0, 1.0);
- /*double vv = 1.0 - 2.0 * noise3d_perlin_abs(
- 0.5+p.X/250,
- 0.5+p.Y/250,
- 0.5+p.Z/250,
- seed+1324031, 4, 0.5);
- double vve = 1.0 - exp(-MYMAX(0, vv*2.0));*/
- //double vve = rangelim(vv, 0, 1.0);
- //dstream<<"vve="<<vve<<std::endl;
-
- /*// Limit turbulence near water level
- double a = contour((p.Y-WATER_LEVEL)/10.0);
- vve = (1.-a) * vve;*/
-
- // Increase turbulence in elevated heights
- double ah = WATER_LEVEL + 30;
- if(p.Y > ah)
- {
- vve *= p.Y/ah;
- }
-#else
- double vve = 1;
-#endif
+ // Start every 2nd cave from surface
+ bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
- double v1 = f * noise3d_perlin(
- 0.5+p.X/100,
- 0.5+p.Y/100,
- 0.5+p.Z/100,
- seed+4045, 5, 0.65);
+ if(coming_from_surface)
+ {
+ route_start_y_min = -of.Y + stone_surface_max_y + 10;
+ }
+
+ route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
+ route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
- double v2 = f * noise3d_perlin(
- 0.5+p.X/100,
- 0.5+p.Y/100,
- 0.5+p.Z/100,
- seed+9495, 5, 0.65);
-
- return v2f(v1*vve, v2*vve);
-#else
- return v2f(0,0);
-#endif
-}
-#endif
+ // Randomize starting position
+ v3f orp(
+ (float)(myrand()%ar.X)+0.5,
+ (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
+ (float)(myrand()%ar.Z)+0.5
+ );
-bool is_carved(u64 seed, v3f p)
-{
-#if 1
- double v1 = noise3d_perlin_abs(
- 0.5+p.X/200,
- 0.5+p.Y/200,
- 0.5+p.Z/200,
- seed+657890854, 5, 0.7);
-
- if(v1 > 1.45)
- return true;
-#endif
+ MapNode airnode(CONTENT_AIR);
+
+ /*
+ Generate some tunnel starting from orp
+ */
+
+ for(u16 j=0; j<tunnel_routepoints; j++)
+ {
+ if(j%7==0 && bruise_surface == false)
+ {
+ main_direction = v3f(
+ ((float)(myrand()%20)-(float)10)/10,
+ ((float)(myrand()%20)-(float)10)/30,
+ ((float)(myrand()%20)-(float)10)/10
+ );
+ main_direction *= (float)myrand_range(1, 3);
+ }
- double f = 10.0;
- double y_div = 1.5;
-
- double v4 = contour(f*noise3d_perlin(
- 0.5+p.X/200,
- 0.5+p.Y/200*y_div,
- 0.5+p.Z/200,
- seed+87592, 5, 0.7));
- // Tilted 90 degrees
- double v5 = contour(f*noise3d_perlin(
- 0.5+p.X/200,
- 0.5+p.Z/200,
- 0.5+p.Y/200*y_div,
- seed+98594, 5, 0.7));
-
- double v45 = v4*v5;
- if(v45 > 2.5/f)
- return true;
-
- return false;
-}
+ // Randomize size
+ s16 min_d = min_tunnel_diameter;
+ s16 max_d = max_tunnel_diameter;
+ s16 rs = myrand_range(min_d, max_d);
+
+ v3s16 maxlen;
+ if(bruise_surface)
+ {
+ maxlen = v3s16(rs*7,rs*7,rs*7);
+ }
+ else
+ {
+ maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
+ }
-bool is_underground_mud(u64 seed, v3f p)
-{
- double v1 = noise3d_perlin_abs(
- 0.5+p.X/50,
- 0.5+p.Y/50,
- 0.5+p.Z/50,
- seed+83401, 5, 0.75);
- return (v1 > 1.3);
-}
-
-/*
- if depth_guess!=NULL, it is set to a guessed value of how deep
- underground the position is.
-*/
-bool is_base_ground(u64 seed, v3f p, double *depth_guess=NULL)
-{
-#if 0
- // This is used for testing the output of the cave function
- {
- if(depth_guess)
- *depth_guess = 10;
- if(p.Y > 50)
- return false;
- return is_carved(seed, p);
- }
-#endif
-#if 0
- // This is used for testing the output of the underground mud function
- {
- if(depth_guess)
- *depth_guess = 10;
- if(p.Y > 50)
- return false;
- return is_underground_mud(seed, p);
- }
-#endif
+ v3f vec;
+
+ if(coming_from_surface && j < 3)
+ {
+ vec = v3f(
+ (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
+ (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
+ (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
+ );
+ }
+ else
+ {
+ vec = v3f(
+ (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
+ (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
+ (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
+ );
+ }
+
+ vec += main_direction;
- bool is_ground = true;
+ v3f rp = orp + vec;
+ if(rp.X < 0)
+ rp.X = 0;
+ else if(rp.X >= ar.X)
+ rp.X = ar.X-1;
+ if(rp.Y < route_y_min)
+ rp.Y = route_y_min;
+ else if(rp.Y >= route_y_max)
+ rp.Y = route_y_max-1;
+ if(rp.Z < 0)
+ rp.Z = 0;
+ else if(rp.Z >= ar.Z)
+ rp.Z = ar.Z-1;
+ vec = rp - orp;
-#if 1
- if(is_carved(seed, p))
- is_ground = false;
-#endif
-
- if(depth_guess || is_ground == true)
- {
- v2f t = base_ground_turbulence(seed, p);
+ 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);
- double surface_y_f = base_rock_level_2d(seed, v2f(p.X+t.X, p.Z+t.Y));
+ s16 d0 = -rs/2;
+ s16 d1 = d0 + rs - 1;
+ for(s16 z0=d0; z0<=d1; z0++)
+ {
+ //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
+ s16 si = rs - MYMAX(0, abs(z0)-rs/7);
+ for(s16 x0=-si; x0<=si-1; x0++)
+ {
+ s16 maxabsxz = MYMAX(abs(x0), abs(z0));
+ //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
+ s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
+ //s16 si2 = rs - abs(x0);
+ for(s16 y0=-si2+1+2; 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(data->vmanip.m_area.contains(p));
+ if(data->vmanip.m_area.contains(p) == false)
+ {
+ dstream<<"WARNING: "<<__FUNCTION_NAME
+ <<":"<<__LINE__<<": "
+ <<"point not in area"
+ <<std::endl;
+ continue;
+ }
+
+ // Just set it to air, it will be changed to
+ // water afterwards
+ u32 i = data->vmanip.m_area.index(p);
+ data->vmanip.m_data[i] = airnode;
-#if 0
- if(depth_guess)
- {
- // Find highest surface near current
- v3f dirs[4] = {
- v3f(1,0,0),
- v3f(-1,0,0),
- v3f(0,0,1),
- v3f(0,0,-1)
- };
- double s2 = surface_y_f;
- for(u32 i=0; i<4; i++)
- {
- v3f dir = dirs[i];
- // Get turbulence at around there
- v2f t2 = base_ground_turbulence(seed, p+dir);
- // Get ground height
- v2f l = v2f(p.X+t2.X+dir.X, p.Z+t2.Y+dir.Z);
- double s = base_rock_level_2d(seed, l);
- if(s > s2)
- s2 = s;
+ if(bruise_surface == false)
+ {
+ // Set tunnel flag
+ data->vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
+ }
+ }
+ }
+ }
}
- *depth_guess = s2 - p.Y;
- }
-#endif
-#if 1
- if(depth_guess)
- {
- // Check a bit lower also, take highest surface
- v2f t2 = base_ground_turbulence(seed, p + v3f(0,-2,0));
- double s2 = base_rock_level_2d(seed, v2f(p.X+t2.X, p.Z+t2.Y));
- if(s2 > surface_y_f)
- *depth_guess = s2 - p.Y;
- else
- *depth_guess = surface_y_f - p.Y;
- }
-#endif
-#if 0
- if(depth_guess)
- *depth_guess = surface_y_f - p.Y;
-#endif
- if(p.Y > surface_y_f)
- is_ground = false;
- }
+ orp = rp;
+ }
- /*if(depth_guess)
- {
- // Guess surface point
- v3f p2(p.X, surface_y_f, p.Z);
- v2f t2 = base_ground_turbulence
- double u1 =
- double s1 = base_rock_level_2d(seed, v2f(p.X+v1,p.Z+v2));
- }*/
+ }
- return is_ground;
-}
+ }//timer1
+#endif
-#define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
+#if 1
+ {
+ // 46ms @cs=8
+ //TimeTaker timer1("ore veins");
-/*
- This is the main map generation method
-*/
-
-#if 0
-MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks,
- bool force)
-{
- DSTACK(__FUNCTION_NAME);
-
- // Shall be not used now
- //assert(0);
-
-#if 0
-
- /*
- Don't generate if already fully generated
- */
- if(force == false)
- {
- MapChunk *chunk = getChunk(chunkpos);
- if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
- {
- dstream<<"generateChunkRaw(): Chunk "
- <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
- <<" already generated"<<std::endl;
- return chunk;
- }
- }
-
- dstream<<"generateChunkRaw(): Generating chunk "
- <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
- <<std::endl;
-
- TimeTaker timer("generateChunkRaw()");
-
- // The distance how far into the neighbors the generator is allowed to go.
- s16 max_spread_amount_sectors = 2;
- assert(max_spread_amount_sectors <= m_chunksize);
- s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
-
- // Minimum amount of space left on sides for mud to fall in
- //s16 min_mud_fall_space = 2;
-
- // Maximum diameter of stone obstacles in X and Z
- /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
- assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
-
- s16 y_blocks_min = -4;
- s16 y_blocks_max = 3;
- s16 h_blocks = y_blocks_max - y_blocks_min + 1;
- s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
- s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
-
- v2s16 sectorpos_base = chunk_to_sector(chunkpos);
- s16 sectorpos_base_size = m_chunksize;
-
- /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
- s16 sectorpos_bigbase_size = m_chunksize * 3;*/
- v2s16 sectorpos_bigbase =
- sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
- s16 sectorpos_bigbase_size =
- sectorpos_base_size + 2 * max_spread_amount_sectors;
-
- v3s16 bigarea_blocks_min(
- sectorpos_bigbase.X,
- y_blocks_min,
- sectorpos_bigbase.Y
- );
-
- v3s16 bigarea_blocks_max(
- sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
- y_blocks_max,
- sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
- );
-
- // Relative values to control amount of stuff in one chunk
- /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
- u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)h_blocks*MAP_BLOCKSIZE;
-
- /*
- The limiting edges of the lighting update, inclusive.
- */
- 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 chunks
- */
- {
- TimeTaker timer("generateChunkRaw() create area");
-
- for(s16 x=0; x<sectorpos_bigbase_size; x++)
- for(s16 z=0; z<sectorpos_bigbase_size; z++)
- {
- v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
- ServerMapSector *sector = createSector(sectorpos);
- assert(sector);
-
- for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
- {
- v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
- MapBlock *block = createBlock(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.
-
- Actually this doesn't matter now because the
- initial lighting is done here.
- */
- block->setIsUnderground(y != y_blocks_max);
- }
- }
- }
-
/*
- Now we have a big empty area.
-
- Make a ManualMapVoxelManipulator that contains this and the
- neighboring chunks
+ Make ore veins
*/
-
- ManualMapVoxelManipulator vmanip(this);
- // Add the area we just generated
+ for(u32 jj=0; jj<relative_volume/1000; jj++)
{
- TimeTaker timer("generateChunkRaw() initialEmerge");
- vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
- }
-
- // Clear all flags
- vmanip.clearFlag(0xff);
-
- TimeTaker timer_generate("generateChunkRaw() generate");
+ s16 max_vein_diameter = 3;
- // Maximum height of the stone surface and obstacles.
- // This is used to disable dungeon generation from going too high.
- s16 stone_surface_max_y = 0;
+ // Allowed route area size in nodes
+ v3s16 ar(
+ data->sectorpos_base_size*MAP_BLOCKSIZE,
+ h_blocks*MAP_BLOCKSIZE,
+ data->sectorpos_base_size*MAP_BLOCKSIZE
+ );
- /*
- Generate general ground level to full area
- */
-
- {
- // 22ms @cs=8
- TimeTaker timer1("ground level");
- dstream<<"Generating base ground..."<<std::endl;
+ // Area starting point in nodes
+ v3s16 of(
+ data->sectorpos_base.X*MAP_BLOCKSIZE,
+ data->y_blocks_min*MAP_BLOCKSIZE,
+ data->sectorpos_base.Y*MAP_BLOCKSIZE
+ );
- for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
- for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
- {
- // Node position
- v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
+ // Allow a bit more
+ //(this should be more than the maximum radius of the tunnel)
+ s16 insure = 3;
+ s16 more = data->max_spread_amount - max_vein_diameter/2 - insure;
+ ar += v3s16(1,0,1) * more * 2;
+ of -= v3s16(1,0,1) * more;
- /*
- Skip if already generated
- */
- {
- v3s16 p(p2d.X, y_nodes_min, p2d.Y);
- if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
- continue;
- }
-
- v2f p2df(p2d.X, p2d.Y);
-
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- s16 min = y_nodes_min;
- s16 max = y_nodes_max;
- /*s16 min = -10;
- s16 max = 20;*/
- //float surface_y_f = base_rock_level_2d(m_seed, p2df);
- u32 i = vmanip.m_area.index(v3s16(p2d.X, min, p2d.Y));
- for(s16 y=min; y<=max; y++)
- {
-#if 1
- bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
- if(is)
- vmanip.m_data[i].d = CONTENT_STONE;
- else
- vmanip.m_data[i].d = CONTENT_AIR;
-#endif
-#if 0
- double v = noise3d_perlin(
- 0.5+(float)p2d.X/200,
- 0.5+(float)y/200,
- 0.5+(float)p2d.Y/200,
- m_seed+293, 6, 0.55);
- if(v > 0.0)
- vmanip.m_data[i].d = CONTENT_STONE;
- else
- vmanip.m_data[i].d = CONTENT_AIR;
-#endif
-#if 0
- /*double v1 = 5 * noise3d_perlin(
- 0.5+(float)p2df.X/200,
- 0.5+(float)y/200,
- 0.5+(float)p2df.Y/200,
- m_seed+293, 6, 0.55);
-
- double v2 = 5 * noise3d_perlin(
- 0.5+(float)p2df.X/200,
- 0.5+(float)y/200,
- 0.5+(float)p2df.Y/200,
- m_seed+293, 6, 0.55);*/
-
- double v1 = 0;
- double v2 = 0;
-
- float surface_y_f = base_rock_level_2d(m_seed, p2df+v2f(v1,v2));
-
- if(y <= surface_y_f)
- vmanip.m_data[i].d = CONTENT_STONE;
- else
- vmanip.m_data[i].d = CONTENT_AIR;
-#endif
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
+ // Randomize starting position
+ v3f orp(
+ (float)(myrand()%ar.X)+0.5,
+ (float)(myrand()%ar.Y)+0.5,
+ (float)(myrand()%ar.Z)+0.5
+ );
-#if 0
- // Node position
- v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
+ // Randomize mineral
+ u8 mineral;
+ if(myrand()%3 != 0)
+ mineral = MINERAL_COAL;
+ else
+ mineral = MINERAL_IRON;
/*
- Skip if already generated
+ Generate some vein starting from orp
*/
- {
- v3s16 p(p2d.X, y_nodes_min, p2d.Y);
- if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
- continue;
- }
-
- // Ground height at this point
- float surface_y_f = 0.0;
- // Use perlin noise for ground height
- surface_y_f = base_rock_level_2d(m_seed, p2d);
-
- /*// Experimental stuff
+ for(u16 j=0; j<2; j++)
{
- float a = highlands_level_2d(m_seed, p2d);
- if(a > surface_y_f)
- surface_y_f = a;
- }*/
-
- // Convert to integer
- s16 surface_y = (s16)surface_y_f;
-
- // Log it
- if(surface_y > stone_surface_max_y)
- stone_surface_max_y = surface_y;
+ /*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(5, 5, 5);
+ 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;
- /*
- Fill ground with stone
- */
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
- for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
- {
- vmanip.m_data[i].d = CONTENT_STONE;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
-#endif
- }
-
- }//timer1
-
- /*
- Randomize some parameters
- */
-
- s32 stone_obstacle_count = 0;
- /*s32 stone_obstacle_count =
- rangelim((1.0+noise2d(m_seed+897,
- sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
-
- s16 stone_obstacle_max_height = 0;
- /*s16 stone_obstacle_max_height =
- rangelim((1.0+noise2d(m_seed+5902,
- sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
-
- /*
- Loop this part, it will make stuff look older and newer nicely
- */
- u32 age_count = 2;
- for(u32 i_age=0; i_age<age_count; i_age++)
- { // Aging loop
-
- {
- // 8ms @cs=8
- //TimeTaker timer1("stone obstacles");
-
- /*
- Add some random stone obstacles
- */
-
- for(s32 ri=0; ri<stone_obstacle_count; ri++)
- {
- // Randomize max height so usually stuff will be quite low
- s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
-
- //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
- s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4;
-
- v3s16 ob_size(
- myrand_range(5, stone_obstacle_max_size),
- myrand_range(0, maxheight_randomized),
- myrand_range(5, stone_obstacle_max_size)
- );
-
- // Don't make stupid small rectangle bumps
- if(ob_size.Y < 5)
- continue;
-
- v2s16 ob_place(
- myrand_range(1+ob_size.X/2+2,
- sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
- myrand_range(1+ob_size.Z/2+2,
- sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
- );
-
- // Minimum space left on top of the obstacle
- s16 min_head_space = 12;
-
- for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
- for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
- {
- // Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
-
- // Find stone ground level
- // (ignore everything else than mud in already generated chunks)
- // and mud amount over the stone level
- s16 surface_y = 0;
- s16 mud_amount = 0;
- {
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y;
- // Go to ground level
- for(y=y_nodes_max; y>=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++;
- /*
- Change to mud because otherwise we might
- be throwing mud on grass at the next
- step
- */
- n->d = CONTENT_MUD;
- }
-
- 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 - min_head_space; y++)
- {
- MapNode &n = vmanip.m_data[i];
- n.d = CONTENT_STONE;
-
- if(y > stone_surface_max_y)
- stone_surface_max_y = y;
-
- count++;
- if(count >= ob_size.Y)
- break;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- // Add mud
- count = 0;
- for(; y<=y_nodes_max - min_head_space; 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);
- }
- }
-
- }
- }
-
- }//timer1
- {
- // 24ms @cs=8
- //TimeTaker timer1("dungeons");
-
- /*
- Make dungeons
- */
- u32 dungeons_count = relative_volume / 600000;
- u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
- if(stone_surface_max_y < WATER_LEVEL)
- bruises_count = 0;
- /*u32 dungeons_count = 0;
- u32 bruises_count = 0;*/
- for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
- {
- s16 min_tunnel_diameter = 2;
- s16 max_tunnel_diameter = 6;
- u16 tunnel_routepoints = 25;
-
- bool bruise_surface = (jj < bruises_count);
-
- if(bruise_surface)
- {
- min_tunnel_diameter = 5;
- max_tunnel_diameter = myrand_range(10, 20);
- /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
- max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
-
- /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42,
- sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/
-
- tunnel_routepoints = 5;
- }
-
- // 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 insure = 5; // Didn't work with max_d = 20
- s16 insure = 10;
- s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
- ar += v3s16(1,0,1) * more * 2;
- of -= v3s16(1,0,1) * more;
-
- s16 route_y_min = 0;
- // Allow half a diameter + 7 over stone surface
- s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
-
- /*// If dungeons, don't go through surface too often
- if(bruise_surface == false)
- route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
-
- // Limit maximum to area
- route_y_max = rangelim(route_y_max, 0, ar.Y-1);
-
- if(bruise_surface)
- {
- /*// Minimum is at y=0
- route_y_min = -of.Y - 0;*/
- // Minimum is at y=max_tunnel_diameter/4
- //route_y_min = -of.Y + max_tunnel_diameter/4;
- //s16 min = -of.Y + max_tunnel_diameter/4;
- s16 min = -of.Y + 0;
- route_y_min = myrand_range(min, min + max_tunnel_diameter);
- route_y_min = rangelim(route_y_min, 0, route_y_max);
- }
-
- /*dstream<<"route_y_min = "<<route_y_min
- <<", route_y_max = "<<route_y_max<<std::endl;*/
-
- s16 route_start_y_min = route_y_min;
- s16 route_start_y_max = route_y_max;
-
- // Start every 2nd dungeon from surface
- bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
-
- if(coming_from_surface)
- {
- route_start_y_min = -of.Y + stone_surface_max_y + 5;
- }
-
- route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
- route_start_y_max = rangelim(route_start_y_max, 0, ar.Y-1);
-
- // Randomize starting position
- v3f orp(
- (float)(myrand()%ar.X)+0.5,
- (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
- (float)(myrand()%ar.Z)+0.5
- );
-
- MapNode airnode(CONTENT_AIR);
-
- /*
- Generate some tunnel starting from orp
- */
-
- for(u16 j=0; j<tunnel_routepoints; j++)
- {
- // Randomize size
- s16 min_d = min_tunnel_diameter;
- s16 max_d = max_tunnel_diameter;
- s16 rs = myrand_range(min_d, max_d);
-
- v3s16 maxlen;
- if(bruise_surface)
- {
- maxlen = v3s16(rs*7,rs*7,rs*7);
- }
- else
- {
- maxlen = v3s16(15, myrand_range(1, 20), 15);
- }
-
- v3f vec;
-
- if(coming_from_surface && j < 3)
- {
- vec = v3f(
- (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
- (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
- (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
- );
- }
- else
- {
- vec = v3f(
- (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-1;
- if(rp.Y < route_y_min)
- rp.Y = route_y_min;
- else if(rp.Y >= route_y_max)
- rp.Y = route_y_max-1;
- if(rp.Z < 0)
- rp.Z = 0;
- else if(rp.Z >= ar.Z)
- rp.Z = ar.Z-1;
- vec = rp - orp;
-
- for(float f=0; f<1.0; f+=1.0/vec.getLength())
+ // 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 - MYMAX(0, abs(z0)-rs/4);
- s16 si = rs - MYMAX(0, abs(z0)-rs/7);
+ s16 si = rs - abs(z0);
for(s16 x0=-si; x0<=si-1; x0++)
{
- s16 maxabsxz = MYMAX(abs(x0), abs(z0));
- //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
- s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
- //s16 si2 = rs - abs(x0);
- for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
+ 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;
continue;
p += of;
- //assert(vmanip.m_area.contains(p));
- if(vmanip.m_area.contains(p) == false)
- {
- dstream<<"WARNING: "<<__FUNCTION_NAME
- <<":"<<__LINE__<<": "
- <<"point not in area"
- <<std::endl;
- continue;
- }
+ assert(data->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;
-
- if(bruise_surface == false)
- {
- // Set tunnel flag
- vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
- }
- }
- }
- }
- }
-
- orp = rp;
- }
-
- }
-
- }//timer1
- {
- // 46ms @cs=8
- //TimeTaker timer1("ore veins");
-
- /*
- Make ore veins
- */
- for(u32 jj=0; jj<relative_volume/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 insure = 3;
- s16 more = max_spread_amount - max_vein_diameter/2 - insure;
- 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;
- if(myrand()%3 != 0)
- mineral = MINERAL_COAL;
- else
- mineral = MINERAL_IRON;
-
- /*
- 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(5, 5, 5);
- 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;
- }
-
- }
-
- }//timer1
- {
- // 15ms @cs=8
- //TimeTaker timer1("add mud");
-
- /*
- Add mud to the central chunk
- */
-
- 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);
-
- // Randomize mud amount
- s16 mud_add_amount = get_mud_amount(m_seed, v2f(p2d.X,p2d.Y))/age_count;
-
- // Find ground level
- s16 surface_y = find_ground_level_clever(vmanip, p2d);
-
- /*
- If topmost node is grass, change it to mud.
- It might be if it was flown to there from a neighboring
- chunk and then converted.
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
- if(n->d == CONTENT_GRASS)
- n->d = CONTENT_MUD;
- }
-
- /*
- Add mud on ground
- */
- {
- s16 mudcount = 0;
- 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));
- for(s16 y=y_start; y<=y_nodes_max; y++)
- {
- if(mudcount >= mud_add_amount)
- break;
-
- MapNode &n = vmanip.m_data[i];
- n.d = CONTENT_MUD;
- mudcount++;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
-
- }
-
- }//timer1
- {
- // 340ms @cs=8
- //TimeTaker timer1("flow mud");
-
- /*
- Flow mud away from steep edges
- */
-
- // Limit area by 1 because mud is flown into neighbors.
- s16 mudflow_minpos = 0-max_spread_amount+1;
- s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
-
- // Iterate a few times
- for(s16 k=0; k<3; k++)
- {
-
- for(s16 x=mudflow_minpos;
- x<=mudflow_maxpos;
- x++)
- for(s16 z=mudflow_minpos;
- z<=mudflow_maxpos;
- z++)
- {
- // Invert coordinates every 2nd iteration
- if(k%2 == 0)
- {
- x = mudflow_maxpos - (x-mudflow_minpos);
- z = mudflow_maxpos - (z-mudflow_minpos);
- }
-
- // Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
-
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y=y_nodes_max;
-
- for(;; y--)
- {
- MapNode *n = NULL;
- // Find mud
- for(; y>=y_nodes_min; y--)
- {
- n = &vmanip.m_data[i];
- //if(content_walkable(n->d))
- // break;
- if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
-
- // Stop if out of area
- //if(vmanip.m_area.contains(i) == false)
- if(y < y_nodes_min)
- break;
-
- /*// If not mud, do nothing to it
- MapNode *n = &vmanip.m_data[i];
- if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
- continue;*/
-
- /*
- Don't flow it if the stuff under it is not mud
- */
- {
- u32 i2 = i;
- vmanip.m_area.add_y(em, i2, -1);
- // Cancel if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- MapNode *n2 = &vmanip.m_data[i2];
- if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
- continue;
- }
-
- // Make it exactly mud
- n->d = CONTENT_MUD;
-
- /*s16 recurse_count = 0;
- mudflow_recurse:*/
-
- v3s16 dirs4[4] = {
- v3s16(0,0,1), // back
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(-1,0,0), // left
- };
-
- // Theck that upper is air or doesn't exist.
- // Cancel dropping if upper keeps it in place
- u32 i3 = i;
- vmanip.m_area.add_y(em, i3, 1);
- if(vmanip.m_area.contains(i3) == true
- && content_walkable(vmanip.m_data[i3].d) == true)
- {
- continue;
- }
-
- // Drop mud on side
-
- for(u32 di=0; di<4; di++)
- {
- v3s16 dirp = dirs4[di];
- u32 i2 = i;
- // Move to side
- vmanip.m_area.add_p(em, i2, dirp);
- // Fail if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- // Check that side is air
- 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);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(content_walkable(n2->d))
- continue;
- /*// Check that under that is air (need a drop of 2)
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- 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);
- // Fail if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- 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);
-
- // Done
- break;
- }
- }
- }
-
- }
-
- }//timer1
- {
- // 50ms @cs=8
- //TimeTaker timer1("add water");
-
- /*
- Add water to the central chunk (and a bit more)
- */
-
- for(s16 x=0-max_spread_amount;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
- x++)
- for(s16 z=0-max_spread_amount;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
- z++)
- {
- // Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
-
- // Find ground level
- //s16 surface_y = find_ground_level(vmanip, p2d);
-
- /*
- If ground level is over water level, skip.
- NOTE: This leaves caves near water without water,
- which looks especially crappy when the nearby water
- won't start flowing either for some reason
- */
- /*if(surface_y > WATER_LEVEL)
- continue;*/
-
- /*
- Add water on ground
- */
- {
- v3s16 em = vmanip.m_area.getExtent();
- u8 light = LIGHT_MAX;
- // Start at global water surface level
- s16 y_start = WATER_LEVEL;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
-
- /*// Add first one to transforming liquid queue, if water
- if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
- {
- v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
- m_transforming_liquid.push_back(p);
- }*/
-
- for(s16 y=y_start; y>=y_nodes_min; y--)
- {
- n = &vmanip.m_data[i];
-
- // Stop when there is no water and no air
- if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
- && n->d != CONTENT_WATER)
- {
- /*// Add bottom one to transforming liquid queue
- vmanip.m_area.add_y(em, i, 1);
- n = &vmanip.m_data[i];
- if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- m_transforming_liquid.push_back(p);
- }*/
-
- break;
- }
-
- // Make water only not in dungeons
- if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
- {
- 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--;
- }
- }
-
- }
-
- }//timer1
-
- } // Aging loop
-
- {
- //TimeTaker timer1("convert mud to sand");
-
- /*
- Convert mud to sand
- */
-
- //s16 mud_add_amount = myrand_range(2, 4);
- //s16 mud_add_amount = 0;
-
- /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
- for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
- for(s16 x=0-max_spread_amount+1;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- x++)
- for(s16 z=0-max_spread_amount+1;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- 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(p2d);
-
- 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);
- }
- }
-
- }
-
- }//timer1
- {
- // 1ms @cs=8
- //TimeTaker timer1("generate trees");
-
- /*
- Generate some trees
- */
- {
- // Divide area into parts
- s16 div = 8;
- 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;
- 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);
- }
- }
- /*u32 tree_max = relative_area / 60;
- //u32 count = myrand_range(0, tree_max);
- for(u32 i=0; i<count; i++)
- {
- s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
- s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
- x += sectorpos_base.X*MAP_BLOCKSIZE;
- z += sectorpos_base.Y*MAP_BLOCKSIZE;
- s16 y = find_ground_level(vmanip, v2s16(x,z));
- // Don't make a tree under water level
- if(y < WATER_LEVEL)
- continue;
- v3s16 p(x,y+1,z);
- // Make a tree
- make_tree(vmanip, p);
- }*/
- }
-
- }//timer1
-
- {
- // 19ms @cs=8
- //TimeTaker timer1("grow grass");
-
- /*
- Grow grass
- */
-
- /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
- for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
- for(s16 x=0-max_spread_amount;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
- x++)
- for(s16 z=0-max_spread_amount;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
- z++)
- {
- // Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
-
- /*
- Find the lowest surface to which enough light ends up
- to make grass grow.
-
- Basically just wait until not air and not leaves.
- */
- s16 surface_y = 0;
- {
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y;
- // Go to ground level
- for(y=y_nodes_max; y>=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;
- }
-
- }//timer1
-
- /*
- Initial lighting (sunlight)
- */
-
- core::map<v3s16, bool> light_sources;
-
- {
- // 750ms @cs=8, can't optimize more
- TimeTaker timer1("initial lighting");
-
-#if 0
- /*
- Go through the edges and add all nodes that have light to light_sources
- */
-
- // 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);
-
- {
- 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(n->getLight(LIGHTBANK_DAY) != 0)
- {
- light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
- }
- //NOTE: This is broken, at least the index has to
- // be incremented
- }
- }
- }
-#endif
-
-#if 1
- /*
- 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);
- }
- }
- }
-#endif
-
- /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
- for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
- /*for(s16 x=0-max_spread_amount+1;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- x++)
- for(s16 z=0-max_spread_amount+1;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
- z++)*/
-#if 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;
+ u32 i = data->vmanip.m_area.index(p);
+ MapNode *n = &data->vmanip.m_data[i];
+ if(n->d == CONTENT_STONE)
+ n->param = mineral;
}
}
}
-
- 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);
}
+
+ orp = rp;
}
+
}
-#endif
}//timer1
+#endif
- // Spread light around
+#if 1
{
- TimeTaker timer("generateChunkRaw() spreadLight");
- vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
- }
-
- /*
- Generation ended
- */
-
- timer_generate.stop();
+ // 15ms @cs=8
+ TimeTaker timer1("add mud");
/*
- Blit generated stuff to map
+ Add mud to the central chunk
*/
+
+ for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)
{
- // 70ms @cs=8
- //TimeTaker timer("generateChunkRaw() blitBackAll");
- vmanip.blitBackAll(&changed_blocks);
- }
+ // Node position in 2d
+ v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ // Randomize mud amount
+ s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
- /*
- Update day/night difference cache of the MapBlocks
- */
- {
- for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
- i.atEnd() == false; i++)
+ // Find ground level
+ s16 surface_y = find_ground_level_clever(data->vmanip, p2d);
+
+ /*
+ If topmost node is grass, change it to mud.
+ It might be if it was flown to there from a neighboring
+ chunk and then converted.
+ */
{
- MapBlock *block = i.getNode()->getValue();
- block->updateDayNightDiff();
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
+ MapNode *n = &data->vmanip.m_data[i];
+ if(n->d == CONTENT_GRASS)
+ *n = MapNode(CONTENT_MUD);
+ //n->d = CONTENT_MUD;
+ }
+
+ /*
+ Add mud on ground
+ */
+ {
+ s16 mudcount = 0;
+ v3s16 em = data->vmanip.m_area.getExtent();
+ s16 y_start = surface_y+1;
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ for(s16 y=y_start; y<=y_nodes_max; y++)
+ {
+ if(mudcount >= mud_add_amount)
+ break;
+
+ MapNode &n = data->vmanip.m_data[i];
+ n = MapNode(CONTENT_MUD);
+ //n.d = CONTENT_MUD;
+ mudcount++;
+
+ data->vmanip.m_area.add_y(em, i, 1);
+ }
}
+
}
+ }//timer1
#endif
-
- /*
- Create chunk metadata
- */
- for(s16 x=-1; x<=1; x++)
- for(s16 y=-1; y<=1; y++)
+#if 1
{
- v2s16 chunkpos0 = chunkpos + v2s16(x,y);
- // Add chunk meta information
- MapChunk *chunk = getChunk(chunkpos0);
- if(chunk == NULL)
- {
- chunk = new MapChunk();
- m_chunks.insert(chunkpos0, chunk);
- }
- //chunk->setIsVolatile(true);
- if(chunk->getGenLevel() > GENERATED_PARTLY)
- chunk->setGenLevel(GENERATED_PARTLY);
- }
+ // 340ms @cs=8
+ TimeTaker timer1("flow mud");
/*
- Set central chunk non-volatile
- */
- MapChunk *chunk = getChunk(chunkpos);
- assert(chunk);
- // Set non-volatile
- //chunk->setIsVolatile(false);
- chunk->setGenLevel(GENERATED_FULLY);
-
- /*
- Save changed parts of map
+ Flow mud away from steep edges
*/
- save(true);
- /*
- Return central chunk (which was requested)
- */
- return chunk;
-}
-#endif
+ // Limit area by 1 because mud is flown into neighbors.
+ s16 mudflow_minpos = 0-data->max_spread_amount+1;
+ s16 mudflow_maxpos = data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-2;
-MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks,
- bool force)
-{
- DSTACK(__FUNCTION_NAME);
+ // Iterate a few times
+ for(s16 k=0; k<3; k++)
+ {
- /*
- Don't generate if already fully generated
- */
- if(force == false)
+ for(s16 x=mudflow_minpos;
+ x<=mudflow_maxpos;
+ x++)
+ for(s16 z=mudflow_minpos;
+ z<=mudflow_maxpos;
+ z++)
{
- MapChunk *chunk = getChunk(chunkpos);
- if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
+ // Invert coordinates every 2nd iteration
+ if(k%2 == 0)
{
- dstream<<"generateChunkRaw(): Chunk "
- <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
- <<" already generated"<<std::endl;
- return chunk;
+ x = mudflow_maxpos - (x-mudflow_minpos);
+ z = mudflow_maxpos - (z-mudflow_minpos);
}
- }
-
-#if 0
- dstream<<"generateChunkRaw(): Generating chunk "
- <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
- <<std::endl;
-
- TimeTaker timer("generateChunkRaw()");
-
- // The distance how far into the neighbors the generator is allowed to go.
- s16 max_spread_amount_sectors = 1;
- assert(max_spread_amount_sectors <= m_chunksize);
- s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
-
- // Minimum amount of space left on sides for mud to fall in
- //s16 min_mud_fall_space = 2;
-
- // Maximum diameter of stone obstacles in X and Z
- /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
- assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
-
- s16 y_blocks_min = -2;
- s16 y_blocks_max = 3;
- //s16 h_blocks = y_blocks_max - y_blocks_min + 1;
- s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
- s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
-
- v2s16 sectorpos_base = chunk_to_sector(chunkpos);
- s16 sectorpos_base_size = m_chunksize;
-
- /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
- s16 sectorpos_bigbase_size = m_chunksize * 3;*/
- v2s16 sectorpos_bigbase =
- sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
- s16 sectorpos_bigbase_size =
- sectorpos_base_size + 2 * max_spread_amount_sectors;
-
- v3s16 bigarea_blocks_min(
- sectorpos_bigbase.X,
- y_blocks_min,
- sectorpos_bigbase.Y
- );
- v3s16 bigarea_blocks_max(
- sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
- y_blocks_max,
- sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
- );
-
- // Relative values to control amount of stuff in one chunk
- /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
- /*u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)sectorpos_base_size*MAP_BLOCKSIZE
- *(u32)h_blocks*MAP_BLOCKSIZE;*/
+ // Node position in 2d
+ v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
- /*
- The limiting edges of the lighting update, inclusive.
- */
- s16 lighting_min_d = 0-max_spread_amount;
- s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+ v3s16 em = data->vmanip.m_area.getExtent();
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
+ s16 y=y_nodes_max;
- /*
- Create the whole area of this and the neighboring chunks
- */
- {
- TimeTaker timer("generateChunkRaw() create area");
-
- for(s16 x=0; x<sectorpos_bigbase_size; x++)
- for(s16 z=0; z<sectorpos_bigbase_size; z++)
+ for(;; y--)
{
- v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
- ServerMapSector *sector = createSector(sectorpos);
- assert(sector);
-
- for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
+ MapNode *n = NULL;
+ // Find mud
+ for(; y>=y_nodes_min; y--)
{
- v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
- MapBlock *block = createBlock(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.
-
- Actually this doesn't matter now because the
- initial lighting is done here.
- */
- block->setIsUnderground(y != y_blocks_max);
+ n = &data->vmanip.m_data[i];
+ //if(content_walkable(n->d))
+ // break;
+ if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
+ break;
+
+ data->vmanip.m_area.add_y(em, i, -1);
}
- }
- }
-
- /*
- 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("generateChunkRaw() initialEmerge");
- vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
- }
-
- // Clear all flags
- vmanip.clearFlag(0xff);
-
- TimeTaker timer_generate("generateChunkRaw() generate");
- /*
- Generate general ground level to full area
- */
-
- {
- // 22ms @cs=8
- TimeTaker timer1("ground level");
- dstream<<"Generating base ground..."<<std::endl;
+ // Stop if out of area
+ //if(data->vmanip.m_area.contains(i) == false)
+ if(y < y_nodes_min)
+ break;
- for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
- for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
- {
- // Node position
- v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
-
- /*
- Skip if already generated
- */
- {
- v3s16 p(p2d.X, y_nodes_min, p2d.Y);
- if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
- continue;
- }
+ /*// If not mud, do nothing to it
+ MapNode *n = &data->vmanip.m_data[i];
+ if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+ continue;*/
- v2f p2df(p2d.X, p2d.Y);
+ /*
+ Don't flow it if the stuff under it is not mud
+ */
+ {
+ u32 i2 = i;
+ data->vmanip.m_area.add_y(em, i2, -1);
+ // Cancel if out of area
+ if(data->vmanip.m_area.contains(i2) == false)
+ continue;
+ MapNode *n2 = &data->vmanip.m_data[i2];
+ if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
+ continue;
+ }
- s16 mud_amount = get_mud_amount(m_seed, p2df);
-
- double tfxz = get_turbulence_factor_2d(m_seed, p2df);
- bool turbulence_is_used = (tfxz > 0.001);
+ // Make it exactly mud
+ n->d = CONTENT_MUD;
+
+ /*s16 recurse_count = 0;
+ mudflow_recurse:*/
- s16 surface_y = 0;
-
- float noturb_surface_y_f = base_rock_level_2d(m_seed, p2df);
- s16 noturb_surface_y = noturb_surface_y_f;
+ v3s16 dirs4[4] = {
+ v3s16(0,0,1), // back
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(-1,0,0), // left
+ };
- {
- s16 depth_counter = 0;
- s16 min = y_nodes_min;
- s16 max = y_nodes_max;
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, max, p2d.Y));
- for(s16 y=max; y>=min; y--)
+ // Theck that upper is air or doesn't exist.
+ // Cancel dropping if upper keeps it in place
+ u32 i3 = i;
+ data->vmanip.m_area.add_y(em, i3, 1);
+ if(data->vmanip.m_area.contains(i3) == true
+ && content_walkable(data->vmanip.m_data[i3].d) == true)
{
- v3f p3df(p2df.X, y, p2df.Y);
-
- bool is_ground = false;
+ continue;
+ }
- bool turb_for_node = (turbulence_is_used
- && y >= TURBULENCE_BOTTOM_CUTOFF_Y);
-
- if(is_carved(m_seed, p3df))
- {
- is_ground = false;
- }
- else
- {
- if(turb_for_node)
- {
- double depth_guess;
- is_ground = is_base_ground(m_seed,
- p3df, &depth_guess);
-
- // Estimate the surface height
- surface_y = y + depth_guess;
- }
- else
- {
- surface_y = noturb_surface_y;
- }
-
- is_ground = (y <= surface_y);
- }
-
- if(is_ground)
- {
- //vmanip.m_data[i].d = CONTENT_STONE;
- /*if(y > surface_y - mud_amount)
- vmanip.m_data[i].d = CONTENT_MUD;
- else
- vmanip.m_data[i].d = CONTENT_STONE;*/
- if(depth_counter < mud_amount)
- vmanip.m_data[i].d = CONTENT_MUD;
- else
- vmanip.m_data[i].d = CONTENT_STONE;
- }
- else
- vmanip.m_data[i].d = CONTENT_AIR;
-
- if(is_ground || depth_counter != 0)
- depth_counter++;
+ // Drop mud on side
+
+ for(u32 di=0; di<4; di++)
+ {
+ v3s16 dirp = dirs4[di];
+ u32 i2 = i;
+ // Move to side
+ data->vmanip.m_area.add_p(em, i2, dirp);
+ // Fail if out of area
+ if(data->vmanip.m_area.contains(i2) == false)
+ continue;
+ // Check that side is air
+ MapNode *n2 = &data->vmanip.m_data[i2];
+ if(content_walkable(n2->d))
+ continue;
+ // Check that under side is air
+ data->vmanip.m_area.add_y(em, i2, -1);
+ if(data->vmanip.m_area.contains(i2) == false)
+ continue;
+ n2 = &data->vmanip.m_data[i2];
+ if(content_walkable(n2->d))
+ continue;
+ /*// Check that under that is air (need a drop of 2)
+ data->vmanip.m_area.add_y(em, i2, -1);
+ if(data->vmanip.m_area.contains(i2) == false)
+ continue;
+ n2 = &data->vmanip.m_data[i2];
+ if(content_walkable(n2->d))
+ continue;*/
+ // Loop further down until not air
+ do{
+ data->vmanip.m_area.add_y(em, i2, -1);
+ // Fail if out of area
+ if(data->vmanip.m_area.contains(i2) == false)
+ continue;
+ n2 = &data->vmanip.m_data[i2];
+ }while(content_walkable(n2->d) == false);
+ // Loop one up so that we're in air
+ data->vmanip.m_area.add_y(em, i2, 1);
+ n2 = &data->vmanip.m_data[i2];
-#if 0
-#if 1
- bool is = is_base_ground(m_seed, v3f(p2df.X,y,p2df.Y));
- if(is)
- vmanip.m_data[i].d = CONTENT_STONE;
- else
- vmanip.m_data[i].d = CONTENT_AIR;
-#endif
-#endif
+ // Move mud to new place
+ *n2 = *n;
+ // Set old place to be air
+ *n = MapNode(CONTENT_AIR);
- vmanip.m_area.add_y(em, i, -1);
+ // Done
+ break;
}
}
}
+ }
+
}//timer1
+#endif
+#if 1
{
// 50ms @cs=8
- //TimeTaker timer1("add water");
+ TimeTaker timer1("add water");
/*
Add water to the central chunk (and a bit more)
*/
- for(s16 x=0-max_spread_amount;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
+ for(s16 x=0-data->max_spread_amount;
+ x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
x++)
- for(s16 z=0-max_spread_amount;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
+ for(s16 z=0-data->max_spread_amount;
+ z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
z++)
{
// Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+ v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
// Find ground level
- //s16 surface_y = find_ground_level(vmanip, p2d);
+ //s16 surface_y = find_ground_level(data->vmanip, p2d);
/*
If ground level is over water level, skip.
Add water on ground
*/
{
- v3s16 em = vmanip.m_area.getExtent();
+ v3s16 em = data->vmanip.m_area.getExtent();
u8 light = LIGHT_MAX;
// Start at global water surface level
s16 y_start = WATER_LEVEL;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
-
- /*// Add first one to transforming liquid queue, if water
- if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
- {
- v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
- m_transforming_liquid.push_back(p);
- }*/
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ MapNode *n = &data->vmanip.m_data[i];
for(s16 y=y_start; y>=y_nodes_min; y--)
{
- n = &vmanip.m_data[i];
+ n = &data->vmanip.m_data[i];
// Stop when there is no water and no air
if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
&& n->d != CONTENT_WATER)
{
- /*// Add bottom one to transforming liquid queue
- vmanip.m_area.add_y(em, i, 1);
- n = &vmanip.m_data[i];
- if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- m_transforming_liquid.push_back(p);
- }*/
break;
}
- // Make water only not in dungeons
- if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
+ // Make water only not in caves
+ if(!(data->vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
{
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);
+ data->transforming_liquid.push_back(p);
}
// Next one
- vmanip.m_area.add_y(em, i, -1);
+ data->vmanip.m_area.add_y(em, i, -1);
if(light > 0)
light--;
}
}
}//timer1
+#endif
+
+ } // Aging loop
+ /***********************
+ END OF AGING LOOP
+ ************************/
+#if 1
{
//TimeTaker timer1("convert mud to sand");
//s16 mud_add_amount = myrand_range(2, 4);
//s16 mud_add_amount = 0;
- /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
- for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
- for(s16 x=0-max_spread_amount+1;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+ /*for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
+ for(s16 x=0-data->max_spread_amount+1;
+ x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
x++)
- for(s16 z=0-max_spread_amount+1;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+ for(s16 z=0-data->max_spread_amount+1;
+ z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
z++)
{
// Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+ v2s16 p2d = data->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));
+ double sandnoise = noise2d_perlin(
+ 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
+ data->seed+59420, 3, 0.50);
+
+ bool have_sand = (sandnoise > -0.15);
if(have_sand == false)
continue;
// Find ground level
- s16 surface_y = find_ground_level_clever(vmanip, p2d);
+ s16 surface_y = find_ground_level_clever(data->vmanip, p2d);
if(surface_y > WATER_LEVEL + 2)
continue;
{
- v3s16 em = vmanip.m_area.getExtent();
+ v3s16 em = data->vmanip.m_area.getExtent();
s16 y_start = surface_y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ u32 i = data->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];
+ MapNode *n = &data->vmanip.m_data[i];
if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
{
n->d = CONTENT_SAND;
break;
}
- vmanip.m_area.add_y(em, i, -1);
+ data->vmanip.m_area.add_y(em, i, -1);
}
}
}
}//timer1
+#endif
+
+#if 1
+ {
+ // 1ms @cs=8
+ //TimeTaker timer1("generate trees");
+
+ /*
+ Generate some trees
+ */
+ {
+ // Divide area into parts
+ s16 div = 8;
+ s16 sidelen = data->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(
+ data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
+ data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
+ );
+ // Minimum edge of part of division
+ v2s16 p2d_min(
+ data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
+ data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
+ );
+ // Maximum edge of part of division
+ v2s16 p2d_max(
+ data->sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
+ data->sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
+ );
+ // Amount of trees
+ u32 tree_count = area * tree_amount_2d(data->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(data->vmanip, v2s16(x,z));
+ // Don't make a tree under water level
+ if(y < WATER_LEVEL)
+ continue;
+ // Don't make a tree so high that it doesn't fit
+ if(y > y_nodes_max - 6)
+ continue;
+ v3s16 p(x,y,z);
+ /*
+ Trees grow only on mud and grass
+ */
+ {
+ u32 i = data->vmanip.m_area.index(v3s16(p));
+ MapNode *n = &data->vmanip.m_data[i];
+ if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+ continue;
+ }
+ p.Y++;
+ // Make a tree
+ make_tree(data->vmanip, p);
+ }
+ }
+ /*u32 tree_max = relative_area / 60;
+ //u32 count = myrand_range(0, tree_max);
+ for(u32 i=0; i<count; i++)
+ {
+ s16 x = myrand_range(0, data->sectorpos_base_size*MAP_BLOCKSIZE-1);
+ s16 z = myrand_range(0, data->sectorpos_base_size*MAP_BLOCKSIZE-1);
+ x += data->sectorpos_base.X*MAP_BLOCKSIZE;
+ z += data->sectorpos_base.Y*MAP_BLOCKSIZE;
+ s16 y = find_ground_level(data->vmanip, v2s16(x,z));
+ // Don't make a tree under water level
+ if(y < WATER_LEVEL)
+ continue;
+ v3s16 p(x,y+1,z);
+ // Make a tree
+ make_tree(data->vmanip, p);
+ }*/
+ }
+
+ }//timer1
+#endif
+#if 1
{
// 19ms @cs=8
//TimeTaker timer1("grow grass");
Grow grass
*/
- /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
- for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
- for(s16 x=0-max_spread_amount;
- x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
+ /*for(s16 x=0-4; x<data->sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
+ for(s16 z=0-4; z<data->sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
+ for(s16 x=0-data->max_spread_amount;
+ x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
x++)
- for(s16 z=0-max_spread_amount;
- z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
+ for(s16 z=0-data->max_spread_amount;
+ z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount;
z++)
{
// Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+ v2s16 p2d = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
/*
Find the lowest surface to which enough light ends up
*/
s16 surface_y = 0;
{
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
+ v3s16 em = data->vmanip.m_area.getExtent();
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
s16 y;
// Go to ground level
for(y=y_nodes_max; y>=y_nodes_min; y--)
{
- MapNode &n = vmanip.m_data[i];
+ MapNode &n = data->vmanip.m_data[i];
if(n.d != CONTENT_AIR
&& n.d != CONTENT_LEAVES)
break;
- vmanip.m_area.add_y(em, i, -1);
+ data->vmanip.m_area.add_y(em, i, -1);
}
if(y >= y_nodes_min)
surface_y = y;
surface_y = y_nodes_min;
}
- u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
- MapNode *n = &vmanip.m_data[i];
+ u32 i = data->vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
+ MapNode *n = &data->vmanip.m_data[i];
if(n->d == CONTENT_MUD)
n->d = CONTENT_GRASS;
}
}//timer1
+#endif
+
+ /*
+ Initial lighting (sunlight)
+ */
+
+ core::map<v3s16, bool> light_sources;
{
- // 1ms @cs=8
- //TimeTaker timer1("generate trees");
+ // 750ms @cs=8, can't optimize more
+ TimeTaker timer1("initial lighting");
+ // NOTE: This is no used... umm... for some reason!
+#if 0
/*
- Generate some trees
+ Go through the edges and add all nodes that have light to light_sources
*/
+
+ // Four edges
+ for(s16 i=0; i<4; i++)
+ // Edge length
+ for(s16 j=lighting_min_d;
+ j<=lighting_max_d;
+ j++)
{
- // Divide area into parts
- s16 div = 8;
- 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++)
+ 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 = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ {
+ v3s16 em = data->vmanip.m_area.getExtent();
+ s16 y_start = y_nodes_max;
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ for(s16 y=y_start; y>=y_nodes_min; y--)
+ {
+ MapNode *n = &data->vmanip.m_data[i];
+ if(n->getLight(LIGHTBANK_DAY) != 0)
+ {
+ light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
+ }
+ //NOTE: This is broken, at least the index has to
+ // be incremented
+ }
+ }
+ }
+#endif
+
+#if 1
+ /*
+ 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 = data->sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+ // Loop from top to down
{
- // 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++)
+ u8 light = LIGHT_SUN;
+ v3s16 em = data->vmanip.m_area.getExtent();
+ s16 y_start = y_nodes_max;
+ u32 i = data->vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ for(s16 y=y_start; y>=y_nodes_min; y--)
{
- 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;
- v3s16 p(x,y,z);
- /*
- Trees grow only on mud and grass
- */
+ MapNode *n = &data->vmanip.m_data[i];
+ if(light_propagates_content(n->d) == false)
{
- u32 i = vmanip.m_area.index(v3s16(p));
- MapNode *n = &vmanip.m_data[i];
- if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
- continue;
+ light = 0;
}
- p.Y++;
- // Make a tree
- make_tree(vmanip, p);
+ 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
+ data->vmanip.m_area.add_y(em, i, -1);
}
}
- /*u32 tree_max = relative_area / 60;
- //u32 count = myrand_range(0, tree_max);
- for(u32 i=0; i<count; i++)
- {
- s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
- s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
- x += sectorpos_base.X*MAP_BLOCKSIZE;
- z += sectorpos_base.Y*MAP_BLOCKSIZE;
- s16 y = find_ground_level(vmanip, v2s16(x,z));
- // Don't make a tree under water level
- if(y < WATER_LEVEL)
- continue;
- v3s16 p(x,y+1,z);
- // Make a tree
- make_tree(vmanip, p);
- }*/
}
+#endif
- }//timer1
-
-
- /*
- Initial lighting (sunlight)
- */
-
- core::map<v3s16, bool> light_sources;
-
- {
- // 750ms @cs=8, can't optimize more
- TimeTaker timer1("initial lighting");
-
+ /*for(s16 x=0; x<data->sectorpos_base_size*MAP_BLOCKSIZE; x++)
+ for(s16 z=0; z<data->sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
+ /*for(s16 x=0-data->max_spread_amount+1;
+ x<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
+ x++)
+ for(s16 z=0-data->max_spread_amount+1;
+ z<data->sectorpos_base_size*MAP_BLOCKSIZE+data->max_spread_amount-1;
+ z++)*/
#if 1
/*
This has to be 1 smaller than the actual area, because
z++)
{
// Node position in 2d
- v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+ v2s16 p2d = data->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();
+ v3s16 em = data->vmanip.m_area.getExtent();
s16 y_start = y_nodes_max;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+ u32 i = data->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];
+ MapNode *n = &data->vmanip.m_data[i];
if(light_propagates_content(n->d) == false)
{
{
v3s16 dirp = dirs4[di];
u32 i2 = i;
- vmanip.m_area.add_p(em, i2, dirp);
- MapNode *n2 = &vmanip.m_data[i2];
+ data->vmanip.m_area.add_p(em, i2, dirp);
+ MapNode *n2 = &data->vmanip.m_data[i2];
if(
n2->d != CONTENT_AIR
&& n2->d != CONTENT_WATERSOURCE
}
// Increment index by y
- vmanip.m_area.add_y(em, i, -1);
+ data->vmanip.m_area.add_y(em, i, -1);
}
}
}
// Spread light around
{
- TimeTaker timer("generateChunkRaw() spreadLight");
- vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
+ TimeTaker timer("makeChunk() spreadLight");
+ data->vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
}
/*
*/
timer_generate.stop();
+}
+
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+//###################################################################
+
+void ServerMap::initChunkMake(ChunkMakeData &data, v2s16 chunkpos)
+{
+ if(m_chunksize == 0)
+ {
+ data.no_op = true;
+ return;
+ }
+
+ data.no_op = false;
+
+ // The distance how far into the neighbors the generator is allowed to go.
+ s16 max_spread_amount_sectors = 2;
+ assert(max_spread_amount_sectors <= m_chunksize);
+ s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
+
+ s16 y_blocks_min = -4;
+ s16 y_blocks_max = 3;
+
+ v2s16 sectorpos_base = chunk_to_sector(chunkpos);
+ s16 sectorpos_base_size = m_chunksize;
+
+ v2s16 sectorpos_bigbase =
+ sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
+ s16 sectorpos_bigbase_size =
+ sectorpos_base_size + 2 * max_spread_amount_sectors;
+
+ data.seed = m_seed;
+ data.chunkpos = chunkpos;
+ data.y_blocks_min = y_blocks_min;
+ data.y_blocks_max = y_blocks_max;
+ data.sectorpos_base = sectorpos_base;
+ data.sectorpos_base_size = sectorpos_base_size;
+ data.sectorpos_bigbase = sectorpos_bigbase;
+ data.sectorpos_bigbase_size = sectorpos_bigbase_size;
+ data.max_spread_amount = max_spread_amount;
+
+ /*
+ Create the whole area of this and the neighboring chunks
+ */
+ {
+ TimeTaker timer("initChunkMake() create area");
+
+ for(s16 x=0; x<sectorpos_bigbase_size; x++)
+ for(s16 z=0; z<sectorpos_bigbase_size; z++)
+ {
+ v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
+ ServerMapSector *sector = createSector(sectorpos);
+ assert(sector);
+
+ for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
+ {
+ v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
+ MapBlock *block = createBlock(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.
+
+ Actually this doesn't matter now because the
+ initial lighting is done here.
+ */
+ block->setIsUnderground(y != y_blocks_max);
+ }
+ }
+ }
+
+ /*
+ Now we have a big empty area.
+
+ Make a ManualMapVoxelManipulator that contains this and the
+ neighboring chunks
+ */
+
+ v3s16 bigarea_blocks_min(
+ sectorpos_bigbase.X,
+ y_blocks_min,
+ sectorpos_bigbase.Y
+ );
+ v3s16 bigarea_blocks_max(
+ sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
+ y_blocks_max,
+ sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
+ );
+
+ data.vmanip.setMap(this);
+ // Add the area
+ {
+ TimeTaker timer("initChunkMake() initialEmerge");
+ data.vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
+ }
+
+}
+
+MapChunk* ServerMap::finishChunkMake(ChunkMakeData &data,
+ core::map<v3s16, MapBlock*> &changed_blocks)
+{
+ if(data.no_op)
+ return NULL;
+
/*
Blit generated stuff to map
*/
{
// 70ms @cs=8
//TimeTaker timer("generateChunkRaw() blitBackAll");
- vmanip.blitBackAll(&changed_blocks);
+ data.vmanip.blitBackAll(&changed_blocks);
}
/*
block->updateDayNightDiff();
}
}
-#endif
-
+
+ /*
+ Copy transforming liquid information
+ */
+ while(data.transforming_liquid.size() > 0)
+ {
+ v3s16 p = data.transforming_liquid.pop_front();
+ m_transforming_liquid.push_back(p);
+ }
+
+ /*
+ Add random objects to blocks
+ */
+ {
+ for(s16 x=0; x<data.sectorpos_base_size; x++)
+ for(s16 z=0; z<data.sectorpos_base_size; z++)
+ {
+ v2s16 sectorpos = data.sectorpos_base + v2s16(x,z);
+ ServerMapSector *sector = createSector(sectorpos);
+ assert(sector);
+
+ for(s16 y=data.y_blocks_min; y<=data.y_blocks_max; y++)
+ {
+ v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
+ MapBlock *block = createBlock(blockpos);
+ addRandomObjects(block);
+ }
+ }
+ }
+
/*
Create chunk metadata
*/
for(s16 x=-1; x<=1; x++)
for(s16 y=-1; y<=1; y++)
{
- v2s16 chunkpos0 = chunkpos + v2s16(x,y);
+ v2s16 chunkpos0 = data.chunkpos + v2s16(x,y);
// Add chunk meta information
MapChunk *chunk = getChunk(chunkpos0);
if(chunk == NULL)
/*
Set central chunk non-volatile
*/
- MapChunk *chunk = getChunk(chunkpos);
+ MapChunk *chunk = getChunk(data.chunkpos);
assert(chunk);
// Set non-volatile
//chunk->setIsVolatile(false);
Save changed parts of map
*/
save(true);
+
+ return chunk;
+}
+
+#if 0
+// NOTE: Deprecated
+MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ bool force)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ /*
+ Don't generate if already fully generated
+ */
+ if(force == false)
+ {
+ MapChunk *chunk = getChunk(chunkpos);
+ if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
+ {
+ dstream<<"generateChunkRaw(): Chunk "
+ <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
+ <<" already generated"<<std::endl;
+ return chunk;
+ }
+ }
+
+ dstream<<"generateChunkRaw(): Generating chunk "
+ <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
+ <<std::endl;
+
+ TimeTaker timer("generateChunkRaw()");
+
+ ChunkMakeData data;
+
+ // Initialize generation
+ initChunkMake(data, chunkpos);
+
+ // Generate stuff
+ makeChunk(&data);
+
+ // Finalize generation
+ MapChunk *chunk = finishChunkMake(data, changed_blocks);
/*
Return central chunk (which was requested)
return chunk;
}
-
+// NOTE: Deprecated
MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
core::map<v3s16, MapBlock*> &changed_blocks)
{
<<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
<<std::endl;
- // Shall be not used now
- //assert(0);
-
/*for(s16 x=-1; x<=1; x++)
for(s16 y=-1; y<=1; y++)*/
for(s16 x=-0; x<=0; x++)
MapChunk *chunk = getChunk(chunkpos1);
return chunk;
}
+#endif
ServerMapSector * ServerMap::createSector(v2s16 p2d)
{
- DSTACK("%s: p2d=(%d,%d)",
+ DSTACKF("%s: p2d=(%d,%d)",
__FUNCTION_NAME,
p2d.X, p2d.Y);
return sector;
}
+#if 0
MapSector * ServerMap::emergeSector(v2s16 p2d,
core::map<v3s16, MapBlock*> &changed_blocks)
{
<<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
<<std::endl;
+#if 0
+ dstream<<"WARNING: Creating an empty sector."<<std::endl;
+
+ return createSector(p2d);
+
+#endif
+
#if 1
dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
- //assert(0);
-#endif
-
-#if 1
- dstream<<"WARNING: Creating an empty sector."<<std::endl;
-
- return createSector(p2d);
-
+ assert(0);
#endif
/*
*/
//return generateSector();
}
+#endif
/*
NOTE: This is not used for main map generation, only for blocks
- that are very high or low.
- NOTE: Now it is used mainly. Might change in the future.
+ that are very high or low
*/
MapBlock * ServerMap::generateBlock(
v3s16 p,
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
)
{
- DSTACK("%s: p=(%d,%d,%d)",
+ DSTACKF("%s: p=(%d,%d,%d)",
__FUNCTION_NAME,
p.X, p.Y, p.Z);
+
+ // If chunks are disabled
+ /*if(m_chunksize == 0)
+ {
+ dstream<<"ServerMap::generateBlock(): Chunks disabled -> "
+ <<"not generating."<<std::endl;
+ return NULL;
+ }*/
/*dstream<<"generateBlock(): "
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
v2s16 p2d(p.X, p.Z);
s16 block_y = p.Y;
v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
- v3s16 p_nodes = p * MAP_BLOCKSIZE;
/*
Do not generate over-limit
block->unDummify();
}
+#if 0
+ /*
+ Generate a completely empty block
+ */
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ {
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+ {
+ MapNode n;
+ n.d = CONTENT_AIR;
+ block->setNode(v3s16(x0,y0,z0), n);
+ }
+ }
+#else
+ /*
+ Generate a proper block
+ */
+
u8 water_material = CONTENT_WATERSOURCE;
s32 lowest_ground_y = 32767;
s32 highest_ground_y = -32768;
-
- enum{
- BT_GROUND,
- BT_SURFACE,
- BT_SKY
- } block_type = BT_SURFACE;
-
- {// ground_timer (0ms or ~100ms)
- TimeTaker ground_timer("Ground generation");
-
- /*
- 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.
- */
-
+
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
- /*
- 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;
+ //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
- 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;
- }
+ //s16 surface_y = 0;
- float block_low_y_f = p_nodes_f.Y;
- float block_high_y_f = p_nodes_f.Y + MAP_BLOCKSIZE;
+ s16 mud_add_amount = get_mud_add_amount(m_seed, p2d_nodes+v2s16(x0,z0));
- /*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;
+ s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
+ + mud_add_amount;
+ // If chunks are disabled
+ if(m_chunksize == 0)
+ surface_y = WATER_LEVEL + 1;
- 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(surface_y < lowest_ground_y)
+ lowest_ground_y = surface_y;
+ if(surface_y > highest_ground_y)
+ highest_ground_y = surface_y;
- if(/*block_type == BT_GROUND ||*/ block_type == BT_SKY)
- {
- lowest_ground_y = surface_y_min;
- highest_ground_y = surface_y_max;
- }
- }
-
- if(block_type == BT_SURFACE || block_type == BT_GROUND)
- {
- /*
- Generate ground precisely
- */
+ s32 surface_depth = AVERAGE_MUD_AMOUNT;
- for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
{
- //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
-
- //s16 surface_y = 0;
-
- /*s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
- + AVERAGE_MUD_AMOUNT;
-
- if(surface_y < lowest_ground_y)
- lowest_ground_y = surface_y;
- if(surface_y > highest_ground_y)
- highest_ground_y = surface_y;*/
-
- v2s16 real_p2d = v2s16(x0,z0) + p2d*MAP_BLOCKSIZE;
-
- v2f real_p2d_f(real_p2d.X,real_p2d.Y);
-
- s16 surface_depth = get_mud_amount(m_seed, real_p2d_f);
-
- 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;
+ s16 real_y = block_y * MAP_BLOCKSIZE + y0;
+ MapNode n;
+ /*
+ Calculate lighting
- // 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;
-
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- {
- #if 1
- s16 real_y = block_y * MAP_BLOCKSIZE + y0;
- v3s16 real_pos = v3s16(x0,y0,z0) + p_nodes;
- MapNode n;
- /*
- Calculate lighting
-
- NOTE: If there are some man-made structures above the
- newly created block, they won't be taken into account.
- */
- /*if(real_y > surface_y)
- n.setLight(LIGHTBANK_DAY, LIGHT_SUN);*/
+ NOTE: If there are some man-made structures above the
+ newly created block, they won't be taken into account.
+ */
+ if(real_y > surface_y)
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
- /*
- 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);
+ /*
+ Calculate material
+ */
- bool is_cavern = false;
-
- if(is_carved(m_seed, real_pos_f))
+ // If node is over heightmap y, it's air or water
+ if(real_y > surface_y)
+ {
+ // If under water level, it's water
+ if(real_y < WATER_LEVEL)
{
- is_ground = false;
- if(real_y < noturb_surface_y)
- is_cavern = true;
+ n.d = water_material;
+ n.setLight(LIGHTBANK_DAY,
+ diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
+ /*
+ Add to transforming liquid queue (in case it'd
+ start flowing)
+ */
+ v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
+ m_transforming_liquid.push_back(real_pos);
}
+ // else air
else
+ n.d = CONTENT_AIR;
+ }
+ // Else it's ground or caves (air)
+ else
+ {
+ // If it's surface_depth under ground, it's stone
+ if(real_y <= surface_y - surface_depth)
{
- 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;
-
- // Get 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;
+ n.d = CONTENT_STONE;
}
- // Else it's ground or dungeons (air)
else
{
- // If it's surface_depth under ground, it's stone
- if((float)real_y <= surface_y_f - surface_depth - 0.75)
+ // It is mud if it is under the first ground
+ // level or under water
+ if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
{
- if(is_underground_mud(m_seed, real_pos_f))
- n.d = CONTENT_MUD;
- else
- n.d = CONTENT_STONE;
- }
- else if(surface_y_f <= WATER_LEVEL + 2.1
- && get_have_sand_coast(m_seed, real_p2d_f))
- {
- n.d = CONTENT_SAND;
+ n.d = CONTENT_MUD;
}
else
{
- /*// It is mud if it is under the first ground
- // level or under water
- if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
- {
- n.d = CONTENT_MUD;
- }
- else
- {
- n.d = CONTENT_GRASS;
- }*/
-
- if(get_have_sand_ground(m_seed, real_p2d_f))
- n.d = CONTENT_SAND;
- else
- n.d = CONTENT_MUD;
-
- /*// If under water level, it's mud
- if(real_y < WATER_LEVEL)
- n.d = CONTENT_MUD;
- // Only the topmost node is grass
- else if(real_y <= surface_y - 1)
- n.d = CONTENT_MUD;
- else
- n.d = CONTENT_GRASS;*/
+ n.d = CONTENT_GRASS;
}
- }
- block->setNode(v3s16(x0,y0,z0), n);
- #endif
- #if 0
- s16 real_y = block_y * MAP_BLOCKSIZE + y0;
- MapNode n;
- /*
- Calculate lighting
+ //n.d = CONTENT_MUD;
- NOTE: If there are some man-made structures above the
- newly created block, they won't be taken into account.
- */
- if(real_y > surface_y)
- n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
-
- /*
- Calculate material
- */
-
- // If node is over heightmap y, it's air or water
- if(real_y > surface_y)
- {
- // If under water level, it's water
+ /*// If under water level, it's mud
if(real_y < WATER_LEVEL)
- {
- n.d = water_material;
- n.setLight(LIGHTBANK_DAY,
- diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
- /*
- Add to transforming liquid queue (in case it'd
- start flowing)
- */
- v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
- m_transforming_liquid.push_back(real_pos);
- }
- // else air
- else
- n.d = CONTENT_AIR;
- }
- // Else it's ground or dungeons (air)
- else
- {
- // If it's surface_depth under ground, it's stone
- if(real_y <= surface_y - surface_depth)
- {
- n.d = CONTENT_STONE;
- }
+ n.d = CONTENT_MUD;
+ // Only the topmost node is grass
+ else if(real_y <= surface_y - 1)
+ n.d = CONTENT_MUD;
else
- {
- // It is mud if it is under the first ground
- // level or under water
- if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
- {
- n.d = CONTENT_MUD;
- }
- else
- {
- n.d = CONTENT_GRASS;
- }
-
- //n.d = CONTENT_MUD;
-
- /*// If under water level, it's mud
- if(real_y < WATER_LEVEL)
- n.d = CONTENT_MUD;
- // Only the topmost node is grass
- else if(real_y <= surface_y - 1)
- n.d = CONTENT_MUD;
- else
- n.d = CONTENT_GRASS;*/
- }
+ n.d = CONTENT_GRASS;*/
}
-
- block->setNode(v3s16(x0,y0,z0), n);
- #endif
}
- }
- }// BT_SURFACE
- else // BT_GROUND, 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 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- {
- //MapNode n = block->getNode(v3s16(x0,y0,z0));
- block->setNode(v3s16(x0,y0,z0), n_fill);
+ block->setNode(v3s16(x0,y0,z0), n);
}
}
- }// ground_timer
-
/*
Calculate some helper variables
*/
//dstream<<"generateBlock(): Getting local attributes"<<std::endl;
- //float caves_amount = 0.5;
+ float caves_amount = 0.5;
#if 0
{
//dstream<<"generateBlock(): Done"<<std::endl;
-#if 0
- // Set to true if has caves.
- // Set when some non-air is changed to air when making caves.
- bool has_dungeons = false;
-
/*
- Generate dungeons
+ Generate caves
*/
// Initialize temporary table
}
// Fill table
-#if 0
+#if 1
{
/*
Initialize orp and ors. Try to find if some neighboring
continue_generating:
/*
- Choose whether to actually generate dungeon
+ Choose whether to actually generate cave
*/
- bool do_generate_dungeons = true;
+ bool do_generate_caves = true;
// Don't generate if no part is underground
if(!some_part_underground)
{
- do_generate_dungeons = false;
+ do_generate_caves = false;
}
// Don't generate if mostly underwater surface
/*else if(mostly_underwater_surface)
{
- do_generate_dungeons = false;
+ do_generate_caves = false;
}*/
// Partly underground = cave
else if(!completely_underground)
{
- //do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
- do_generate_dungeons = false;
+ do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
}
- // Found existing dungeon underground
+ // Found existing cave underground
else if(found_existing && completely_underground)
{
- do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
+ do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
}
- // Underground and no dungeons found
+ // Underground and no caves found
else
{
- do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
+ do_generate_caves = (rand() % 300 <= (s32)(caves_amount*100));
}
- if(do_generate_dungeons)
+ if(do_generate_caves)
{
/*
Generate some tunnel starting from orp and ors
}
#endif
+ // Set to true if has caves.
+ // Set when some non-air is changed to air when making caves.
+ bool has_caves = false;
+
/*
Apply temporary cave data to block
*/
{
MapNode n = block->getNode(v3s16(x0,y0,z0));
- // Create dungeons
+ // Create caves
if(underground_emptiness[
ued*ued*(z0*ued/MAP_BLOCKSIZE)
+ued*(y0*ued/MAP_BLOCKSIZE)
if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
{
// Has now caves
- has_dungeons = true;
+ has_caves = true;
// Set air to node
n.d = CONTENT_AIR;
}
block->setNode(v3s16(x0,y0,z0), n);
}
}
-#endif
/*
This is used for guessing whether or not the block should
Force lighting update if some part of block is partly
underground and has caves.
*/
- /*if(some_part_underground && !completely_underground && has_dungeons)
+ /*if(some_part_underground && !completely_underground && has_caves)
{
//dstream<<"Half-ground caves"<<std::endl;
lighting_invalidated_blocks[block->getPos()] = block;
/*
Add coal
*/
- u16 coal_amount = 60;
- u16 coal_rareness = 120 / coal_amount;
+ u16 coal_amount = 30;
+ u16 coal_rareness = 60 / coal_amount;
if(coal_rareness == 0)
coal_rareness = 1;
if(myrand()%coal_rareness == 0)
/*
Add iron
*/
- u16 iron_amount = 40;
- u16 iron_rareness = 80 / iron_amount;
+ //TODO: change to iron_amount or whatever
+ u16 iron_amount = 15;
+ u16 iron_rareness = 60 / iron_amount;
if(iron_rareness == 0)
iron_rareness = 1;
if(myrand()%iron_rareness == 0)
}
}
}
+
+#endif // end of proper block generation
/*
- Add block to sector
+ Add block to sector.
*/
sector->insertBlock(block);
- // Lighting is invalid after generation for surface blocks
- if(block_type == BT_SURFACE)
- {
-#if 1
- block->setLightingExpired(true);
- lighting_invalidated_blocks.insert(p, block);
-#else
- block->setLightingExpired(false);
-#endif
- }
- // Lighting is not invalid for other blocks
- else
- {
- block->setLightingExpired(false);
- }
-
- /*
- Add trees
- */
-#if 1
- if(some_part_underground && !completely_underground)
- {
- MapVoxelManipulator vm(this);
-
- double a = tree_amount_2d(m_seed, v2s16(p_nodes.X+8, p_nodes.Z+8));
- u16 tree_count = (u16)(a*MAP_BLOCKSIZE*MAP_BLOCKSIZE);
- for(u16 i=0; i<tree_count/2; i++)
- {
- v3s16 tree_p = p_nodes + v3s16(
- myrand_range(0,MAP_BLOCKSIZE-1),
- 8,
- myrand_range(0,MAP_BLOCKSIZE-1)
- );
- double depth_guess;
- /*bool is_ground =*/ is_base_ground(m_seed,
- intToFloat(tree_p, 1), &depth_guess);
- tree_p.Y += (depth_guess - 0.5);
- if(tree_p.Y <= WATER_LEVEL)
- continue;
- make_tree(vm, tree_p);
- }
-
- vm.blitBack(changed_blocks);
- }
-#endif
+ // Lighting is invalid after generation.
+ block->setLightingExpired(true);
#if 0
/*
*/
dstream
<<"lighting_invalidated_blocks.size()"
- <<", has_dungeons"
+ <<", has_caves"
<<", completely_ug"
<<", some_part_ug"
<<" "<<lighting_invalidated_blocks.size()
- <<", "<<has_dungeons
+ <<", "<<has_caves
<<", "<<completely_underground
<<", "<<some_part_underground
<<std::endl;
MapBlock * ServerMap::createBlock(v3s16 p)
{
- DSTACK("%s: p=(%d,%d,%d)",
+ DSTACKF("%s: p=(%d,%d,%d)",
__FUNCTION_NAME, p.X, p.Y, p.Z);
/*
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
)
{
- DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
+ DSTACKF("%s: p=(%d,%d,%d), only_from_disk=%d",
__FUNCTION_NAME,
p.X, p.Y, p.Z, only_from_disk);
if(does_not_exist)
{
block = generateBlock(p, block, sector, changed_blocks,
- lighting_invalidated_blocks);
-
- lighting_expired = block->getLightingExpired();
+ lighting_invalidated_blocks);
}
if(lighting_expired)
Initially update sunlight
*/
- if(lighting_expired)
{
core::map<v3s16, bool> light_sources;
bool black_air_left = false;
/*
Plan B: Get from map generator perlin noise function
*/
- double level = base_rock_level_2d(m_seed, p2d);
+ // This won't work if proper generation is disabled
+ if(m_chunksize == 0)
+ return WATER_LEVEL+2;
+ double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
return (s16)level;
}
-void ServerMap::createDir(std::string path)
+void ServerMap::createDirs(std::string path)
{
- if(fs::CreateDir(path) == false)
+ if(fs::CreateAllDirs(path) == false)
{
m_dout<<DTIME<<"ServerMap: Failed to create directory "
<<"\""<<path<<"\""<<std::endl;
}
}
-std::string ServerMap::getSectorSubDir(v2s16 pos)
+std::string ServerMap::getSectorDir(v2s16 pos, int layout)
{
char cc[9];
- snprintf(cc, 9, "%.4x%.4x",
- (unsigned int)pos.X&0xffff,
- (unsigned int)pos.Y&0xffff);
+ switch(layout)
+ {
+ case 1:
+ snprintf(cc, 9, "%.4x%.4x",
+ (unsigned int)pos.X&0xffff,
+ (unsigned int)pos.Y&0xffff);
- return std::string(cc);
-}
+ return m_savedir + "/sectors/" + cc;
+ case 2:
+ snprintf(cc, 9, "%.3x/%.3x",
+ (unsigned int)pos.X&0xfff,
+ (unsigned int)pos.Y&0xfff);
-std::string ServerMap::getSectorDir(v2s16 pos)
-{
- return m_savedir + "/sectors/" + getSectorSubDir(pos);
+ return m_savedir + "/sectors2/" + cc;
+ default:
+ assert(false);
+ }
}
v2s16 ServerMap::getSectorPos(std::string dirname)
{
- if(dirname.size() != 8)
- throw InvalidFilenameException("Invalid sector directory name");
unsigned int x, y;
- int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
- if(r != 2)
- throw InvalidFilenameException("Invalid sector directory name");
+ int r;
+ size_t spos = dirname.rfind('/') + 1;
+ assert(spos != std::string::npos);
+ if(dirname.size() - spos == 8)
+ {
+ // Old layout
+ r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
+ }
+ else if(dirname.size() - spos == 3)
+ {
+ // New layout
+ r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
+ // Sign-extend the 12 bit values up to 16 bits...
+ if(x&0x800) x|=0xF000;
+ if(y&0x800) y|=0xF000;
+ }
+ else
+ {
+ assert(false);
+ }
+ assert(r == 2);
v2s16 pos((s16)x, (s16)y);
return pos;
}
dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
<<std::endl;
- saveMapMeta();
- saveChunkMeta();
+ if(only_changed == false || m_map_metadata_changed)
+ {
+ saveMapMeta();
+ }
+
+ // Disable saving chunk metadata if chunks are disabled
+ if(m_chunksize != 0)
+ {
+ if(only_changed == false || anyChunkModified())
+ saveChunkMeta();
+ }
u32 sector_meta_count = 0;
u32 block_count = 0;
{ //sectorlock
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
for(; i.atEnd() == false; i++)
}
}
+#if 0
+// NOTE: Doing this is insane. Deprecated and probably broken.
void ServerMap::loadAll()
{
DSTACK(__FUNCTION_NAME);
dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
s32 counter = 0;
s32 printed_counter = -100000;
}
dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
}
+#endif
#if 0
void ServerMap::saveMasterHeightmap()
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
<<std::endl;
- createDir(m_savedir);
+ createDirs(m_savedir);
std::string fullpath = m_savedir + "/map_meta.txt";
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
os<<"[end_of_params]\n";
+ m_map_metadata_changed = false;
}
void ServerMap::loadMapMeta()
{
DSTACK(__FUNCTION_NAME);
- dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
+ dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
<<std::endl;
std::string fullpath = m_savedir + "/map_meta.txt";
{
dstream<<"ERROR: ServerMap::loadMapMeta(): "
<<"could not open"<<fullpath<<std::endl;
- throw FileNotGoodException("Cannot open chunk metadata");
+ throw FileNotGoodException("Cannot open map metadata");
}
Settings params;
void ServerMap::saveChunkMeta()
{
DSTACK(__FUNCTION_NAME);
+
+ // This should not be called if chunks are disabled.
+ assert(m_chunksize != 0);
u32 count = m_chunks.size();
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
<<count<<" chunks"<<std::endl;
- createDir(m_savedir);
+ createDirs(m_savedir);
std::string fullpath = m_savedir + "/chunk_meta";
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
// Write chunk data
chunk->serialize(os, version);
}
+
+ setChunksNonModified();
}
void ServerMap::loadChunkMeta()
u8 version = SER_FMT_VER_HIGHEST;
// Get destination
v2s16 pos = sector->getPos();
- createDir(m_savedir);
- createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(pos);
- createDir(dir);
+ createDirs(dir);
std::string fullpath = dir + "/meta";
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
sector->differs_from_disk = false;
}
-MapSector* ServerMap::loadSectorMeta(std::string dirname)
+MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);
// Get destination
- v2s16 p2d = getSectorPos(dirname);
- std::string dir = m_savedir + "/sectors/" + dirname;
-
- std::string fullpath = dir + "/meta";
+ v2s16 p2d = getSectorPos(sectordir);
+
+ ServerMapSector *sector = NULL;
+
+ std::string fullpath = sectordir + "/meta";
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false)
- throw FileNotGoodException("Cannot open sector metafile");
-
- ServerMapSector *sector = ServerMapSector::deSerialize
- (is, this, p2d, m_sectors);
+ {
+ // If the directory exists anyway, it probably is in some old
+ // format. Just go ahead and create the sector.
+ if(fs::PathExists(sectordir))
+ {
+ dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
+ <<fullpath<<" doesn't exist but directory does."
+ <<" Continuing with a sector with no metadata."
+ <<std::endl;
+ sector = new ServerMapSector(this, p2d);
+ m_sectors.insert(p2d, sector);
+ }
+ else
+ {
+ throw FileNotGoodException("Cannot open sector metafile");
+ }
+ }
+ else
+ {
+ sector = ServerMapSector::deSerialize
+ (is, this, p2d, m_sectors);
+ if(save_after_load)
+ saveSectorMeta(sector);
+ }
sector->differs_from_disk = false;
bool ServerMap::loadSectorFull(v2s16 p2d)
{
DSTACK(__FUNCTION_NAME);
- std::string sectorsubdir = getSectorSubDir(p2d);
MapSector *sector = NULL;
- JMutexAutoLock lock(m_sector_mutex);
+ // The directory layout we're going to load from.
+ // 1 - original sectors/xxxxzzzz/
+ // 2 - new sectors2/xxx/zzz/
+ // If we load from anything but the latest structure, we will
+ // immediately save to the new one, and remove the old.
+ int loadlayout = 1;
+ std::string sectordir1 = getSectorDir(p2d, 1);
+ std::string sectordir;
+ if(fs::PathExists(sectordir1))
+ {
+ sectordir = sectordir1;
+ }
+ else
+ {
+ loadlayout = 2;
+ sectordir = getSectorDir(p2d, 2);
+ }
+
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
try{
- sector = loadSectorMeta(sectorsubdir);
+ sector = loadSectorMeta(sectordir, loadlayout != 2);
}
catch(InvalidFilenameException &e)
{
Load blocks
*/
std::vector<fs::DirListNode> list2 = fs::GetDirListing
- (m_savedir+"/sectors/"+sectorsubdir);
+ (sectordir);
std::vector<fs::DirListNode>::iterator i2;
for(i2=list2.begin(); i2!=list2.end(); i2++)
{
if(i2->dir)
continue;
try{
- loadBlock(sectorsubdir, i2->name, sector);
+ loadBlock(sectordir, i2->name, sector, loadlayout != 2);
}
catch(InvalidFilenameException &e)
{
// This catches unknown crap in directory
}
}
+
+ if(loadlayout != 2)
+ {
+ dstream<<"Sector converted to new layout - deleting "<<
+ sectordir1<<std::endl;
+ fs::RecursiveDelete(sectordir1);
+ }
+
return true;
}
+
void ServerMap::saveBlock(MapBlock *block)
{
DSTACK(__FUNCTION_NAME);
// Get destination
v3s16 p3d = block->getPos();
v2s16 p2d(p3d.X, p3d.Z);
- createDir(m_savedir);
- createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(p2d);
- createDir(dir);
+ createDirs(dir);
- // Block file is map/sectors/xxxxxxxx/xxxx
char cc[5];
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
std::string fullpath = dir + "/" + cc;
block->serializeObjects(o, version);
}
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ {
+ block->m_static_objects.serialize(o);
+ }
+
// We just wrote it to the disk
block->resetChangedFlag();
}
-void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
+void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);
+ std::string fullpath = sectordir+"/"+blockfile;
try{
- // Block file is map/sectors/xxxxxxxx/xxxx
- std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false)
throw FileNotGoodException("Cannot open block file");
-
+
v3s16 p3d = getBlockPos(sectordir, blockfile);
v2s16 p2d(p3d.X, p3d.Z);
block->updateObjects(is, version, NULL, 0);
}
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ {
+ block->m_static_objects.deSerialize(is);
+ }
+
if(created_new)
sector->insertBlock(block);
*/
// Save old format blocks in new format
- if(version < SER_FMT_VER_HIGHEST)
+ if(version < SER_FMT_VER_HIGHEST || save_after_load)
{
saveBlock(block);
}
"(SerializationError). Ignoring. "
"A new one will be generated."
<<std::endl;
+
+ // TODO: Backup file; name is in fullpath.
}
}
ClientMapSector *sector = new ClientMapSector(this, p2d);
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector);
}
DSTACK(__FUNCTION_NAME);
ClientMapSector *sector = NULL;
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
{
sector = new ClientMapSector(this, p2d);
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector);
}
}
*/
int time1 = time(0);
- u32 daynight_ratio = m_client->getDayNightRatio();
+ //u32 daynight_ratio = m_client->getDayNightRatio();
m_camera_mutex.Lock();
v3f camera_position = m_camera_position;
continue;
}
- // This is ugly
+ // This is ugly (spherical distance limit?)
/*if(m_control.range_all == false &&
d - 0.5*BS*MAP_BLOCKSIZE > range)
continue;*/
#if 1
/*
Update expired mesh (used for day/night change)
+
+ It doesn't work exactly like it should now with the
+ tasked mesh update but whatever.
*/
bool mesh_expired = false;
mesh_update_count++;
// Mesh has been expired: generate new mesh
- //block->updateMeshes(daynight_i);
- block->updateMesh(daynight_ratio);
+ //block->updateMesh(daynight_ratio);
+ m_client->addUpdateMeshTask(block->getPos());
mesh_expired = false;
}
- /*
- Don't draw an expired mesh that is far away
- */
- /*if(mesh_expired && d >= faraway)
- //if(mesh_expired)
- {
- // Instead, delete it
- JMutexAutoLock lock(block->mesh_mutex);
- if(block->mesh)
- {
- block->mesh->drop();
- block->mesh = NULL;
- }
- // And continue to next block
- continue;
- }*/
#endif
/*
Draw the faces of the block
void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
{
+ assert(mapType() == MAPTYPE_CLIENT);
+
try{
v3s16 p = blockpos + v3s16(0,0,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh(daynight_ratio);
+ //b->setMeshExpired(true);
}
catch(InvalidPositionException &e){}
// Leading edge
v3s16 p = blockpos + v3s16(-1,0,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh(daynight_ratio);
+ //b->setMeshExpired(true);
}
catch(InvalidPositionException &e){}
try{
v3s16 p = blockpos + v3s16(0,-1,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh(daynight_ratio);
+ //b->setMeshExpired(true);
}
catch(InvalidPositionException &e){}
try{
v3s16 p = blockpos + v3s16(0,0,-1);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh(daynight_ratio);
+ //b->setMeshExpired(true);
}
catch(InvalidPositionException &e){}
}
+#if 0
/*
Update mesh of block in which the node is, and if the node is at the
leading edge, update the appropriate leading blocks too.
b->updateMesh(daynight_ratio);
}
}
+#endif
void ClientMap::PrintInfo(std::ostream &out)
{
}
ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
- MapVoxelManipulator(map)
+ MapVoxelManipulator(map),
+ m_create_area(false)
{
}