New map generator added (and SQLite, messed up the commits at that time...) (import from temporary git repo)

This commit is contained in:
Perttu Ahola 2011-06-25 04:25:14 +03:00
parent 47e4eda4bb
commit 7538b4c620
29 changed files with 135053 additions and 2913 deletions

1
.gitignore vendored

@ -1,4 +1,5 @@
map/* map/*
world/*
CMakeFiles/* CMakeFiles/*
src/CMakeFiles/* src/CMakeFiles/*
src/Makefile src/Makefile

0
data/gravel.png Normal file

0
data/mossycobble.png Normal file

@ -131,6 +131,7 @@ include_directories(
${CMAKE_BUILD_TYPE} ${CMAKE_BUILD_TYPE}
${PNG_INCLUDE_DIR} ${PNG_INCLUDE_DIR}
"${PROJECT_SOURCE_DIR}/jthread" "${PROJECT_SOURCE_DIR}/jthread"
"${PROJECT_SOURCE_DIR}/sqlite"
) )
set(EXECUTABLE_OUTPUT_PATH ../bin) set(EXECUTABLE_OUTPUT_PATH ../bin)
@ -149,6 +150,7 @@ if(BUILD_CLIENT)
${PLATFORM_LIBS} ${PLATFORM_LIBS}
${CLIENT_PLATFORM_LIBS} ${CLIENT_PLATFORM_LIBS}
jthread jthread
sqlite3
) )
endif(BUILD_CLIENT) endif(BUILD_CLIENT)
@ -159,6 +161,7 @@ if(BUILD_SERVER)
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${PLATFORM_LIBS} ${PLATFORM_LIBS}
jthread jthread
sqlite3
) )
endif(BUILD_SERVER) endif(BUILD_SERVER)
@ -249,5 +252,6 @@ endif(BUILD_SERVER)
# Subdirectories # Subdirectories
add_subdirectory(jthread) add_subdirectory(jthread)
add_subdirectory(sqlite)
#end #end

@ -220,12 +220,12 @@ void Client::step(float dtime)
g_settings.getFloat("client_delete_unused_sectors_timeout"); g_settings.getFloat("client_delete_unused_sectors_timeout");
// Delete sector blocks // Delete sector blocks
/*u32 num = m_env.getMap().deleteUnusedSectors /*u32 num = m_env.getMap().unloadUnusedData
(delete_unused_sectors_timeout, (delete_unused_sectors_timeout,
true, &deleted_blocks);*/ true, &deleted_blocks);*/
// Delete whole sectors // Delete whole sectors
u32 num = m_env.getMap().deleteUnusedSectors u32 num = m_env.getMap().unloadUnusedData
(delete_unused_sectors_timeout, (delete_unused_sectors_timeout,
false, &deleted_blocks); false, &deleted_blocks);
@ -722,7 +722,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
*/ */
//dstream<<"Updating"<<std::endl; //dstream<<"Updating"<<std::endl;
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version);
//block->setChangedFlag();
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{ {
@ -733,7 +732,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
block = new MapBlock(&m_env.getMap(), p); block = new MapBlock(&m_env.getMap(), p);
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version);
sector->insertBlock(block); sector->insertBlock(block);
//block->setChangedFlag();
//DEBUG //DEBUG
/*NodeMod mod; /*NodeMod mod;
@ -744,27 +742,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
block->setTempMod(v3s16(8,8,8), mod); block->setTempMod(v3s16(8,8,8), mod);
block->setTempMod(v3s16(8,7,8), mod); block->setTempMod(v3s16(8,7,8), mod);
block->setTempMod(v3s16(8,6,8), mod);*/ block->setTempMod(v3s16(8,6,8), mod);*/
#if 0
/*
Add some coulds
Well, this is a dumb way to do it, they should just
be drawn as separate objects. But the looks of them
can be tested this way.
*/
if(p.Y == 3)
{
NodeMod mod;
mod.type = NODEMOD_CHANGECONTENT;
mod.param = CONTENT_CLOUD;
v3s16 p2;
p2.Y = 8;
for(p2.X=3; p2.X<=13; p2.X++)
for(p2.Z=3; p2.Z<=13; p2.Z++)
{
block->setTempMod(p2, mod);
}
}
#endif
} }
} //envlock } //envlock
@ -796,6 +773,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
/*
Add it to mesh update queue and set it to be acknowledged after update.
*/
addUpdateMeshTaskWithEdge(p, true); addUpdateMeshTaskWithEdge(p, true);
} }
else if(command == TOCLIENT_PLAYERPOS) else if(command == TOCLIENT_PLAYERPOS)

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapblock.h" #include "content_mapblock.h"
#include "content_mapnode.h" #include "content_mapnode.h"
#include "main.h" // For g_settings and g_texturesource #include "main.h" // For g_settings and g_texturesource
#include "mineral.h"
#ifndef SERVER #ifndef SERVER
// Create a cuboid. // Create a cuboid.
@ -129,6 +130,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
bool new_style_water = g_settings.getBool("new_style_water"); bool new_style_water = g_settings.getBool("new_style_water");
bool new_style_leaves = g_settings.getBool("new_style_leaves"); bool new_style_leaves = g_settings.getBool("new_style_leaves");
//bool smooth_lighting = g_settings.getBool("smooth_lighting"); //bool smooth_lighting = g_settings.getBool("smooth_lighting");
bool invisible_stone = g_settings.getBool("invisible_stone");
float node_water_level = 1.0; float node_water_level = 1.0;
if(new_style_water) if(new_style_water)
@ -178,6 +180,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
g_texturesource->getTextureId("wood.png")); g_texturesource->getTextureId("wood.png"));
material_wood.setTexture(0, pa_wood.atlas); material_wood.setTexture(0, pa_wood.atlas);
// General ground material for special output
// Texture is modified just before usage
video::SMaterial material_general;
material_general.setFlag(video::EMF_LIGHTING, false);
material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
material_general.setFlag(video::EMF_FOG_ENABLE, true);
material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
for(s16 z=0; z<MAP_BLOCKSIZE; z++) for(s16 z=0; z<MAP_BLOCKSIZE; z++)
for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 y=0; y<MAP_BLOCKSIZE; y++)
for(s16 x=0; x<MAP_BLOCKSIZE; x++) for(s16 x=0; x<MAP_BLOCKSIZE; x++)
@ -824,6 +834,88 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
} }
} }
#if 1
/*
Add stones with minerals if stone is invisible
*/
else if(n.d == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE)
{
for(u32 j=0; j<6; j++)
{
// NOTE: Hopefully g_6dirs[j] is the right direction...
v3s16 dir = g_6dirs[j];
/*u8 l = 0;
MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + dir);
if(content_features(n2.d).param_type == CPT_LIGHT)
l = decode_light(n2.getLightBlend(data->m_daynight_ratio));
else
l = 255;*/
u8 l = 255;
video::SColor c(255,l,l,l);
// Get the right texture
TileSpec ts = n.getTile(dir);
AtlasPointer ap = ts.texture;
material_general.setTexture(0, ap.atlas);
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
if(j == 0)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(0);
}
else if(j == 1)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(180);
}
else if(j == 2)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-90);
}
else if(j == 3)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(90);
}
else if(j == 4)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(-90);
}
else if(j == 5)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(90);
}
for(u16 i=0; i<4; i++)
{
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_general, vertices, 4, indices, 6);
}
}
#endif
} }
} }

@ -36,6 +36,7 @@ void content_mapnode_init()
// Read some settings // Read some settings
bool new_style_water = g_settings.getBool("new_style_water"); bool new_style_water = g_settings.getBool("new_style_water");
bool new_style_leaves = g_settings.getBool("new_style_leaves"); bool new_style_leaves = g_settings.getBool("new_style_leaves");
bool invisible_stone = g_settings.getBool("invisible_stone");
u8 i; u8 i;
ContentFeatures *f = NULL; ContentFeatures *f = NULL;
@ -48,6 +49,8 @@ void content_mapnode_init()
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0); setStoneLikeDiggingProperties(f->digging_properties, 1.0);
if(invisible_stone)
f->solidness = 0; // For debugging, hides regular stone
i = CONTENT_GRASS; i = CONTENT_GRASS;
f = &content_features(i); f = &content_features(i);
@ -81,11 +84,21 @@ void content_mapnode_init()
i = CONTENT_SAND; i = CONTENT_SAND;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("sand.png"); f->setAllTextures("sand.png");
f->setInventoryTextureCube("sand.png", "sand.png", "sand.png");
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0); setDirtLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_GRAVEL;
f = &content_features(i);
f->setAllTextures("gravel.png");
f->setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.75);
i = CONTENT_TREE; i = CONTENT_TREE;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("tree.png"); f->setAllTextures("tree.png");
@ -146,6 +159,7 @@ void content_mapnode_init()
i = CONTENT_WOOD; i = CONTENT_WOOD;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("wood.png"); f->setAllTextures("wood.png");
f->setInventoryTextureCube("wood.png", "wood.png", "wood.png");
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.75); setWoodLikeDiggingProperties(f->digging_properties, 0.75);
@ -153,6 +167,7 @@ void content_mapnode_init()
i = CONTENT_MESE; i = CONTENT_MESE;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("mese.png"); f->setAllTextures("mese.png");
f->setInventoryTextureCube("mese.png", "mese.png", "mese.png");
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.5); setStoneLikeDiggingProperties(f->digging_properties, 0.5);
@ -160,6 +175,7 @@ void content_mapnode_init()
i = CONTENT_CLOUD; i = CONTENT_CLOUD;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("cloud.png"); f->setAllTextures("cloud.png");
f->setInventoryTextureCube("cloud.png", "cloud.png", "cloud.png");
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
@ -190,7 +206,8 @@ void content_mapnode_init()
i = CONTENT_WATERSOURCE; i = CONTENT_WATERSOURCE;
f = &content_features(i); f = &content_features(i);
f->setInventoryTexture("water.png"); //f->setInventoryTexture("water.png");
f->setInventoryTextureCube("water.png", "water.png", "water.png");
if(new_style_water) if(new_style_water)
{ {
f->solidness = 0; // drawn separately, makes no faces f->solidness = 0; // drawn separately, makes no faces
@ -229,7 +246,7 @@ void content_mapnode_init()
f->wall_mounted = true; f->wall_mounted = true;
f->air_equivalent = true; f->air_equivalent = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
f->light_source = LIGHT_MAX; f->light_source = LIGHT_MAX-1;
f->digging_properties.set("", DiggingProperties(true, 0.0, 0)); f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
i = CONTENT_SIGN_WALL; i = CONTENT_SIGN_WALL;
@ -280,7 +297,16 @@ void content_mapnode_init()
f->param_type = CPT_NONE; f->param_type = CPT_NONE;
f->is_ground_content = true; f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0); setStoneLikeDiggingProperties(f->digging_properties, 0.9);
i = CONTENT_MOSSYCOBBLE;
f = &content_features(i);
f->setAllTextures("mossycobble.png");
f->setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
i = CONTENT_STEEL; i = CONTENT_STEEL;
f = &content_features(i); f = &content_features(i);

@ -48,6 +48,8 @@ void content_mapnode_init();
#define CONTENT_STEEL 19 #define CONTENT_STEEL 19
#define CONTENT_GLASS 20 #define CONTENT_GLASS 20
#define CONTENT_FENCE 21 #define CONTENT_FENCE 21
#define CONTENT_MOSSYCOBBLE 22
#define CONTENT_GRAVEL 23
#endif #endif

@ -69,6 +69,7 @@ void set_default_settings()
g_settings.setDefault("invert_mouse", "false"); g_settings.setDefault("invert_mouse", "false");
g_settings.setDefault("enable_farmesh", "false"); g_settings.setDefault("enable_farmesh", "false");
g_settings.setDefault("enable_clouds", "true"); g_settings.setDefault("enable_clouds", "true");
g_settings.setDefault("invisible_stone", "false");
// Server stuff // Server stuff
g_settings.setDefault("enable_experimental", "false"); g_settings.setDefault("enable_experimental", "false");
@ -81,8 +82,8 @@ void set_default_settings()
g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2"); g_settings.setDefault("active_object_range", "2");
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1"); //g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "2"); g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "8"); g_settings.setDefault("max_simultaneous_block_sends_server_total", "8");
g_settings.setDefault("max_block_send_distance", "8"); g_settings.setDefault("max_block_send_distance", "8");
g_settings.setDefault("max_block_generate_distance", "8"); g_settings.setDefault("max_block_generate_distance", "8");

@ -579,6 +579,64 @@ void spawnRandomObjects(MapBlock *block)
} }
#endif #endif
void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
{
// Get time difference
u32 dtime_s = 0;
u32 stamp = block->getTimestamp();
if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
dtime_s = m_game_time - block->getTimestamp();
dtime_s += additional_dtime;
// Set current time as timestamp (and let it set ChangedFlag)
block->setTimestamp(m_game_time);
//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
// Activate stored objects
activateObjects(block);
// Run node metadata
bool changed = block->m_node_metadata.step((float)dtime_s);
if(changed)
{
MapEditEvent event;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = block->getPos();
m_map->dispatchEvent(&event);
block->setChangedFlag();
}
// TODO: Do something
// TODO: Implement usage of ActiveBlockModifier
// Here's a quick demonstration
v3s16 p0;
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
{
v3s16 p = p0 + block->getPosRelative();
MapNode n = block->getNodeNoEx(p0);
// Test something:
// Convert all mud under proper day lighting to grass
if(n.d == CONTENT_MUD)
{
if(dtime_s > 300)
{
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
if(content_features(n_top.d).air_equivalent &&
n_top.getLight(LIGHTBANK_DAY) >= 13)
{
n.d = CONTENT_GRASS;
m_map->addNodeWithEvent(p, n);
}
}
}
}
}
void ServerEnvironment::step(float dtime) void ServerEnvironment::step(float dtime)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -715,60 +773,8 @@ void ServerEnvironment::step(float dtime)
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if(block==NULL) if(block==NULL)
continue; continue;
// Get time difference
u32 dtime_s = 0;
u32 stamp = block->getTimestamp();
if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
dtime_s = m_game_time - block->getTimestamp();
// Set current time as timestamp (and let it set ChangedFlag) activateBlock(block);
block->setTimestamp(m_game_time);
//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
// Activate stored objects
activateObjects(block);
// Run node metadata
bool changed = block->m_node_metadata.step((float)dtime_s);
if(changed)
{
MapEditEvent event;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = p;
m_map->dispatchEvent(&event);
block->setChangedFlag();
}
// TODO: Do something
// TODO: Implement usage of ActiveBlockModifier
// Here's a quick demonstration
v3s16 p0;
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
{
v3s16 p = p0 + block->getPosRelative();
MapNode n = block->getNodeNoEx(p0);
// Test something:
// Convert all mud under proper day lighting to grass
if(n.d == CONTENT_MUD)
{
if(dtime_s > 300)
{
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
if(content_features(n_top.d).air_equivalent &&
n_top.getLight(LIGHTBANK_DAY) >= 13)
{
n.d = CONTENT_GRASS;
m_map->addNodeWithEvent(p, n);
}
}
}
}
} }
} }
@ -867,6 +873,22 @@ void ServerEnvironment::step(float dtime)
} }
} }
} }
/*
Convert grass into mud if under something else than air
*/
else if(n.d == CONTENT_GRASS)
{
//if(myrand()%20 == 0)
{
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
if(n_top.d != CONTENT_AIR
&& n_top.d != CONTENT_IGNORE)
{
n.d = CONTENT_MUD;
m_map->addNodeWithEvent(p, n);
}
}
}
} }
} }
} }

@ -197,6 +197,12 @@ public:
*/ */
ActiveObjectMessage getActiveObjectMessage(); ActiveObjectMessage getActiveObjectMessage();
/*
Activate objects and dynamically modify for the dtime determined
from timestamp and additional_dtime
*/
void activateBlock(MapBlock *block, u32 additional_dtime=0);
/* /*
ActiveBlockModifiers (TODO) ActiveBlockModifiers (TODO)
------------------------------------------- -------------------------------------------

@ -33,8 +33,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Temporarily exposed map generator stuff Temporarily exposed map generator stuff
Should only be used for testing Should only be used for testing
*/ */
extern double base_rock_level_2d(u64 seed, v2s16 p); //extern double base_rock_level_2d(u64 seed, v2s16 p);
extern double get_mud_add_amount(u64 seed, v2s16 p); //extern double get_mud_add_amount(u64 seed, v2s16 p);
extern s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision);
extern bool get_have_sand(u64 seed, v2s16 p2d); extern bool get_have_sand(u64 seed, v2s16 p2d);
extern double tree_amount_2d(u64 seed, v2s16 p); extern double tree_amount_2d(u64 seed, v2s16 p);
@ -126,8 +127,11 @@ HeightPoint ground_height(u64 seed, v2s16 p2d)
if(n) if(n)
return n->getValue(); return n->getValue();
HeightPoint hp; HeightPoint hp;
hp.gh = BS*base_rock_level_2d(seed, p2d); s16 level = find_ground_level_from_noise(seed, p2d, 3);
hp.ma = BS*get_mud_add_amount(seed, p2d); hp.gh = (level-4)*BS;
hp.ma = (4)*BS;
/*hp.gh = BS*base_rock_level_2d(seed, p2d);
hp.ma = BS*get_mud_add_amount(seed, p2d);*/
hp.have_sand = get_have_sand(seed, p2d); hp.have_sand = get_have_sand(seed, p2d);
if(hp.gh > BS*WATER_LEVEL) if(hp.gh > BS*WATER_LEVEL)
hp.tree_amount = tree_amount_2d(seed, p2d); hp.tree_amount = tree_amount_2d(seed, p2d);
@ -136,7 +140,7 @@ HeightPoint ground_height(u64 seed, v2s16 p2d)
// No mud has been added if mud amount is less than 1 // No mud has been added if mud amount is less than 1
if(hp.ma < 1.0*BS) if(hp.ma < 1.0*BS)
hp.ma = 0.0; hp.ma = 0.0;
hp.gh -= BS*3; // Lower a bit so that it is not that much in the way //hp.gh -= BS*3; // Lower a bit so that it is not that much in the way
g_heights[p2d] = hp; g_heights[p2d] = hp;
return hp; return hp;
} }

@ -186,6 +186,11 @@ TODO: Better control of draw_control.wanted_max_blocks
TODO: Further investigate the use of GPU lighting in addition to the TODO: Further investigate the use of GPU lighting in addition to the
current one current one
TODO: Artificial (night) light could be more yellow colored than sunlight.
- This is technically doable.
- Also the actual colors of the textures could be made less colorful
in the dark but it's a bit more difficult.
SUGG: Somehow make the night less colorful SUGG: Somehow make the night less colorful
Configuration: Configuration:
@ -361,6 +366,12 @@ Fixes to the current release:
Stuff to do after release: Stuff to do after release:
--------------------------- ---------------------------
Doing currently:
----------------
TODO: Use MapBlock::resetUsageTimer() in appropriate places
(on client and server)
====================================================================== ======================================================================
*/ */

File diff suppressed because it is too large Load Diff

218
src/map.h

@ -132,7 +132,7 @@ public:
// On failure returns NULL // On failure returns NULL
MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d); MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
// On failure returns NULL // Same as the above (there exists no lock anymore)
MapSector * getSectorNoGenerateNoEx(v2s16 p2d); MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
// On failure throws InvalidPositionException // On failure throws InvalidPositionException
MapSector * getSectorNoGenerate(v2s16 p2d); MapSector * getSectorNoGenerate(v2s16 p2d);
@ -268,6 +268,9 @@ public:
//bool updateChangedVisibleArea(); //bool updateChangedVisibleArea();
virtual void save(bool only_changed){assert(0);}; virtual void save(bool only_changed){assert(0);};
// Server implements this
virtual void saveBlock(MapBlock *block){};
/* /*
Updates usage timers Updates usage timers
@ -279,7 +282,7 @@ public:
void deleteSectors(core::list<v2s16> &list, bool only_blocks); void deleteSectors(core::list<v2s16> &list, bool only_blocks);
// Returns count of deleted sectors // Returns count of deleted sectors
u32 deleteUnusedSectors(float timeout, bool only_blocks=false, u32 unloadUnusedData(float timeout, bool only_blocks=false,
core::list<v3s16> *deleted_blocks=NULL); core::list<v3s16> *deleted_blocks=NULL);
// For debug printing // For debug printing
@ -330,7 +333,9 @@ protected:
This is the only map class that is able to generate map. This is the only map class that is able to generate map.
*/ */
struct ChunkMakeData; //struct ChunkMakeData;
struct BlockMakeData;
class ServerMap : public Map class ServerMap : public Map
{ {
@ -346,160 +351,25 @@ public:
return MAPTYPE_SERVER; return MAPTYPE_SERVER;
} }
/*
Map generation
*/
// Returns the position of the chunk where the sector is in
v2s16 sector_to_chunk(v2s16 sectorpos)
{
if(m_chunksize == 0)
return v2s16(0,0);
sectorpos.X += m_chunksize / 2;
sectorpos.Y += m_chunksize / 2;
v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
return chunkpos;
}
// Returns the position of the (0,0) sector of the chunk
v2s16 chunk_to_sector(v2s16 chunkpos)
{
if(m_chunksize == 0)
return v2s16(0,0);
v2s16 sectorpos(
chunkpos.X * m_chunksize,
chunkpos.Y * m_chunksize
);
sectorpos.X -= m_chunksize / 2;
sectorpos.Y -= m_chunksize / 2;
return sectorpos;
}
/*
Get a chunk.
*/
MapChunk *getChunk(v2s16 chunkpos)
{
core::map<v2s16, MapChunk*>::Node *n;
n = m_chunks.find(chunkpos);
if(n == NULL)
return NULL;
return n->getValue();
}
/*
True if the chunk and its neighbors are fully generated.
It means the chunk will not be touched in the future by the
generator. If false, generateChunk will make it true.
*/
bool chunkNonVolatile(v2s16 chunkpos)
{
if(m_chunksize == 0)
return true;
/*for(s16 x=-1; x<=1; x++)
for(s16 y=-1; y<=1; y++)*/
s16 x=0;
s16 y=0;
{
v2s16 chunkpos0 = chunkpos + v2s16(x,y);
MapChunk *chunk = getChunk(chunkpos);
if(chunk == NULL)
return false;
if(chunk->getGenLevel() != GENERATED_FULLY)
return false;
}
return true;
}
/*
Returns true if any chunk is marked as modified
*/
bool anyChunkModified()
{
for(core::map<v2s16, MapChunk*>::Iterator
i = m_chunks.getIterator();
i.atEnd()==false; i++)
{
v2s16 p = i.getNode()->getKey();
MapChunk *chunk = i.getNode()->getValue();
if(chunk->isModified())
return true;
}
return false;
}
void setChunksNonModified()
{
for(core::map<v2s16, MapChunk*>::Iterator
i = m_chunks.getIterator();
i.atEnd()==false; i++)
{
v2s16 p = i.getNode()->getKey();
MapChunk *chunk = i.getNode()->getValue();
chunk->setModified(false);
}
}
/*
Chunks are generated by using these and makeChunk().
*/
void initChunkMake(ChunkMakeData &data, v2s16 chunkpos);
MapChunk* finishChunkMake(ChunkMakeData &data,
core::map<v3s16, MapBlock*> &changed_blocks);
/*
Generate a chunk.
All chunks touching this one can be altered also.
*/
/*MapChunk* generateChunkRaw(v2s16 chunkpos,
core::map<v3s16, MapBlock*> &changed_blocks,
bool force=false);*/
/*
Generate a chunk and its neighbors so that it won't be touched
anymore.
*/
/*MapChunk* generateChunk(v2s16 chunkpos,
core::map<v3s16, MapBlock*> &changed_blocks);*/
/*
Generate a sector.
This is mainly called by generateChunkRaw.
*/
//ServerMapSector * generateSector(v2s16 p);
/* /*
Get a sector from somewhere. Get a sector from somewhere.
- Check memory - Check memory
- Check disk (loads blocks also) - Check disk (doesn't load blocks)
- Create blank one - Create blank one
*/ */
ServerMapSector * createSector(v2s16 p); ServerMapSector * createSector(v2s16 p);
/* /*
Get a sector from somewhere. Blocks are generated by using these and makeBlock().
- Check memory
- Check disk (loads blocks also)
- Generate chunk
*/ */
/*MapSector * emergeSector(v2s16 p, void initBlockMake(BlockMakeData *data, v3s16 blockpos);
core::map<v3s16, MapBlock*> &changed_blocks);*/ MapBlock* finishBlockMake(BlockMakeData *data,
core::map<v3s16, MapBlock*> &changed_blocks);
/*MapSector * emergeSector(v2s16 p) // A non-threaded wrapper to the above
{
core::map<v3s16, MapBlock*> changed_blocks;
return emergeSector(p, changed_blocks);
}*/
MapBlock * generateBlock( MapBlock * generateBlock(
v3s16 p, v3s16 p,
MapBlock *original_dummy, core::map<v3s16, MapBlock*> &modified_blocks
ServerMapSector *sector,
core::map<v3s16, MapBlock*> &changed_blocks,
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
); );
/* /*
@ -508,37 +378,17 @@ public:
- Create blank - Create blank
*/ */
MapBlock * createBlock(v3s16 p); MapBlock * createBlock(v3s16 p);
/*
only_from_disk, changed_blocks and lighting_invalidated_blocks
are not properly used by the new map generator.
*/
MapBlock * emergeBlock(
v3s16 p,
bool only_from_disk,
core::map<v3s16, MapBlock*> &changed_blocks,
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
);
#if 0 #if 0
/* /*
NOTE: This comment might be outdated
Forcefully get a block from somewhere. Forcefully get a block from somewhere.
Exceptions: InvalidPositionException possible if only_from_disk==true
- InvalidPositionException: possible if only_from_disk==true
changed_blocks: Parameters:
- All already existing blocks that were modified are added. changed_blocks: Blocks that have been modified
- If found on disk, nothing will be added.
- If generated, the new block will not be included.
lighting_invalidated_blocks:
- All blocks that have heavy-to-calculate lighting changes
are added.
- updateLighting() should be called for these.
- A block that is in changed_blocks may not be in
lighting_invalidated_blocks.
*/ */
MapBlock * emergeBlock( MapBlock * emergeBlock(
v3s16 p, v3s16 p,
@ -561,6 +411,7 @@ public:
// dirname: final directory name // dirname: final directory name
v2s16 getSectorPos(std::string dirname); v2s16 getSectorPos(std::string dirname);
v3s16 getBlockPos(std::string sectordir, std::string blockfile); v3s16 getBlockPos(std::string sectordir, std::string blockfile);
static std::string getBlockFilename(v3s16 p);
void save(bool only_changed); void save(bool only_changed);
//void loadAll(); //void loadAll();
@ -569,8 +420,8 @@ public:
void saveMapMeta(); void saveMapMeta();
void loadMapMeta(); void loadMapMeta();
void saveChunkMeta(); /*void saveChunkMeta();
void loadChunkMeta(); void loadChunkMeta();*/
// The sector mutex should be locked when calling most of these // The sector mutex should be locked when calling most of these
@ -579,6 +430,7 @@ public:
// DEPRECATED? Sectors have no metadata anymore. // DEPRECATED? Sectors have no metadata anymore.
void saveSectorMeta(ServerMapSector *sector); void saveSectorMeta(ServerMapSector *sector);
MapSector* loadSectorMeta(std::string dirname, bool save_after_load); MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
bool loadSectorMeta(v2s16 p2d);
// Full load of a sector including all blocks. // Full load of a sector including all blocks.
// returns true on success, false on failure. // returns true on success, false on failure.
@ -590,6 +442,7 @@ public:
void saveBlock(MapBlock *block); void saveBlock(MapBlock *block);
// This will generate a sector with getSector if not found. // This will generate a sector with getSector if not found.
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false); void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
MapBlock* loadBlock(v3s16 p);
// For debug printing // For debug printing
virtual void PrintInfo(std::ostream &out); virtual void PrintInfo(std::ostream &out);
@ -605,11 +458,13 @@ private:
std::string m_savedir; std::string m_savedir;
bool m_map_saving_enabled; bool m_map_saving_enabled;
#if 0
// Chunk size in MapSectors // Chunk size in MapSectors
// If 0, chunks are disabled. // If 0, chunks are disabled.
s16 m_chunksize; s16 m_chunksize;
// Chunks // Chunks
core::map<v2s16, MapChunk*> m_chunks; core::map<v2s16, MapChunk*> m_chunks;
#endif
/* /*
Metadata is re-written on disk only if this is true. Metadata is re-written on disk only if this is true.
@ -815,6 +670,7 @@ protected:
bool m_create_area; bool m_create_area;
}; };
#if 0
struct ChunkMakeData struct ChunkMakeData
{ {
bool no_op; bool no_op;
@ -838,6 +694,24 @@ struct ChunkMakeData
}; };
void makeChunk(ChunkMakeData *data); void makeChunk(ChunkMakeData *data);
#endif
struct BlockMakeData
{
bool no_op;
ManualMapVoxelManipulator vmanip;
u64 seed;
v3s16 blockpos;
UniqueQueue<v3s16> transforming_liquid;
BlockMakeData():
no_op(false),
vmanip(NULL),
seed(0)
{}
};
void makeBlock(BlockMakeData *data);
#endif #endif

@ -31,13 +31,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
m_parent(parent), m_parent(parent),
m_pos(pos), m_pos(pos),
changed(true), m_modified(MOD_STATE_WRITE_NEEDED),
is_underground(false), is_underground(false),
m_lighting_expired(true), m_lighting_expired(true),
m_day_night_differs(false), m_day_night_differs(false),
//m_not_fully_generated(false), m_generated(false),
m_objects(this), m_objects(this),
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED) m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
m_usage_timer(BLOCK_TIMESTAMP_UNDEFINED)
{ {
data = NULL; data = NULL;
if(dummy == false) if(dummy == false)
@ -241,7 +242,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
// Check if node above block has sunlight // Check if node above block has sunlight
try{ try{
MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN) if(n.d == CONTENT_IGNORE || n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
{ {
no_sunlight = true; no_sunlight = true;
} }
@ -593,6 +594,11 @@ void MapBlock::serialize(std::ostream &os, u8 version)
flags |= 0x02; flags |= 0x02;
if(m_lighting_expired) if(m_lighting_expired)
flags |= 0x04; flags |= 0x04;
if(version >= 18)
{
if(m_generated == false)
flags |= 0x08;
}
os.write((char*)&flags, 1); os.write((char*)&flags, 1);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
@ -668,6 +674,12 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
setLightingExpired(true); setLightingExpired(true);
} }
// These have no "generated" field
if(version < 18)
{
m_generated = true;
}
// These have no compression // These have no compression
if(version <= 3 || version == 5 || version == 6) if(version <= 3 || version == 5 || version == 6)
{ {
@ -749,6 +761,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
is_underground = (flags & 0x01) ? true : false; is_underground = (flags & 0x01) ? true : false;
m_day_night_differs = (flags & 0x02) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false;
m_lighting_expired = (flags & 0x04) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false;
if(version >= 18)
m_generated = (flags & 0x08) ? false : true;
// Uncompress data // Uncompress data
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);

@ -51,6 +51,36 @@ enum{
FACE_LEFT FACE_LEFT
};*/ };*/
enum ModifiedState
{
// Has not been modified.
MOD_STATE_CLEAN = 0,
MOD_RESERVED1 = 1,
// Has been modified, and will be saved when being unloaded.
MOD_STATE_WRITE_AT_UNLOAD = 2,
MOD_RESERVED3 = 3,
// Has been modified, and will be saved as soon as possible.
MOD_STATE_WRITE_NEEDED = 4,
MOD_RESERVED5 = 5,
};
// NOTE: If this is enabled, set MapBlock to be initialized with
// CONTENT_IGNORE.
/*enum BlockGenerationStatus
{
// Completely non-generated (filled with CONTENT_IGNORE).
BLOCKGEN_UNTOUCHED=0,
// Trees or similar might have been blitted from other blocks to here.
// Otherwise, the block contains CONTENT_IGNORE
BLOCKGEN_FROM_NEIGHBORS=2,
// Has been generated, but some neighbors might put some stuff in here
// when they are generated.
// Does not contain any CONTENT_IGNORE
BLOCKGEN_SELF_GENERATED=4,
// The block and all its neighbors have been generated
BLOCKGEN_FULLY_GENERATED=6
};*/
enum enum
{ {
NODECONTAINER_ID_MAPBLOCK, NODECONTAINER_ID_MAPBLOCK,
@ -106,9 +136,10 @@ public:
u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
data = new MapNode[l]; data = new MapNode[l];
for(u32 i=0; i<l; i++){ for(u32 i=0; i<l; i++){
data[i] = MapNode(); //data[i] = MapNode();
data[i] = MapNode(CONTENT_IGNORE);
} }
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
/* /*
@ -130,19 +161,43 @@ public:
modified, so that the block is saved and possibly not deleted from modified, so that the block is saved and possibly not deleted from
memory. memory.
*/ */
// DEPRECATED, use *Modified()
void setChangedFlag() void setChangedFlag()
{ {
changed = true; //dstream<<"Deprecated setChangedFlag() called"<<std::endl;
raiseModified(MOD_STATE_WRITE_NEEDED);
} }
// DEPRECATED, use *Modified()
void resetChangedFlag() void resetChangedFlag()
{ {
changed = false; //dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
resetModified();
} }
// DEPRECATED, use *Modified()
bool getChangedFlag() bool getChangedFlag()
{ {
return changed; //dstream<<"Deprecated getChangedFlag() called"<<std::endl;
if(getModified() == MOD_STATE_CLEAN)
return false;
else
return true;
} }
// m_modified methods
void raiseModified(u32 mod)
{
m_modified = MYMAX(m_modified, mod);
}
u32 getModified()
{
return m_modified;
}
void resetModified()
{
m_modified = MOD_STATE_CLEAN;
}
// is_underground getter/setter
bool getIsUnderground() bool getIsUnderground()
{ {
return is_underground; return is_underground;
@ -150,7 +205,7 @@ public:
void setIsUnderground(bool a_is_underground) void setIsUnderground(bool a_is_underground)
{ {
is_underground = a_is_underground; is_underground = a_is_underground;
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
#ifndef SERVER #ifndef SERVER
@ -168,22 +223,22 @@ public:
void setLightingExpired(bool expired) void setLightingExpired(bool expired)
{ {
m_lighting_expired = expired; m_lighting_expired = expired;
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
bool getLightingExpired() bool getLightingExpired()
{ {
return m_lighting_expired; return m_lighting_expired;
} }
/*bool isFullyGenerated() bool isGenerated()
{ {
return !m_not_fully_generated; return m_generated;
} }
void setFullyGenerated(bool b) void setGenerated(bool b)
{ {
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
m_not_fully_generated = !b; m_generated = b;
}*/ }
bool isValid() bool isValid()
{ {
@ -261,7 +316,7 @@ public:
if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n; data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
void setNode(v3s16 p, MapNode & n) void setNode(v3s16 p, MapNode & n)
@ -290,7 +345,7 @@ public:
if(data == NULL) if(data == NULL)
throw InvalidPositionException(); throw InvalidPositionException();
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n; data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
void setNodeNoCheck(v3s16 p, MapNode & n) void setNodeNoCheck(v3s16 p, MapNode & n)
@ -376,26 +431,26 @@ public:
{ {
m_objects.update(is, version, smgr, daynight_ratio); m_objects.update(is, version, smgr, daynight_ratio);
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
void clearObjects() void clearObjects()
{ {
m_objects.clear(); m_objects.clear();
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
void addObject(MapBlockObject *object) void addObject(MapBlockObject *object)
throw(ContainerFullException, AlreadyExistsException) throw(ContainerFullException, AlreadyExistsException)
{ {
m_objects.add(object); m_objects.add(object);
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
void removeObject(s16 id) void removeObject(s16 id)
{ {
m_objects.remove(id); m_objects.remove(id);
setChangedFlag(); raiseModified(MOD_STATE_WRITE_NEEDED);
} }
MapBlockObject * getObject(s16 id) MapBlockObject * getObject(s16 id)
{ {
@ -505,7 +560,7 @@ public:
void setTimestamp(u32 time) void setTimestamp(u32 time)
{ {
m_timestamp = time; m_timestamp = time;
setChangedFlag(); raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
} }
void setTimestampNoChangedFlag(u32 time) void setTimestampNoChangedFlag(u32 time)
{ {
@ -515,6 +570,22 @@ public:
{ {
return m_timestamp; return m_timestamp;
} }
/*
See m_usage_timer
*/
void resetUsageTimer()
{
m_usage_timer = 0;
}
void incrementUsageTimer(float dtime)
{
m_usage_timer += dtime;
}
u32 getUsageTimer()
{
return m_usage_timer;
}
/* /*
Serialization Serialization
@ -581,10 +652,10 @@ private:
/* /*
- On the server, this is used for telling whether the - On the server, this is used for telling whether the
block has been changed from the one on disk. block has been modified from the one on disk.
- On the client, this is used for nothing. - On the client, this is used for nothing.
*/ */
bool changed; u32 m_modified;
/* /*
When propagating sunlight and the above block doesn't exist, When propagating sunlight and the above block doesn't exist,
@ -607,6 +678,8 @@ private:
// Whether day and night lighting differs // Whether day and night lighting differs
bool m_day_night_differs; bool m_day_night_differs;
bool m_generated;
// DEPRECATED // DEPRECATED
MapBlockObjectList m_objects; MapBlockObjectList m_objects;
@ -630,6 +703,12 @@ private:
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp. Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
*/ */
u32 m_timestamp; u32 m_timestamp;
/*
When the block is accessed, this is set to 0.
Map will unload the block when this reaches a timeout.
*/
float m_usage_timer;
}; };
inline bool blockpos_over_limit(v3s16 p) inline bool blockpos_over_limit(v3s16 p)

@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
MapSector::MapSector(NodeContainer *parent, v2s16 pos): MapSector::MapSector(NodeContainer *parent, v2s16 pos):
differs_from_disk(true), differs_from_disk(true),
usage_timer(0.0),
m_parent(parent), m_parent(parent),
m_pos(pos), m_pos(pos),
m_block_cache(NULL) m_block_cache(NULL)

@ -203,13 +203,6 @@ public:
// Basically, this should be changed to true in every setter method // Basically, this should be changed to true in every setter method
bool differs_from_disk; bool differs_from_disk;
// Counts seconds from last usage.
// Sector can be deleted from memory after some time of inactivity.
// NOTE: It has to be made very sure no other thread is accessing
// the sector and it doesn't remain in any cache when
// deleting it.
float usage_timer;
protected: protected:
// The pile of MapBlocks // The pile of MapBlocks

@ -222,6 +222,49 @@ double noise3d_perlin_abs(double x, double y, double z, int seed,
return a; return a;
} }
// -1->0, 0->1, 1->0
double contour(double v)
{
v = fabs(v);
if(v >= 1.0)
return 0.0;
return (1.0-v);
}
double noise3d_param(const NoiseParams &param, double x, double y, double z)
{
double s = param.pos_scale;
x /= s;
y /= s;
z /= s;
if(param.type == NOISE_PERLIN)
{
return param.noise_scale*noise3d_perlin(x,y,z, param.seed,
param.octaves,
param.persistence);
}
else if(param.type == NOISE_PERLIN_ABS)
{
return param.noise_scale*noise3d_perlin_abs(x,y,z, param.seed,
param.octaves,
param.persistence);
}
else if(param.type == NOISE_PERLIN_CONTOUR)
{
return contour(param.noise_scale*noise3d_perlin(x,y,z,
param.seed, param.octaves,
param.persistence));
}
else if(param.type == NOISE_PERLIN_CONTOUR_FLIP_YZ)
{
return contour(param.noise_scale*noise3d_perlin(x,z,y,
param.seed, param.octaves,
param.persistence));
}
else assert(0);
}
/* /*
NoiseBuffer NoiseBuffer
*/ */
@ -246,8 +289,7 @@ void NoiseBuffer::clear()
m_size_z = 0; m_size_z = 0;
} }
void NoiseBuffer::create(int seed, int octaves, double persistence, void NoiseBuffer::create(const NoiseParams &param,
double pos_scale,
double first_x, double first_y, double first_z, double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z, double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z) double samplelength_x, double samplelength_y, double samplelength_z)
@ -265,22 +307,54 @@ void NoiseBuffer::create(int seed, int octaves, double persistence,
m_size_y = (last_y - m_start_y)/samplelength_y + 2; m_size_y = (last_y - m_start_y)/samplelength_y + 2;
m_size_z = (last_z - m_start_z)/samplelength_z + 2; m_size_z = (last_z - m_start_z)/samplelength_z + 2;
/*dstream<<"m_size_x="<<m_size_x<<", m_size_y="<<m_size_y
<<", m_size_z="<<m_size_z<<std::endl;*/
m_data = new double[m_size_x*m_size_y*m_size_z]; m_data = new double[m_size_x*m_size_y*m_size_z];
for(int x=0; x<m_size_x; x++) for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++) for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++) for(int z=0; z<m_size_z; z++)
{ {
double xd = (m_start_x + (double)x*m_samplelength_x)/pos_scale; double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y)/pos_scale; double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z)/pos_scale; double zd = (m_start_z + (double)z*m_samplelength_z);
intSet(x,y,z, noise3d_perlin(xd,yd,zd,seed,octaves,persistence)); double a = noise3d_param(param, xd,yd,zd);
intSet(x,y,z, a);
} }
} }
void NoiseBuffer::multiply(const NoiseParams &param)
{
assert(m_data != NULL);
for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++)
{
double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z);
double a = noise3d_param(param, xd,yd,zd);
intMultiply(x,y,z, a);
}
}
// Deprecated
void NoiseBuffer::create(int seed, int octaves, double persistence,
bool abs,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z)
{
NoiseParams param;
param.type = abs ? NOISE_PERLIN_ABS : NOISE_PERLIN;
param.seed = seed;
param.octaves = octaves;
param.persistence = persistence;
create(param, first_x, first_y, first_z,
last_x, last_y, last_z,
samplelength_x, samplelength_y, samplelength_z);
}
void NoiseBuffer::intSet(int x, int y, int z, double d) void NoiseBuffer::intSet(int x, int y, int z, double d)
{ {
int i = m_size_x*m_size_y*z + m_size_x*y + x; int i = m_size_x*m_size_y*z + m_size_x*y + x;
@ -289,6 +363,14 @@ void NoiseBuffer::intSet(int x, int y, int z, double d)
m_data[i] = d; m_data[i] = d;
} }
void NoiseBuffer::intMultiply(int x, int y, int z, double d)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
m_data[i] = m_data[i] * d;
}
double NoiseBuffer::intGet(int x, int y, int z) double NoiseBuffer::intGet(int x, int y, int z)
{ {
int i = m_size_x*m_size_y*z + m_size_x*y + x; int i = m_size_x*m_size_y*z + m_size_x*y + x;
@ -326,3 +408,14 @@ double NoiseBuffer::get(double x, double y, double z)
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl); return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
} }
/*bool NoiseBuffer::contains(double x, double y, double z)
{
x -= m_start_x;
y -= m_start_y;
z -= m_start_z;
x /= m_samplelength_x;
y /= m_samplelength_y;
z /= m_samplelength_z;
if(x <= 0.0 || x >= m_size_x)
}*/

@ -41,6 +41,38 @@ double noise3d_perlin(double x, double y, double z, int seed,
double noise3d_perlin_abs(double x, double y, double z, int seed, double noise3d_perlin_abs(double x, double y, double z, int seed,
int octaves, double persistence); int octaves, double persistence);
enum NoiseType
{
NOISE_PERLIN,
NOISE_PERLIN_ABS,
NOISE_PERLIN_CONTOUR,
NOISE_PERLIN_CONTOUR_FLIP_YZ
};
struct NoiseParams
{
NoiseType type;
int seed;
int octaves;
double persistence;
double pos_scale;
double noise_scale; // Useful for contour noises
NoiseParams(NoiseType type_=NOISE_PERLIN, int seed_=0,
int octaves_=3, double persistence_=0.5,
double pos_scale_=100.0, double noise_scale_=1.0):
type(type_),
seed(seed_),
octaves(octaves_),
persistence(persistence_),
pos_scale(pos_scale_),
noise_scale(noise_scale_)
{
}
};
double noise3d_param(const NoiseParams &param, double x, double y, double z);
class NoiseBuffer class NoiseBuffer
{ {
public: public:
@ -48,15 +80,23 @@ public:
~NoiseBuffer(); ~NoiseBuffer();
void clear(); void clear();
void create(const NoiseParams &param,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z);
void multiply(const NoiseParams &param);
// Deprecated
void create(int seed, int octaves, double persistence, void create(int seed, int octaves, double persistence,
double pos_scale, bool abs,
double first_x, double first_y, double first_z, double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z, double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z); double samplelength_x, double samplelength_y, double samplelength_z);
void intSet(int x, int y, int z, double d); void intSet(int x, int y, int z, double d);
void intMultiply(int x, int y, int z, double d);
double intGet(int x, int y, int z); double intGet(int x, int y, int z);
double get(double x, double y, double z); double get(double x, double y, double z);
//bool contains(double x, double y, double z);
private: private:
double *m_data; double *m_data;

@ -53,11 +53,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
15: StaticObjects 15: StaticObjects
16: larger maximum size of node metadata, and compression 16: larger maximum size of node metadata, and compression
17: MapBlocks contain timestamp 17: MapBlocks contain timestamp
18: sqlite/new generator/whatever
*/ */
// This represents an uninitialized or invalid format // This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255 #define SER_FMT_VER_INVALID 255
// Highest supported serialization version // Highest supported serialization version
#define SER_FMT_VER_HIGHEST 17 #define SER_FMT_VER_HIGHEST 18
// Lowest supported serialization version // Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0 #define SER_FMT_VER_LOWEST 0

@ -37,6 +37,31 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
class MapEditEventIgnorer
{
public:
MapEditEventIgnorer(bool *flag):
m_flag(flag)
{
if(*m_flag == false)
*m_flag = true;
else
m_flag = NULL;
}
~MapEditEventIgnorer()
{
if(m_flag)
{
assert(*m_flag);
*m_flag = false;
}
}
private:
bool *m_flag;
};
void * ServerThread::Thread() void * ServerThread::Thread()
{ {
ThreadStarted(); ThreadStarted();
@ -150,8 +175,8 @@ void * EmergeThread::Thread()
ServerMap &map = ((ServerMap&)m_server->m_env.getMap()); ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
core::map<v3s16, MapBlock*> changed_blocks; //core::map<v3s16, MapBlock*> changed_blocks;
core::map<v3s16, MapBlock*> lighting_invalidated_blocks; //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
MapBlock *block = NULL; MapBlock *block = NULL;
bool got_block = true; bool got_block = true;
@ -162,32 +187,6 @@ void * EmergeThread::Thread()
if(optional) if(optional)
only_from_disk = true; only_from_disk = true;
v2s16 chunkpos = map.sector_to_chunk(p2d);
bool generate_chunk = false;
if(only_from_disk == false)
{
JMutexAutoLock envlock(m_server->m_env_mutex);
if(map.chunkNonVolatile(chunkpos) == false)
generate_chunk = true;
}
if(generate_chunk)
{
ChunkMakeData data;
{
JMutexAutoLock envlock(m_server->m_env_mutex);
map.initChunkMake(data, chunkpos);
}
makeChunk(&data);
{
JMutexAutoLock envlock(m_server->m_env_mutex);
map.finishChunkMake(data, changed_blocks);
}
}
/* /*
Fetch block from map or generate a single block Fetch block from map or generate a single block
*/ */
@ -196,36 +195,55 @@ void * EmergeThread::Thread()
// Load sector if it isn't loaded // Load sector if it isn't loaded
if(map.getSectorNoGenerateNoEx(p2d) == NULL) if(map.getSectorNoGenerateNoEx(p2d) == NULL)
map.loadSectorFull(p2d); //map.loadSectorFull(p2d);
map.loadSectorMeta(p2d);
block = map.getBlockNoCreateNoEx(p); block = map.getBlockNoCreateNoEx(p);
if(!block || block->isDummy()) if(!block || block->isDummy() || !block->isGenerated())
{ {
if(only_from_disk) // Get, load or create sector
/*ServerMapSector *sector =
(ServerMapSector*)map.createSector(p2d);*/
// Load/generate block
/*block = map.emergeBlock(p, sector, changed_blocks,
lighting_invalidated_blocks);*/
block = map.loadBlock(p);
if(block == NULL && only_from_disk == false)
block = map.generateBlock(p, modified_blocks);
//block = map.generateBlock(p, changed_blocks);
/*block = map.generateBlock(p, block, sector, changed_blocks,
lighting_invalidated_blocks);*/
if(block == NULL)
{ {
got_block = false; got_block = false;
} }
else else
{ {
// Get, load or create sector /*
ServerMapSector *sector = Ignore map edit events, they will not need to be
(ServerMapSector*)map.createSector(p2d); sent to anybody because the block hasn't been sent
// Generate block to anybody
block = map.generateBlock(p, block, sector, changed_blocks, */
lighting_invalidated_blocks); MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
if(block == NULL)
got_block = false; // Activate objects and stuff
m_server->m_env.activateBlock(block, 3600);
} }
} }
else else
{ {
if(block->getLightingExpired()){ /*if(block->getLightingExpired()){
lighting_invalidated_blocks[block->getPos()] = block; lighting_invalidated_blocks[block->getPos()] = block;
} }*/
} }
// TODO: Some additional checking and lighting updating, // TODO: Some additional checking and lighting updating,
// see emergeBlock // see emergeBlock
} }
{//envlock {//envlock
@ -237,7 +255,8 @@ void * EmergeThread::Thread()
Collect a list of blocks that have been modified in Collect a list of blocks that have been modified in
addition to the fetched one. addition to the fetched one.
*/ */
#if 0
if(lighting_invalidated_blocks.size() > 0) if(lighting_invalidated_blocks.size() > 0)
{ {
/*dstream<<"lighting "<<lighting_invalidated_blocks.size() /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
@ -258,11 +277,12 @@ void * EmergeThread::Thread()
MapBlock *block = i.getNode()->getValue(); MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block); modified_blocks.insert(block->getPos(), block);
} }
#endif
} }
// If we got no block, there should be no invalidated blocks // If we got no block, there should be no invalidated blocks
else else
{ {
assert(lighting_invalidated_blocks.size() == 0); //assert(lighting_invalidated_blocks.size() == 0);
} }
}//envlock }//envlock
@ -597,12 +617,16 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
{ {
block_is_invalid = true; block_is_invalid = true;
}*/ }*/
#if 0
v2s16 p2d(p.X, p.Z); v2s16 p2d(p.X, p.Z);
ServerMap *map = (ServerMap*)(&server->m_env.getMap()); ServerMap *map = (ServerMap*)(&server->m_env.getMap());
v2s16 chunkpos = map->sector_to_chunk(p2d); v2s16 chunkpos = map->sector_to_chunk(p2d);
if(map->chunkNonVolatile(chunkpos) == false) if(map->chunkNonVolatile(chunkpos) == false)
block_is_invalid = true; block_is_invalid = true;
#endif
if(block->isGenerated() == false)
block_is_invalid = true;
#if 1 #if 1
/* /*
If block is not close, don't send it unless it is near If block is not close, don't send it unless it is near
@ -649,6 +673,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
//TODO: Get value from somewhere //TODO: Get value from somewhere
// Allow only one block in emerge queue // Allow only one block in emerge queue
//if(server->m_emerge_queue.peerItemCount(peer_id) < 1) //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
// Allow two blocks in queue per client
if(server->m_emerge_queue.peerItemCount(peer_id) < 2) if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
{ {
//dstream<<"Adding block to emerge queue"<<std::endl; //dstream<<"Adding block to emerge queue"<<std::endl;
@ -1630,19 +1655,28 @@ void Server::AsyncRunStep()
Send queued-for-sending map edit events. Send queued-for-sending map edit events.
*/ */
{ {
// Don't send too many at a time
u32 count = 0;
while(m_unsent_map_edit_queue.size() != 0) while(m_unsent_map_edit_queue.size() != 0)
{ {
MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
// Players far away from the change are stored here.
// Instead of sending the changes, MapBlocks are set not sent
// for them.
core::list<u16> far_players;
if(event->type == MEET_ADDNODE) if(event->type == MEET_ADDNODE)
{ {
dstream<<"Server: MEET_ADDNODE"<<std::endl; dstream<<"Server: MEET_ADDNODE"<<std::endl;
sendAddNode(event->p, event->n, event->already_known_by_peer); sendAddNode(event->p, event->n, event->already_known_by_peer,
&far_players, 30);
} }
else if(event->type == MEET_REMOVENODE) else if(event->type == MEET_REMOVENODE)
{ {
dstream<<"Server: MEET_REMOVENODE"<<std::endl; dstream<<"Server: MEET_REMOVENODE"<<std::endl;
sendRemoveNode(event->p, event->already_known_by_peer); sendRemoveNode(event->p, event->already_known_by_peer,
&far_players, 30);
} }
else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
{ {
@ -1659,8 +1693,35 @@ void Server::AsyncRunStep()
dstream<<"WARNING: Server: Unknown MapEditEvent " dstream<<"WARNING: Server: Unknown MapEditEvent "
<<((u32)event->type)<<std::endl; <<((u32)event->type)<<std::endl;
} }
/*
Set blocks not sent to far players
*/
core::map<v3s16, MapBlock*> modified_blocks2;
for(core::map<v3s16, bool>::Iterator
i = event->modified_blocks.getIterator();
i.atEnd()==false; i++)
{
v3s16 p = i.getNode()->getKey();
modified_blocks2.insert(p, m_env.getMap().getBlockNoCreateNoEx(p));
}
for(core::list<u16>::Iterator
i = far_players.begin();
i != far_players.end(); i++)
{
u16 peer_id = *i;
RemoteClient *client = getClient(peer_id);
if(client==NULL)
continue;
client->SetBlocksNotSent(modified_blocks2);
}
delete event; delete event;
// Don't send too many at a time
count++;
if(count >= 2 && m_unsent_map_edit_queue.size() < 50)
break;
} }
} }
@ -1754,7 +1815,7 @@ void Server::AsyncRunStep()
m_env.getMap().save(true); m_env.getMap().save(true);
// Delete unused sectors // Delete unused sectors
u32 deleted_count = m_env.getMap().deleteUnusedSectors( u32 deleted_count = m_env.getMap().unloadUnusedData(
g_settings.getFloat("server_unload_unused_sectors_timeout")); g_settings.getFloat("server_unload_unused_sectors_timeout"));
if(deleted_count > 0) if(deleted_count > 0)
{ {
@ -2565,10 +2626,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
Remove the node Remove the node
(this takes some time so it is done after the quick stuff) (this takes some time so it is done after the quick stuff)
*/ */
m_ignore_map_edit_events = true; {
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); MapEditEventIgnorer ign(&m_ignore_map_edit_events);
m_ignore_map_edit_events = false;
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
}
/* /*
Set blocks not sent to far players Set blocks not sent to far players
*/ */
@ -2679,10 +2741,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
This takes some time so it is done after the quick stuff This takes some time so it is done after the quick stuff
*/ */
core::map<v3s16, MapBlock*> modified_blocks; core::map<v3s16, MapBlock*> modified_blocks;
m_ignore_map_edit_events = true; {
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); MapEditEventIgnorer ign(&m_ignore_map_edit_events);
m_ignore_map_edit_events = false;
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
}
/* /*
Set blocks not sent to far players Set blocks not sent to far players
*/ */
@ -3889,10 +3952,16 @@ std::wstring Server::getStatusString()
v3f findSpawnPos(ServerMap &map) v3f findSpawnPos(ServerMap &map)
{ {
//return v3f(50,50,50)*BS; //return v3f(50,50,50)*BS;
v2s16 nodepos; v2s16 nodepos;
s16 groundheight = 0; s16 groundheight = 0;
#if 0
nodepos = v2s16(0,0);
groundheight = 20;
#endif
#if 1
// Try to find a good place a few times // Try to find a good place a few times
for(s32 i=0; i<1000; i++) for(s32 i=0; i<1000; i++)
{ {
@ -3922,6 +3991,7 @@ v3f findSpawnPos(ServerMap &map)
//dstream<<"Searched through "<<i<<" places."<<std::endl; //dstream<<"Searched through "<<i<<" places."<<std::endl;
break; break;
} }
#endif
// If no suitable place was not found, go above water at least. // If no suitable place was not found, go above water at least.
if(groundheight < WATER_LEVEL) if(groundheight < WATER_LEVEL)
@ -3929,7 +3999,7 @@ v3f findSpawnPos(ServerMap &map)
return intToFloat(v3s16( return intToFloat(v3s16(
nodepos.X, nodepos.X,
groundheight + 2, groundheight + 3,
nodepos.Y nodepos.Y
), BS); ), BS);
} }

16
src/sqlite/CMakeLists.txt Normal file

@ -0,0 +1,16 @@
if( UNIX )
set(sqlite3_SRCS sqlite3.c)
set(sqlite3_platform_LIBS "")
else( UNIX )
set(sqlite3_SRCS sqlite3.c)
set(sqlite3_platform_LIBS "")
endif( UNIX )
add_library(sqlite3 ${sqlite3_SRCS})
target_link_libraries(
sqlite3
${sqlite3_platform_LIBS}
)

125968
src/sqlite/sqlite3.c Normal file

File diff suppressed because it is too large Load Diff

6464
src/sqlite/sqlite3.h Normal file

File diff suppressed because it is too large Load Diff

@ -425,16 +425,27 @@ struct TestMapBlock
assert(b.getChangedFlag() == false); assert(b.getChangedFlag() == false);
// All nodes should have been set to // All nodes should have been set to
// .d=CONTENT_AIR and .getLight() = 0 // .d=CONTENT_IGNORE and .getLight() = 0
for(u16 z=0; z<MAP_BLOCKSIZE; z++) for(u16 z=0; z<MAP_BLOCKSIZE; z++)
for(u16 y=0; y<MAP_BLOCKSIZE; y++) for(u16 y=0; y<MAP_BLOCKSIZE; y++)
for(u16 x=0; x<MAP_BLOCKSIZE; x++) for(u16 x=0; x<MAP_BLOCKSIZE; x++)
{ {
assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR); //assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
assert(b.getNode(v3s16(x,y,z)).d == CONTENT_IGNORE);
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0); assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0);
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0); assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
} }
{
MapNode n(CONTENT_AIR);
for(u16 z=0; z<MAP_BLOCKSIZE; z++)
for(u16 y=0; y<MAP_BLOCKSIZE; y++)
for(u16 x=0; x<MAP_BLOCKSIZE; x++)
{
b.setNode(v3s16(x,y,z), n);
}
}
/* /*
Parent fetch functions Parent fetch functions
*/ */

@ -515,6 +515,8 @@ void TextureSource::buildMainAtlas()
sourcelist.push_back("glass.png"); sourcelist.push_back("glass.png");
sourcelist.push_back("mud.png^grass_side.png"); sourcelist.push_back("mud.png^grass_side.png");
sourcelist.push_back("cobble.png"); sourcelist.push_back("cobble.png");
sourcelist.push_back("mossycobble.png");
sourcelist.push_back("gravel.png");
sourcelist.push_back("stone.png^mineral_coal.png"); sourcelist.push_back("stone.png^mineral_coal.png");
sourcelist.push_back("stone.png^mineral_iron.png"); sourcelist.push_back("stone.png^mineral_iron.png");

@ -384,6 +384,14 @@ public:
return m_data[m_area.index(p)]; return m_data[m_area.index(p)];
} }
MapNode getNodeNoExNoEmerge(v3s16 p)
{
if(m_area.contains(p) == false)
return MapNode(CONTENT_IGNORE);
if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
return MapNode(CONTENT_IGNORE);
return m_data[m_area.index(p)];
}
MapNode & getNodeRef(v3s16 p) MapNode & getNodeRef(v3s16 p)
{ {
emerge(p); emerge(p);