working nicely

This commit is contained in:
Perttu Ahola 2010-12-13 03:19:12 +02:00
parent 47a593b519
commit 571fb14f94
20 changed files with 938 additions and 396 deletions

@ -33,6 +33,12 @@ cp -r data/sign.png $PACKAGEPATH/data/
cp -r data/sign_back.png $PACKAGEPATH/data/ cp -r data/sign_back.png $PACKAGEPATH/data/
cp -r data/rat.png $PACKAGEPATH/data/ cp -r data/rat.png $PACKAGEPATH/data/
cp -r data/mud.png $PACKAGEPATH/data/ cp -r data/mud.png $PACKAGEPATH/data/
cp -r data/torch.png $PACKAGEPATH/data/
cp -r data/torch_floor.png $PACKAGEPATH/data/
cp -r data/torch_ceiling.png $PACKAGEPATH/data/
cp -r data/skybox1.png $PACKAGEPATH/data/
cp -r data/skybox2.png $PACKAGEPATH/data/
cp -r data/skybox3.png $PACKAGEPATH/data/
cp -r doc/README.txt $PACKAGEPATH/doc/README.txt cp -r doc/README.txt $PACKAGEPATH/doc/README.txt

@ -54,5 +54,8 @@
#max_simultaneous_block_sends_server_total = 4 #max_simultaneous_block_sends_server_total = 4
#max_block_send_distance = 8 #max_block_send_distance = 8
#max_block_generate_distance = 5 #max_block_generate_distance = 6
#disable_water_climb = true
#endless_water = true

@ -1651,6 +1651,7 @@ MapBlockObject * Client::getSelectedObject(
v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map; v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
block->getObjects(from_pos_f_on_block, max_d, objects); block->getObjects(from_pos_f_on_block, max_d, objects);
//block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
} }
//dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl; //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;

@ -142,9 +142,9 @@ void Environment::step(float dtime)
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0)); v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
try{ try{
MapNode n = m_map->getNode(bottompos); MapNode n = m_map->getNode(bottompos);
if(n.d == MATERIAL_GRASS) if(n.d == CONTENT_GRASS)
{ {
n.d = MATERIAL_GRASS_FOOTSTEPS; n.d = CONTENT_GRASS_FOOTSTEPS;
m_map->setNode(bottompos, n); m_map->setNode(bottompos, n);
// Update mesh on client // Update mesh on client

@ -101,4 +101,47 @@ u8 light_decode_table[LIGHT_MAX+1] =
255, 255,
}; };
/*
#!/usr/bin/python
from math import *
from sys import stdout
# We want 0 at light=0 and 255 at light=LIGHT_MAX
LIGHT_MAX = 14
#FACTOR = 0.69
FACTOR = 0.75
maxlight = 255
minlight = 8
L = []
for i in range(1,LIGHT_MAX+1):
L.append(minlight+int(round((maxlight-minlight) * FACTOR ** (i-1))))
#L.append(int(round(255.0 * FACTOR ** (i-1))))
L.append(minlight)
L.reverse()
for i in L:
stdout.write(str(i)+",\n")
*/
/*u8 light_decode_table[LIGHT_MAX+1] =
{
8,
14,
16,
18,
22,
27,
33,
41,
52,
67,
86,
112,
147,
193,
255,
};*/

@ -186,13 +186,11 @@ SUGG: Implement a "Fast check queue" (a queue with a map for checking
TODO: Proper looking torches. TODO: Proper looking torches.
- Signs could be done in the same way? - Signs could be done in the same way?
TODO: A mapper to map contents to tile names (for each side)
Doing now: Doing now:
====================================================================== ======================================================================
TODO: A system for showing some nodes in some other way than cubes
- Needed for torches
- Also for signs, stairs, etc
====================================================================== ======================================================================
*/ */
@ -257,22 +255,26 @@ TODO: A system for showing some nodes in some other way than cubes
IrrlichtDevice *g_device = NULL; IrrlichtDevice *g_device = NULL;
const char *g_material_filenames[MATERIALS_COUNT] = const char *g_content_filenames[MATERIALS_COUNT] =
{ {
"../data/stone.png", "../data/stone.png",
"../data/grass.png", "../data/grass.png",
"../data/water.png", "../data/water.png",
"../data/light.png", "../data/torch_on_floor.png",
"../data/tree.png", "../data/tree.png",
"../data/leaves.png", "../data/leaves.png",
"../data/grass_footsteps.png", "../data/grass_footsteps.png",
"../data/mese.png", "../data/mese.png",
"../data/mud.png", "../data/mud.png",
"../data/water.png", // ocean "../data/water.png", // CONTENT_OCEAN
}; };
// Material cache
video::SMaterial g_materials[MATERIALS_COUNT]; video::SMaterial g_materials[MATERIALS_COUNT];
//video::SMaterial g_mesh_materials[3];
// Texture cache
TextureCache g_texturecache;
// All range-related stuff below is locked behind this // All range-related stuff below is locked behind this
JMutex g_range_mutex; JMutex g_range_mutex;
@ -320,20 +322,22 @@ void set_default_settings()
g_settings.set("random_input", "false"); g_settings.set("random_input", "false");
g_settings.set("client_delete_unused_sectors_timeout", "1200"); g_settings.set("client_delete_unused_sectors_timeout", "1200");
g_settings.set("max_block_send_distance", "8"); g_settings.set("max_block_send_distance", "8");
g_settings.set("max_block_generate_distance", "5"); g_settings.set("max_block_generate_distance", "6");
// Server stuff // Server stuff
g_settings.set("creative_mode", "false"); g_settings.set("creative_mode", "false");
g_settings.set("heightmap_blocksize", "128"); g_settings.set("heightmap_blocksize", "32");
g_settings.set("height_randmax", "constant 70.0"); g_settings.set("height_randmax", "constant 50.0");
g_settings.set("height_randfactor", "constant 0.6"); g_settings.set("height_randfactor", "constant 0.6");
g_settings.set("height_base", "linear 0 35 0"); g_settings.set("height_base", "linear 0 0 0");
g_settings.set("plants_amount", "1.0"); g_settings.set("plants_amount", "1.0");
g_settings.set("ravines_amount", "1.0"); g_settings.set("ravines_amount", "1.0");
g_settings.set("objectdata_interval", "0.2"); g_settings.set("objectdata_interval", "0.2");
g_settings.set("active_object_range", "2"); g_settings.set("active_object_range", "2");
g_settings.set("max_simultaneous_block_sends_per_client", "1"); g_settings.set("max_simultaneous_block_sends_per_client", "1");
g_settings.set("max_simultaneous_block_sends_server_total", "4"); g_settings.set("max_simultaneous_block_sends_server_total", "4");
g_settings.set("disable_water_climb", "true");
g_settings.set("endless_water", "true");
} }
/* /*
@ -673,7 +677,7 @@ public:
if(counter1 < 0.0) if(counter1 < 0.0)
{ {
counter1 = 0.1*Rand(1,10); counter1 = 0.1*Rand(1,10);
/*if(g_selected_material < USEFUL_MATERIAL_COUNT-1) /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)
g_selected_material++; g_selected_material++;
else else
g_selected_material = 0;*/ g_selected_material = 0;*/
@ -1297,7 +1301,7 @@ int main(int argc, char *argv[])
g_materials[i].Lighting = false; g_materials[i].Lighting = false;
g_materials[i].BackfaceCulling = false; g_materials[i].BackfaceCulling = false;
const char *filename = g_material_filenames[i]; const char *filename = g_content_filenames[i];
if(filename != NULL){ if(filename != NULL){
video::ITexture *t = driver->getTexture(filename); video::ITexture *t = driver->getTexture(filename);
if(t == NULL){ if(t == NULL){
@ -1313,9 +1317,9 @@ int main(int argc, char *argv[])
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true); //g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
} }
g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
//g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; //g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
g_materials[MATERIAL_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; g_materials[CONTENT_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
/*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png")); /*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));
g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png")); g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));
@ -1328,8 +1332,18 @@ int main(int argc, char *argv[])
g_mesh_materials[i].setFlag(video::EMF_FOG_ENABLE, true); g_mesh_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
}*/ }*/
// Make a scope here for the client so that it gets removed /*
// before the irrlicht device Preload some random textures that are used in threads
*/
g_texturecache.set("torch", driver->getTexture("../data/torch.png"));
g_texturecache.set("torch_on_floor", driver->getTexture("../data/torch_on_floor.png"));
g_texturecache.set("torch_on_ceiling", driver->getTexture("../data/torch_on_ceiling.png"));
/*
Make a scope here for the client so that it gets removed
before the irrlicht device
*/
{ {
std::cout<<DTIME<<"Creating server and client"<<std::endl; std::cout<<DTIME<<"Creating server and client"<<std::endl;
@ -1380,6 +1394,23 @@ int main(int argc, char *argv[])
std::cout<<DTIME<<"Timed out."<<std::endl; std::cout<<DTIME<<"Timed out."<<std::endl;
return 0; return 0;
} }
/*
Create skybox
*/
scene::ISceneNode* skybox = smgr->addSkyBoxSceneNode(
driver->getTexture("../data/skybox2.png"),
driver->getTexture("../data/skybox3.png"),
driver->getTexture("../data/skybox1.png"),
driver->getTexture("../data/skybox1.png"),
driver->getTexture("../data/skybox1.png"),
driver->getTexture("../data/skybox1.png"));
/* driver->getTexture("../data/irrlicht2_up.jpg"),
driver->getTexture("../data/irrlicht2_dn.jpg"),
driver->getTexture("../data/irrlicht2_lf.jpg"),
driver->getTexture("../data/irrlicht2_rt.jpg"),
driver->getTexture("../data/irrlicht2_ft.jpg"),
driver->getTexture("../data/irrlicht2_bk.jpg"));*/
/* /*
Create the camera node Create the camera node
@ -1862,14 +1893,19 @@ int main(int argc, char *argv[])
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1); s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1); s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
for(s16 y = ystart; y <= yend; y++){ for(s16 y = ystart; y <= yend; y++)
for(s16 z = zstart; z <= zend; z++){ for(s16 z = zstart; z <= zend; z++)
for(s16 x = xstart; x <= xend; x++) for(s16 x = xstart; x <= xend; x++)
{ {
try{ MapNode n;
if(material_pointable(client.getNode(v3s16(x,y,z)).d) == false) try
{
n = client.getNode(v3s16(x,y,z));
if(content_pointable(n.d) == false)
continue; continue;
}catch(InvalidPositionException &e){ }
catch(InvalidPositionException &e)
{
continue; continue;
} }
@ -1878,55 +1914,110 @@ int main(int argc, char *argv[])
f32 d = 0.01; f32 d = 0.01;
v3s16 directions[6] = { v3s16 dirs[6] = {
v3s16(0,0,1), // back v3s16(0,0,1), // back
v3s16(0,1,0), // top v3s16(0,1,0), // top
v3s16(1,0,0), // right v3s16(1,0,0), // right
v3s16(0,0,-1), v3s16(0,0,-1), // front
v3s16(0,-1,0), v3s16(0,-1,0), // bottom
v3s16(-1,0,0), v3s16(-1,0,0), // left
}; };
/*
Meta-objects
*/
if(n.d == CONTENT_LIGHT)
{
v3s16 dir = unpackDir(n.dir);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
f32 distance = (cpf - camera_position).getLength();
for(u16 i=0; i<6; i++){ core::aabbox3d<f32> box;
//{u16 i=3;
v3f dir_f = v3f(directions[i].X,
directions[i].Y, directions[i].Z);
v3f centerpoint = npf + dir_f * BS/2;
f32 distance =
(centerpoint - camera_position).getLength();
if(distance < mindistance){ // bottom
//std::cout<<DTIME<<"for centerpoint=("<<centerpoint.X<<","<<centerpoint.Y<<","<<centerpoint.Z<<"): distance < mindistance"<<std::endl; if(dir == v3s16(0,-1,0))
//std::cout<<DTIME<<"npf=("<<npf.X<<","<<npf.Y<<","<<npf.Z<<")"<<std::endl; {
core::CMatrix4<f32> m; box = core::aabbox3d<f32>(
m.buildRotateFromTo(v3f(0,0,1), dir_f); npf - v3f(BS/6, BS/2, BS/6),
npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
);
}
// top
else if(dir == v3s16(0,1,0))
{
box = core::aabbox3d<f32>(
npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
npf + v3f(BS/6, BS/2, BS/6)
);
}
// side
else
{
box = core::aabbox3d<f32>(
cpf - v3f(BS/6, BS/3, BS/6),
cpf + v3f(BS/6, BS/3, BS/6)
);
}
// This is the back face if(distance < mindistance)
v3f corners[2] = { {
v3f(BS/2, BS/2, BS/2), if(box.intersectsWithLine(shootline))
v3f(-BS/2, -BS/2, BS/2+d) {
};
for(u16 j=0; j<2; j++){
m.rotateVect(corners[j]);
corners[j] += npf;
//std::cout<<DTIME<<"box corners["<<j<<"]: ("<<corners[j].X<<","<<corners[j].Y<<","<<corners[j].Z<<")"<<std::endl;
}
//core::aabbox3d<f32> facebox(corners[0],corners[1]);
core::aabbox3d<f32> facebox(corners[0]);
facebox.addInternalPoint(corners[1]);
if(facebox.intersectsWithLine(shootline)){
nodefound = true; nodefound = true;
nodepos = np; nodepos = np;
neighbourpos = np + directions[i]; neighbourpos = np;
mindistance = distance; mindistance = distance;
nodefacebox = facebox; nodefacebox = box;
} }
} }
} }
}}} /*
Regular blocks
*/
else
{
for(u16 i=0; i<6; i++)
{
v3f dir_f = v3f(dirs[i].X,
dirs[i].Y, dirs[i].Z);
v3f centerpoint = npf + dir_f * BS/2;
f32 distance =
(centerpoint - camera_position).getLength();
if(distance < mindistance)
{
core::CMatrix4<f32> m;
m.buildRotateFromTo(v3f(0,0,1), dir_f);
// This is the back face
v3f corners[2] = {
v3f(BS/2, BS/2, BS/2),
v3f(-BS/2, -BS/2, BS/2+d)
};
for(u16 j=0; j<2; j++)
{
m.rotateVect(corners[j]);
corners[j] += npf;
}
core::aabbox3d<f32> facebox(corners[0]);
facebox.addInternalPoint(corners[1]);
if(facebox.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np + dirs[i];
mindistance = distance;
nodefacebox = facebox;
}
} // if distance < mindistance
} // for dirs
} // regular block
} // for coords
if(nodefound) if(nodefound)
{ {

@ -55,7 +55,9 @@ extern std::ostream *derr_server_ptr;
// This header is only for MATERIALS_COUNT // This header is only for MATERIALS_COUNT
#include "mapnode.h" #include "mapnode.h"
extern video::SMaterial g_materials[MATERIALS_COUNT]; extern video::SMaterial g_materials[MATERIALS_COUNT];
//extern video::SMaterial g_mesh_materials[3];
#include "utility.h"
extern TextureCache g_texturecache;
extern IrrlichtDevice *g_device; extern IrrlichtDevice *g_device;

@ -510,6 +510,10 @@ void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
light_sources.remove(n2pos); light_sources.remove(n2pos);
}*/ }*/
} }
/*// DEBUG
if(light_sources.find(n2pos) != NULL)
light_sources.remove(n2pos);*/
} }
else{ else{
light_sources.insert(n2pos, true); light_sources.insert(n2pos, true);
@ -850,8 +854,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
// Collect borders for unlighting // Collect borders for unlighting
if(x==0 || x == MAP_BLOCKSIZE-1 if(x==0 || x == MAP_BLOCKSIZE-1
|| y==0 || y == MAP_BLOCKSIZE-1 || y==0 || y == MAP_BLOCKSIZE-1
|| z==0 || z == MAP_BLOCKSIZE-1) || z==0 || z == MAP_BLOCKSIZE-1)
{ {
v3s16 p_map = p + v3s16( v3s16 p_map = p + v3s16(
MAP_BLOCKSIZE*pos.X, MAP_BLOCKSIZE*pos.X,
@ -912,6 +916,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
// Yes, add it to light_sources... somehow. // Yes, add it to light_sources... somehow.
// It has to be added at somewhere above, in the loop. // It has to be added at somewhere above, in the loop.
// TODO // TODO
// NOTE: This actually works quite fine without it
// - Find out why it works
{ {
//TimeTaker timer("spreadLight", g_device); //TimeTaker timer("spreadLight", g_device);
@ -1048,7 +1054,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
v3s16 toppos = p + v3s16(0,1,0); v3s16 toppos = p + v3s16(0,1,0);
// Node will be replaced with this // Node will be replaced with this
u8 replace_material = MATERIAL_AIR; u8 replace_material = CONTENT_AIR;
// NOTE: Water is now managed elsewhere // NOTE: Water is now managed elsewhere
#if 0 #if 0
@ -1099,7 +1105,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
if( if(
c > highest_ranking || c > highest_ranking ||
// Prefer something else than air // Prefer something else than air
(c >= highest_ranking && m != MATERIAL_AIR) (c >= highest_ranking && m != CONTENT_AIR)
) )
{ {
@ -1722,17 +1728,91 @@ MapBlock * ServerMap::emergeBlock(
low_block_is_empty = true;*/ low_block_is_empty = true;*/
const s32 ued = 4; const s32 ued = 4;
//const s32 ued = 8;
bool underground_emptiness[ued*ued*ued]; bool underground_emptiness[ued*ued*ued];
for(s32 i=0; i<ued*ued*ued; i++) for(s32 i=0; i<ued*ued*ued; i++)
{ {
underground_emptiness[i] = ((rand() % 4) == 0); underground_emptiness[i] = ((rand() % 5) == 0);
} }
#if 0
/*
This is a messy hack to sort the emptiness a bit
*/
for(s32 j=0; j<2; j++)
for(s32 y0=0; y0<ued; y0++)
for(s32 z0=0; z0<ued; z0++)
for(s32 x0=0; x0<ued; x0++)
{
v3s16 p0(x0,y0,z0);
bool &e0 = underground_emptiness[
ued*ued*(z0*ued/MAP_BLOCKSIZE)
+ued*(y0*ued/MAP_BLOCKSIZE)
+(x0*ued/MAP_BLOCKSIZE)];
v3s16 dirs[6] = {
v3s16(0,0,1), // back
v3s16(1,0,0), // right
v3s16(0,0,-1), // front
v3s16(-1,0,0), // left
/*v3s16(0,1,0), // top
v3s16(0,-1,0), // bottom*/
};
for(s32 i=0; i<4; i++)
{
v3s16 p1 = p0 + dirs[i];
if(isInArea(p1, ued) == false)
continue;
bool &e1 = underground_emptiness[
ued*ued*(p1.Z*ued/MAP_BLOCKSIZE)
+ued*(p1.Y*ued/MAP_BLOCKSIZE)
+(p1.X*ued/MAP_BLOCKSIZE)];
if(e0 == e1)
continue;
v3s16 dirs[6] = {
v3s16(0,1,0), // top
v3s16(0,-1,0), // bottom
/*v3s16(0,0,1), // back
v3s16(1,0,0), // right
v3s16(0,0,-1), // front
v3s16(-1,0,0), // left*/
};
for(s32 i=0; i<2; i++)
{
v3s16 p2 = p1 + dirs[i];
if(p2 == p0)
continue;
if(isInArea(p2, ued) == false)
continue;
bool &e2 = underground_emptiness[
ued*ued*(p2.Z*ued/MAP_BLOCKSIZE)
+ued*(p2.Y*ued/MAP_BLOCKSIZE)
+(p2.X*ued/MAP_BLOCKSIZE)];
if(e2 != e0)
continue;
bool t = e1;
e1 = e2;
e2 = t;
break;
}
//break;
}
}
#endif
// This is the basic material of what the visible flat ground // This is the basic material of what the visible flat ground
// will consist of // will consist of
u8 material = MATERIAL_GRASS; u8 material = CONTENT_GRASS;
u8 water_material = CONTENT_WATER;
if(g_settings.getBool("endless_water"))
water_material = CONTENT_OCEAN;
s32 lowest_ground_y = 32767; s32 lowest_ground_y = 32767;
s32 highest_ground_y = -32768;
// DEBUG // DEBUG
//sector->printHeightmaps(); //sector->printHeightmaps();
@ -1755,14 +1835,19 @@ MapBlock * ServerMap::emergeBlock(
//avg_ground_y += surface_y; //avg_ground_y += surface_y;
if(surface_y < lowest_ground_y) if(surface_y < lowest_ground_y)
lowest_ground_y = surface_y; lowest_ground_y = surface_y;
if(surface_y > highest_ground_y)
highest_ground_y = surface_y;
s32 surface_depth = 0; s32 surface_depth = 0;
float slope = sector->getSlope(v2s16(x0,z0)).getLength(); float slope = sector->getSlope(v2s16(x0,z0)).getLength();
float min_slope = 0.45; //float min_slope = 0.45;
float max_slope = 0.85; //float max_slope = 0.85;
float min_slope_depth = 5.0; float min_slope = 0.70;
float max_slope = 1.20;
float min_slope_depth = 4.0;
//float min_slope_depth = 5.0;
float max_slope_depth = 0; float max_slope_depth = 0;
if(slope < min_slope) if(slope < min_slope)
surface_depth = min_slope_depth; surface_depth = min_slope_depth;
@ -1783,33 +1868,55 @@ MapBlock * ServerMap::emergeBlock(
*/ */
if(real_y > surface_y) if(real_y > surface_y)
n.setLight(LIGHT_SUN); n.setLight(LIGHT_SUN);
/* /*
Calculate material Calculate material
*/ */
// If node is very low // If node is very low
if(real_y <= surface_y - 7){ /*if(real_y <= surface_y - 7)
{
// Create dungeons // Create dungeons
if(underground_emptiness[ if(underground_emptiness[
ued*ued*(z0*ued/MAP_BLOCKSIZE) ued*ued*(z0*ued/MAP_BLOCKSIZE)
+ued*(y0*ued/MAP_BLOCKSIZE) +ued*(y0*ued/MAP_BLOCKSIZE)
+(x0*ued/MAP_BLOCKSIZE)]) +(x0*ued/MAP_BLOCKSIZE)])
{ {
n.d = MATERIAL_AIR; n.d = CONTENT_AIR;
} }
else else
{ {
n.d = MATERIAL_STONE; n.d = CONTENT_STONE;
} }
} }
// If node is under surface level // If node is under surface level
else if(real_y <= surface_y - surface_depth) else if(real_y <= surface_y - surface_depth)
n.d = MATERIAL_STONE; n.d = CONTENT_STONE;
*/
if(real_y <= surface_y - surface_depth)
{
// Create dungeons
if(underground_emptiness[
ued*ued*(z0*ued/MAP_BLOCKSIZE)
+ued*(y0*ued/MAP_BLOCKSIZE)
+(x0*ued/MAP_BLOCKSIZE)])
{
n.d = CONTENT_AIR;
}
else
{
n.d = CONTENT_STONE;
}
}
// If node is at or under heightmap y // If node is at or under heightmap y
else if(real_y <= surface_y) else if(real_y <= surface_y)
{ {
// If under water level, it's mud // If under water level, it's mud
if(real_y < WATER_LEVEL) if(real_y < WATER_LEVEL)
n.d = MATERIAL_MUD; n.d = CONTENT_MUD;
// Only the topmost node is grass
else if(real_y <= surface_y - 1)
n.d = CONTENT_MUD;
// Else it's the main material // Else it's the main material
else else
n.d = material; n.d = material;
@ -1819,13 +1926,12 @@ MapBlock * ServerMap::emergeBlock(
// If under water level, it's water // If under water level, it's water
if(real_y < WATER_LEVEL) if(real_y < WATER_LEVEL)
{ {
//n.d = MATERIAL_WATER; n.d = water_material;
n.d = MATERIAL_OCEAN;
n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1)); n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
} }
// else air // else air
else else
n.d = MATERIAL_AIR; n.d = CONTENT_AIR;
} }
block->setNode(v3s16(x0,y0,z0), n); block->setNode(v3s16(x0,y0,z0), n);
} }
@ -1836,15 +1942,17 @@ MapBlock * ServerMap::emergeBlock(
*/ */
// Probably underground if the highest part of block is under lowest // Probably underground if the highest part of block is under lowest
// ground height // ground height
bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y; bool is_underground = (block_y+1) * MAP_BLOCKSIZE <= lowest_ground_y;
block->setIsUnderground(is_underground); block->setIsUnderground(is_underground);
/* /*
Force lighting update if underground. Force lighting update if some part of block is underground
This is needed because of ravines. This is needed because of caves.
*/ */
if(is_underground) bool some_part_underground = (block_y+0) * MAP_BLOCKSIZE < highest_ground_y;
if(some_part_underground)
//if(is_underground)
{ {
lighting_invalidated_blocks[block->getPos()] = block; lighting_invalidated_blocks[block->getPos()] = block;
} }
@ -1867,15 +1975,15 @@ MapBlock * ServerMap::emergeBlock(
); );
MapNode n; MapNode n;
n.d = MATERIAL_MESE; n.d = CONTENT_MESE;
if(is_ground_material(block->getNode(cp).d)) if(is_ground_content(block->getNode(cp).d))
if(rand()%8 == 0) if(rand()%8 == 0)
block->setNode(cp, n); block->setNode(cp, n);
for(u16 i=0; i<26; i++) for(u16 i=0; i<26; i++)
{ {
if(is_ground_material(block->getNode(cp+g_26dirs[i]).d)) if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
if(rand()%8 == 0) if(rand()%8 == 0)
block->setNode(cp+g_26dirs[i], n); block->setNode(cp+g_26dirs[i], n);
} }
@ -1897,7 +2005,7 @@ MapBlock * ServerMap::emergeBlock(
); );
// Check that the place is empty // Check that the place is empty
//if(!is_ground_material(block->getNode(cp).d)) //if(!is_ground_content(block->getNode(cp).d))
if(1) if(1)
{ {
RatObject *obj = new RatObject(NULL, -1, intToFloat(cp)); RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
@ -1978,7 +2086,7 @@ MapBlock * ServerMap::emergeBlock(
p + v3s16(0,0,0), &changed_blocks_sector)) p + v3s16(0,0,0), &changed_blocks_sector))
{ {
MapNode n; MapNode n;
n.d = MATERIAL_LIGHT; n.d = CONTENT_LIGHT;
sector->setNode(p, n); sector->setNode(p, n);
objects_to_remove.push_back(p); objects_to_remove.push_back(p);
} }
@ -1991,13 +2099,13 @@ MapBlock * ServerMap::emergeBlock(
&changed_blocks_sector)) &changed_blocks_sector))
{ {
MapNode n; MapNode n;
n.d = MATERIAL_TREE; n.d = CONTENT_TREE;
sector->setNode(p+v3s16(0,0,0), n); sector->setNode(p+v3s16(0,0,0), n);
sector->setNode(p+v3s16(0,1,0), n); sector->setNode(p+v3s16(0,1,0), n);
sector->setNode(p+v3s16(0,2,0), n); sector->setNode(p+v3s16(0,2,0), n);
sector->setNode(p+v3s16(0,3,0), n); sector->setNode(p+v3s16(0,3,0), n);
n.d = MATERIAL_LEAVES; n.d = CONTENT_LEAVES;
sector->setNode(p+v3s16(0,4,0), n); sector->setNode(p+v3s16(0,4,0), n);
@ -2032,7 +2140,7 @@ MapBlock * ServerMap::emergeBlock(
p + v3s16(0,0,0), &changed_blocks_sector)) p + v3s16(0,0,0), &changed_blocks_sector))
{ {
MapNode n; MapNode n;
n.d = MATERIAL_LEAVES; n.d = CONTENT_LEAVES;
sector->setNode(p+v3s16(0,0,0), n); sector->setNode(p+v3s16(0,0,0), n);
objects_to_remove.push_back(p); objects_to_remove.push_back(p);
@ -2047,9 +2155,9 @@ MapBlock * ServerMap::emergeBlock(
&changed_blocks_sector)) &changed_blocks_sector))
{ {
MapNode n; MapNode n;
n.d = MATERIAL_STONE; n.d = CONTENT_STONE;
MapNode n2; MapNode n2;
n2.d = MATERIAL_AIR; n2.d = CONTENT_AIR;
s16 depth = maxdepth + (rand()%10); s16 depth = maxdepth + (rand()%10);
s16 z = 0; s16 z = 0;
s16 minz = -6 - (-2); s16 minz = -6 - (-2);
@ -2067,22 +2175,22 @@ MapBlock * ServerMap::emergeBlock(
<<std::endl;*/ <<std::endl;*/
{ {
v3s16 p2 = p + v3s16(x,y,z-2); v3s16 p2 = p + v3s16(x,y,z-2);
if(is_ground_material(sector->getNode(p2).d)) if(is_ground_content(sector->getNode(p2).d))
sector->setNode(p2, n); sector->setNode(p2, n);
} }
{ {
v3s16 p2 = p + v3s16(x,y,z-1); v3s16 p2 = p + v3s16(x,y,z-1);
if(is_ground_material(sector->getNode(p2).d)) if(is_ground_content(sector->getNode(p2).d))
sector->setNode(p2, n2); sector->setNode(p2, n2);
} }
{ {
v3s16 p2 = p + v3s16(x,y,z+0); v3s16 p2 = p + v3s16(x,y,z+0);
if(is_ground_material(sector->getNode(p2).d)) if(is_ground_content(sector->getNode(p2).d))
sector->setNode(p2, n2); sector->setNode(p2, n2);
} }
{ {
v3s16 p2 = p + v3s16(x,y,z+1); v3s16 p2 = p + v3s16(x,y,z+1);
if(is_ground_material(sector->getNode(p2).d)) if(is_ground_content(sector->getNode(p2).d))
sector->setNode(p2, n); sector->setNode(p2, n);
} }
@ -3100,7 +3208,7 @@ void ClientMap::updateMesh()
/*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount() /*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
<<std::endl; <<std::endl;
scene::IMeshBuffer *buf = mesh_new->getMeshBuffer scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
(g_materials[MATERIAL_GRASS]); (g_materials[CONTENT_GRASS]);
if(buf != NULL) if(buf != NULL)
dstream<<"grass buf refcount="<<buf->getReferenceCount() dstream<<"grass buf refcount="<<buf->getReferenceCount()
<<std::endl;*/ <<std::endl;*/

@ -111,7 +111,7 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p,
u8 alpha = 255; u8 alpha = 255;
if(material == MATERIAL_WATER || material == MATERIAL_OCEAN) if(material == CONTENT_WATER || material == CONTENT_OCEAN)
{ {
alpha = 128; alpha = 128;
} }
@ -152,7 +152,11 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
MapNode n = getNodeParent(p); MapNode n = getNodeParent(p);
MapNode n2 = getNodeParent(p + face_dir); MapNode n2 = getNodeParent(p + face_dir);
u8 light; u8 light;
if(n.solidness() < n2.solidness()) /*if(n.solidness() < n2.solidness())
light = n.getLight();
else
light = n2.getLight();*/
if(n.getLight() > n2.getLight())
light = n.getLight(); light = n.getLight();
else else
light = n2.getLight(); light = n2.getLight();
@ -173,18 +177,18 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
/* /*
Gets node material from any place relative to block. Gets node material from any place relative to block.
Returns MATERIAL_IGNORE if doesn't exist or should not be drawn. Returns CONTENT_IGNORE if doesn't exist or should not be drawn.
*/ */
u8 MapBlock::getNodeMaterial(v3s16 p) u8 MapBlock::getNodeTile(v3s16 p)
{ {
try{ try{
MapNode n = getNodeParent(p); MapNode n = getNodeParent(p);
return content_cube_material(n.d); return content_tile(n.d);
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{ {
return MATERIAL_IGNORE; return CONTENT_IGNORE;
} }
} }
@ -216,82 +220,82 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
*/ */
u8 light = getFaceLight(p, face_dir); u8 light = getFaceLight(p, face_dir);
u16 continuous_materials_count = 0; u16 continuous_tiles_count = 0;
u8 material0 = getNodeMaterial(p); u8 tile0 = getNodeTile(p);
u8 material1 = getNodeMaterial(p + face_dir); u8 tile1 = getNodeTile(p + face_dir);
for(u16 j=0; j<length; j++) for(u16 j=0; j<length; j++)
{ {
bool next_is_different = true; bool next_is_different = true;
v3s16 p_next; v3s16 p_next;
u8 material0_next = 0; u8 tile0_next = 0;
u8 material1_next = 0; u8 tile1_next = 0;
u8 light_next = 0; u8 light_next = 0;
if(j != length - 1){ if(j != length - 1){
p_next = p + translate_dir; p_next = p + translate_dir;
material0_next = getNodeMaterial(p_next); tile0_next = getNodeTile(p_next);
material1_next = getNodeMaterial(p_next + face_dir); tile1_next = getNodeTile(p_next + face_dir);
light_next = getFaceLight(p_next, face_dir); light_next = getFaceLight(p_next, face_dir);
if(material0_next == material0 if(tile0_next == tile0
&& material1_next == material1 && tile1_next == tile1
&& light_next == light) && light_next == light)
{ {
next_is_different = false; next_is_different = false;
} }
} }
continuous_materials_count++; continuous_tiles_count++;
if(next_is_different) if(next_is_different)
{ {
/* /*
Create a face if there should be one Create a face if there should be one
*/ */
u8 mf = face_materials(material0, material1); u8 mf = face_contents(tile0, tile1);
if(mf != 0) if(mf != 0)
{ {
// Floating point conversion of the position vector // Floating point conversion of the position vector
v3f pf(p.X, p.Y, p.Z); v3f pf(p.X, p.Y, p.Z);
// Center point of face (kind of) // Center point of face (kind of)
v3f sp = pf - ((f32)continuous_materials_count / 2. - 0.5) * translate_dir_f; v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
v3f scale(1,1,1); v3f scale(1,1,1);
if(translate_dir.X != 0){ if(translate_dir.X != 0){
scale.X = continuous_materials_count; scale.X = continuous_tiles_count;
} }
if(translate_dir.Y != 0){ if(translate_dir.Y != 0){
scale.Y = continuous_materials_count; scale.Y = continuous_tiles_count;
} }
if(translate_dir.Z != 0){ if(translate_dir.Z != 0){
scale.Z = continuous_materials_count; scale.Z = continuous_tiles_count;
} }
FastFace *f; FastFace *f;
// If node at sp (material0) is more solid // If node at sp (tile0) is more solid
if(mf == 1) if(mf == 1)
{ {
f = makeFastFace(material0, light, f = makeFastFace(tile0, light,
sp, face_dir_f, scale, sp, face_dir_f, scale,
posRelative_f); posRelative_f);
} }
// If node at sp is less solid (mf == 2) // If node at sp is less solid (mf == 2)
else else
{ {
f = makeFastFace(material1, light, f = makeFastFace(tile1, light,
sp+face_dir_f, -1*face_dir_f, scale, sp+face_dir_f, -1*face_dir_f, scale,
posRelative_f); posRelative_f);
} }
dest.push_back(f); dest.push_back(f);
} }
continuous_materials_count = 0; continuous_tiles_count = 0;
material0 = material0_next; tile0 = tile0_next;
material1 = material1_next; tile1 = tile1_next;
light = light_next; light = light_next;
} }
@ -451,6 +455,8 @@ void MapBlock::updateMesh()
scene::SMesh *mesh_new = NULL; scene::SMesh *mesh_new = NULL;
mesh_new = new scene::SMesh();
if(fastfaces_new->getSize() > 0) if(fastfaces_new->getSize() > 0)
{ {
MeshCollector collector; MeshCollector collector;
@ -467,8 +473,6 @@ void MapBlock::updateMesh()
indices, 6); indices, 6);
} }
mesh_new = new scene::SMesh();
collector.fillMesh(mesh_new); collector.fillMesh(mesh_new);
// Use VBO for mesh (this just would set this for ever buffer) // Use VBO for mesh (this just would set this for ever buffer)
@ -495,13 +499,103 @@ void MapBlock::updateMesh()
/* /*
Add special graphics: Add special graphics:
- torches - torches
TODO: Optimize by using same meshbuffer for same textures
*/ */
/*scene::ISceneManager *smgr = NULL;
video::IVideoDriver* driver = NULL;
if(g_device)
{
smgr = g_device->getSceneManager();
driver = smgr->getVideoDriver();
}*/
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++)
{ {
v3s16 p(x,y,z); v3s16 p(x,y,z);
MapNode &n = getNodeRef(x,y,z);
if(n.d == CONTENT_LIGHT)
{
//scene::IMeshBuffer *buf = new scene::SMeshBuffer();
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
};
v3s16 dir = unpackDir(n.dir);
for(s32 i=0; i<4; i++)
{
if(dir == v3s16(1,0,0))
vertices[i].Pos.rotateXZBy(0);
if(dir == v3s16(-1,0,0))
vertices[i].Pos.rotateXZBy(180);
if(dir == v3s16(0,0,1))
vertices[i].Pos.rotateXZBy(90);
if(dir == v3s16(0,0,-1))
vertices[i].Pos.rotateXZBy(-90);
if(dir == v3s16(0,-1,0))
vertices[i].Pos.rotateXZBy(45);
if(dir == v3s16(0,1,0))
vertices[i].Pos.rotateXZBy(-45);
vertices[i].Pos += intToFloat(p + getPosRelative());
}
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
//buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
buf->getMaterial().MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
if(dir == v3s16(0,-1,0))
buf->getMaterial().setTexture(0,
g_texturecache.get("torch_on_floor"));
else if(dir == v3s16(0,1,0))
buf->getMaterial().setTexture(0,
g_texturecache.get("torch_on_ceiling"));
// For backwards compatibility
else if(dir == v3s16(0,0,0))
buf->getMaterial().setTexture(0,
g_texturecache.get("torch_on_floor"));
else
buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
// Add to mesh
mesh_new->addMeshBuffer(buf);
buf->drop();
}
}
/*
Do some stuff to the mesh
*/
mesh_new->recalculateBoundingBox();
/*
Delete new mesh if it is empty
*/
if(mesh_new->getMeshBufferCount() == 0)
{
mesh_new->drop();
mesh_new = NULL;
} }
/* /*
@ -681,6 +775,11 @@ void MapBlock::copyTo(VoxelManipulator &dst)
getPosRelative(), data_size); getPosRelative(), data_size);
} }
/*void getPseudoObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest)
{
}*/
/* /*
Serialization Serialization
*/ */

@ -288,11 +288,7 @@ public:
u8 getFaceLight(v3s16 p, v3s16 face_dir); u8 getFaceLight(v3s16 p, v3s16 face_dir);
/* u8 getNodeTile(v3s16 p);
Gets node material from any place relative to block.
Returns MATERIAL_AIR if doesn't exist.
*/
u8 getNodeMaterial(v3s16 p);
/* /*
startpos: startpos:
@ -376,6 +372,9 @@ public:
m_objects.getObjects(origin, max_d, dest); m_objects.getObjects(origin, max_d, dest);
} }
/*void getPseudoObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest);*/
s32 getObjectCount() s32 getObjectCount()
{ {
return m_objects.getCount(); return m_objects.getCount();

@ -145,7 +145,7 @@ void MovingObject::move(float dtime, v3f acceleration)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++) for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
{ {
try{ try{
if(material_walkable(m_block->getNodeParent(v3s16(x,y,z)).d) if(content_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
== false) == false)
continue; continue;
} }

@ -28,13 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h" #include "constants.h"
#include "debug.h" #include "debug.h"
enum #define MAPBLOCKOBJECT_TYPE_TEST 0
{ #define MAPBLOCKOBJECT_TYPE_TEST2 1
MAPBLOCKOBJECT_TYPE_TEST=0, #define MAPBLOCKOBJECT_TYPE_SIGN 2
MAPBLOCKOBJECT_TYPE_TEST2=1, #define MAPBLOCKOBJECT_TYPE_RAT 3
MAPBLOCKOBJECT_TYPE_SIGN=2, // Used for handling selecting special stuff
MAPBLOCKOBJECT_TYPE_RAT=3, //#define MAPBLOCKOBJECT_TYPE_PSEUDO 4
};
class MapBlock; class MapBlock;
@ -170,6 +169,57 @@ protected:
friend class MapBlockObjectList; friend class MapBlockObjectList;
}; };
#if 0
/*
Used for handling selections of special stuff
*/
class PseudoMBObject : public MapBlockObject
{
public:
// The constructor of every MapBlockObject should be like this
PseudoMBObject(MapBlock *block, s16 id, v3f pos):
MapBlockObject(block, id, pos)
{
}
virtual ~PseudoMBObject()
{
if(m_selection_box)
delete m_selection_box;
}
/*
Implementation interface
*/
virtual u16 getTypeId() const
{
return MAPBLOCKOBJECT_TYPE_PSEUDO;
}
virtual void serialize(std::ostream &os, u8 version)
{
assert(0);
}
virtual void update(std::istream &is, u8 version)
{
assert(0);
}
virtual bool serverStep(float dtime)
{
assert(0);
}
/*
Special methods
*/
void setSelectionBox(core::aabbox3d<f32> box)
{
m_selection_box = new core::aabbox3d<f32>(box);
}
protected:
};
#endif
class TestObject : public MapBlockObject class TestObject : public MapBlockObject
{ {
public: public:

@ -41,66 +41,68 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Doesn't create faces with anything and is considered being Doesn't create faces with anything and is considered being
out-of-map in the game map. out-of-map in the game map.
*/ */
#define MATERIAL_IGNORE 255 #define CONTENT_IGNORE 255
#define MATERIAL_IGNORE_DEFAULT_PARAM 0 #define CONTENT_IGNORE_DEFAULT_PARAM 0
/* /*
The common material through which the player can walk and which The common material through which the player can walk and which
is transparent to light is transparent to light
*/ */
#define MATERIAL_AIR 254 #define CONTENT_AIR 254
/* /*
Materials-todo: Suggested materials:
GRAVEL GRAVEL
- Dynamics of gravel: if there is a drop of more than two - Dynamics of gravel: if there is a drop of more than two
blocks on any side, it will drop in there. Is this doable? blocks on any side, it will drop in there. Is this doable?
TODO: These should be named to "content" or something like that New naming scheme:
- Material = irrlicht's Material class
- Content = (u8) content of a node
- Tile = (u16) Material ID at some side of a node
*/ */
enum Material enum Content
{ {
MATERIAL_STONE=0, CONTENT_STONE=0,
MATERIAL_GRASS, CONTENT_GRASS,
MATERIAL_WATER, CONTENT_WATER,
MATERIAL_LIGHT, CONTENT_LIGHT,
MATERIAL_TREE, CONTENT_TREE,
MATERIAL_LEAVES, CONTENT_LEAVES,
MATERIAL_GRASS_FOOTSTEPS, CONTENT_GRASS_FOOTSTEPS,
MATERIAL_MESE, CONTENT_MESE,
MATERIAL_MUD, CONTENT_MUD,
MATERIAL_OCEAN, CONTENT_OCEAN,
// This is set to the number of the actual values in this enum // This is set to the number of the actual values in this enum
USEFUL_MATERIAL_COUNT USEFUL_CONTENT_COUNT
}; };
/* /*
If true, the material allows light propagation and brightness is stored If true, the material allows light propagation and brightness is stored
in param. in param.
*/ */
inline bool light_propagates_material(u8 m) inline bool light_propagates_content(u8 m)
{ {
return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER || m == MATERIAL_OCEAN); return (m == CONTENT_AIR || m == CONTENT_LIGHT || m == CONTENT_WATER || m == CONTENT_OCEAN);
} }
/* /*
If true, the material allows lossless sunlight propagation. If true, the material allows lossless sunlight propagation.
*/ */
inline bool sunlight_propagates_material(u8 m) inline bool sunlight_propagates_content(u8 m)
{ {
return (m == MATERIAL_AIR); return (m == CONTENT_AIR || m == CONTENT_LIGHT);
} }
/* /*
@ -110,98 +112,157 @@ inline bool sunlight_propagates_material(u8 m)
1: Transparent 1: Transparent
2: Opaque 2: Opaque
*/ */
inline u8 material_solidness(u8 m) inline u8 content_solidness(u8 m)
{ {
if(m == MATERIAL_AIR) if(m == CONTENT_AIR)
return 0; return 0;
if(m == MATERIAL_WATER || m == MATERIAL_OCEAN) if(m == CONTENT_WATER || m == CONTENT_OCEAN)
return 1; return 1;
return 2; return 2;
} }
// Objects collide with walkable materials // Objects collide with walkable contents
inline bool material_walkable(u8 m) inline bool content_walkable(u8 m)
{ {
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN && m != MATERIAL_LIGHT); return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN && m != CONTENT_LIGHT);
} }
// A liquid resists fast movement // A liquid resists fast movement
inline bool material_liquid(u8 m) inline bool content_liquid(u8 m)
{ {
return (m == MATERIAL_WATER || m == MATERIAL_OCEAN); return (m == CONTENT_WATER || m == CONTENT_OCEAN);
} }
// Pointable materials can be pointed to in the map // Pointable contents can be pointed to in the map
inline bool material_pointable(u8 m) inline bool content_pointable(u8 m)
{ {
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN); return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN);
} }
inline bool material_diggable(u8 m) inline bool content_diggable(u8 m)
{ {
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN); return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN);
} }
inline bool material_buildable_to(u8 m) inline bool content_buildable_to(u8 m)
{ {
return (m == MATERIAL_AIR || m == MATERIAL_WATER || m == MATERIAL_OCEAN); return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_OCEAN);
} }
/* /*
As of now, input is a "material" and the output is a "material" TODO: Make a mapper class for mapping every side of a content
to some tile.
This dumbily maps all sides of content to the tile of the same id.
*/ */
inline u8 content_cube_material(u8 c) inline u8 content_tile(u8 c)
{ {
if(c == MATERIAL_IGNORE || c == MATERIAL_LIGHT) if(c == CONTENT_IGNORE || c == CONTENT_LIGHT)
return MATERIAL_AIR; return CONTENT_AIR;
return c; return c;
} }
/* /*
Returns true for materials that form the base ground that Returns true for contents that form the base ground that
follows the main heightmap follows the main heightmap
*/ */
inline bool is_ground_material(u8 m) inline bool is_ground_content(u8 m)
{ {
return( return(
m == MATERIAL_STONE || m == CONTENT_STONE ||
m == MATERIAL_GRASS || m == CONTENT_GRASS ||
m == MATERIAL_GRASS_FOOTSTEPS || m == CONTENT_GRASS_FOOTSTEPS ||
m == MATERIAL_MESE || m == CONTENT_MESE ||
m == MATERIAL_MUD m == CONTENT_MUD
); );
} }
/* /*
Nodes make a face if materials differ and solidness differs. Nodes make a face if contents differ and solidness differs.
Return value: Return value:
0: No face 0: No face
1: Face uses m1's material 1: Face uses m1's content
2: Face uses m2's material 2: Face uses m2's content
*/ */
inline u8 face_materials(u8 m1, u8 m2) inline u8 face_contents(u8 m1, u8 m2)
{ {
if(m1 == MATERIAL_IGNORE || m2 == MATERIAL_IGNORE) if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
return 0; return 0;
bool materials_differ = (m1 != m2); bool contents_differ = (m1 != m2);
bool solidness_differs = (material_solidness(m1) != material_solidness(m2)); bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
bool makes_face = materials_differ && solidness_differs; bool makes_face = contents_differ && solidness_differs;
if(makes_face == false) if(makes_face == false)
return 0; return 0;
if(material_solidness(m1) > material_solidness(m2)) if(content_solidness(m1) > content_solidness(m2))
return 1; return 1;
else else
return 2; return 2;
} }
inline bool liquid_replaces_content(u8 c)
{
return (c == CONTENT_AIR || c == CONTENT_LIGHT);
}
/*
When placing a node, drection info is added to it if this is true
*/
inline bool content_directional(u8 c)
{
return (c == CONTENT_LIGHT);
}
/*
Packs directions like (1,0,0), (1,-1,0)
*/
inline u8 packDir(v3s16 dir)
{
u8 b = 0;
if(dir.X > 0)
b |= (1<<0);
else if(dir.X < 0)
b |= (1<<1);
if(dir.Y > 0)
b |= (1<<2);
else if(dir.Y < 0)
b |= (1<<3);
if(dir.Z > 0)
b |= (1<<4);
else if(dir.Z < 0)
b |= (1<<5);
return b;
}
inline v3s16 unpackDir(u8 b)
{
v3s16 d(0,0,0);
if(b & (1<<0))
d.X = 1;
else if(b & (1<<1))
d.X = -1;
if(b & (1<<2))
d.Y = 1;
else if(b & (1<<3))
d.Y = -1;
if(b & (1<<4))
d.Z = 1;
else if(b & (1<<5))
d.Z = -1;
return d;
}
struct MapNode struct MapNode
{ {
//TODO: block type to differ from material // Content
// (e.g. grass edges or something)
// block type
u8 d; u8 d;
/* /*
@ -211,15 +272,27 @@ struct MapNode
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1. Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
*/ */
s8 param; s8 param;
union
{
/*
Pressure for liquids
*/
u8 pressure;
u8 pressure; /*
Direction for torches and other stuff.
If possible, packed with packDir.
*/
u8 dir;
};
MapNode(const MapNode & n) MapNode(const MapNode & n)
{ {
*this = n; *this = n;
} }
MapNode(u8 data=MATERIAL_AIR, u8 a_param=0, u8 a_pressure=0) MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_pressure=0)
{ {
d = data; d = data;
param = a_param; param = a_param;
@ -235,17 +308,17 @@ struct MapNode
bool light_propagates() bool light_propagates()
{ {
return light_propagates_material(d); return light_propagates_content(d);
} }
bool sunlight_propagates() bool sunlight_propagates()
{ {
return sunlight_propagates_material(d); return sunlight_propagates_content(d);
} }
u8 solidness() u8 solidness()
{ {
return material_solidness(d); return content_solidness(d);
} }
u8 light_source() u8 light_source()
@ -253,7 +326,7 @@ struct MapNode
/* /*
Note that a block that isn't light_propagates() can be a light source. Note that a block that isn't light_propagates() can be a light source.
*/ */
if(d == MATERIAL_LIGHT) if(d == CONTENT_LIGHT)
return LIGHT_MAX; return LIGHT_MAX;
return 0; return 0;
@ -261,7 +334,7 @@ struct MapNode
u8 getLight() u8 getLight()
{ {
// Select the brightest of [light_source, transparent_light] // Select the brightest of [light source, propagated light]
u8 light = 0; u8 light = 0;
if(light_propagates()) if(light_propagates())
light = param & 0x0f; light = param & 0x0f;

@ -72,12 +72,12 @@ void Player::move(f32 dtime, Map &map)
if(in_water) if(in_water)
{ {
v3s16 pp = floatToInt(position + v3f(0,0,0)); v3s16 pp = floatToInt(position + v3f(0,0,0));
in_water = material_liquid(map.getNode(pp).d); in_water = content_liquid(map.getNode(pp).d);
} }
else else
{ {
v3s16 pp = floatToInt(position + v3f(0,BS/2,0)); v3s16 pp = floatToInt(position + v3f(0,BS/2,0));
in_water = material_liquid(map.getNode(pp).d); in_water = content_liquid(map.getNode(pp).d);
} }
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -122,7 +122,7 @@ void Player::move(f32 dtime, Map &map)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++){ for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++){
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++){ for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++){
try{ try{
if(material_walkable(map.getNode(v3s16(x,y,z)).d) == false){ if(content_walkable(map.getNode(v3s16(x,y,z)).d) == false){
continue; continue;
} }
} }

@ -94,6 +94,8 @@ void * EmergeThread::Thread()
v3s16 &p = q->pos; v3s16 &p = q->pos;
//derr_server<<"EmergeThread::Thread(): running"<<std::endl; //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
//TimeTaker timer("block emerge", g_device);
/* /*
Try to emerge it from somewhere. Try to emerge it from somewhere.
@ -185,39 +187,32 @@ void * EmergeThread::Thread()
dout_server<<std::endl; dout_server<<std::endl;
} }
/*
Update water pressure
*/
m_server->UpdateBlockWaterPressure(block, modified_blocks);
for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
i.atEnd() == false; i++)
{
MapBlock *block = i.getNode()->getValue();
m_server->UpdateBlockWaterPressure(block, modified_blocks);
//v3s16 p = i.getNode()->getKey();
//m_server->UpdateBlockWaterPressure(p, modified_blocks);
}
/* /*
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.
*/ */
// Add all the "changed blocks" // Add all the "changed blocks" to modified_blocks
for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator(); for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
i.atEnd() == false; i++) i.atEnd() == false; i++)
{ {
MapBlock *block = i.getNode()->getValue(); MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block); modified_blocks.insert(block->getPos(), block);
/*
Update water pressure.
This also adds suitable nodes to active_nodes.
*/
MapVoxelManipulator v(&map);
VoxelArea area(block->getPosRelative(),
block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
try
{
v.updateAreaWaterPressure(area, m_server->m_flow_active_nodes);
}
catch(ProcessingLimitException &e)
{
dstream<<"Processing limit reached (1)"<<std::endl;
}
v.blitBack(modified_blocks);
} }
/*dstream<<"lighting "<<lighting_invalidated_blocks.size() /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
@ -1017,9 +1012,11 @@ void Server::AsyncRunStep()
{ {
JMutexAutoLock lock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
MapVoxelManipulator v(&m_env.getMap()); MapVoxelManipulator v(&m_env.getMap());
v.m_disable_water_climb =
g_settings.getBool("disable_water_climb");
v.flowWater(m_flow_active_nodes, 0, false, 50); v.flowWater(m_flow_active_nodes, 0, false, 50);
@ -1039,7 +1036,7 @@ void Server::AsyncRunStep()
MapBlock *block = i.getNode()->getValue(); MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block); modified_blocks.insert(block->getPos(), block);
} }
} } // envlock
/* /*
Set the modified blocks unsent for all the clients Set the modified blocks unsent for all the clients
@ -1492,7 +1489,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Get material at position // Get material at position
material = m_env.getMap().getNode(p_under).d; material = m_env.getMap().getNode(p_under).d;
// If it's not diggable, do nothing // If it's not diggable, do nothing
if(material_diggable(material) == false) if(content_diggable(material) == false)
{ {
return; return;
} }
@ -1539,6 +1536,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// This also adds it to m_flow_active_nodes if appropriate // This also adds it to m_flow_active_nodes if appropriate
MapVoxelManipulator v(&m_env.getMap()); MapVoxelManipulator v(&m_env.getMap());
v.m_disable_water_climb =
g_settings.getBool("disable_water_climb");
VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1)); VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
@ -1575,15 +1574,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
if(std::string("MaterialItem") == item->getName()) if(std::string("MaterialItem") == item->getName())
{ {
MaterialItem *mitem = (MaterialItem*)item;
MapNode n;
n.d = mitem->getMaterial();
try{ try{
// Don't add a node if this is not a free space // Don't add a node if this is not a free space
MapNode n2 = m_env.getMap().getNode(p_over); MapNode n2 = m_env.getMap().getNode(p_over);
if(material_buildable_to(n2.d) == false) if(content_buildable_to(n2.d) == false)
return; return;
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -1596,17 +1590,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Reset build time counter // Reset build time counter
getClient(peer->id)->m_time_from_building.set(0.0); getClient(peer->id)->m_time_from_building.set(0.0);
if(g_settings.getBool("creative_mode") == false) // Create node data
{ MaterialItem *mitem = (MaterialItem*)item;
// Remove from inventory and send inventory MapNode n;
if(mitem->getCount() == 1) n.d = mitem->getMaterial();
player->inventory.deleteItem(item_i); if(content_directional(n.d))
else n.dir = packDir(p_under - p_over);
mitem->remove(1);
// Send inventory #if 1
SendInventory(peer_id);
}
// Create packet // Create packet
u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver); u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
SharedBuffer<u8> reply(replysize); SharedBuffer<u8> reply(replysize);
@ -1618,6 +1609,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send as reliable // Send as reliable
m_con.SendToAll(0, reply, true); m_con.SendToAll(0, reply, true);
/*
Handle inventory
*/
if(g_settings.getBool("creative_mode") == false)
{
// Remove from inventory and send inventory
if(mitem->getCount() == 1)
player->inventory.deleteItem(item_i);
else
mitem->remove(1);
// Send inventory
SendInventory(peer_id);
}
/* /*
Add node. Add node.
@ -1625,6 +1630,49 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
core::map<v3s16, MapBlock*> modified_blocks; core::map<v3s16, MapBlock*> modified_blocks;
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
#endif
#if 0
/*
Handle inventory
*/
if(g_settings.getBool("creative_mode") == false)
{
// Remove from inventory and send inventory
if(mitem->getCount() == 1)
player->inventory.deleteItem(item_i);
else
mitem->remove(1);
// Send inventory
SendInventory(peer_id);
}
/*
Add node.
This takes some time so it is done after the quick stuff
*/
core::map<v3s16, MapBlock*> modified_blocks;
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
/*
Set the modified blocks unsent for all the clients
*/
//JMutexAutoLock lock2(m_con_mutex);
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
if(modified_blocks.size() > 0)
{
// Remove block from sent history
client->SetBlocksNotSent(modified_blocks);
}
}
#endif
/* /*
Update water Update water
@ -1634,6 +1682,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// This also adds it to m_flow_active_nodes if appropriate // This also adds it to m_flow_active_nodes if appropriate
MapVoxelManipulator v(&m_env.getMap()); MapVoxelManipulator v(&m_env.getMap());
v.m_disable_water_climb =
g_settings.getBool("disable_water_climb");
VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1)); VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1));
@ -1825,6 +1875,8 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
writeS16(&reply[4], p.Y); writeS16(&reply[4], p.Y);
writeS16(&reply[6], p.Z); writeS16(&reply[6], p.Z);
memcpy(&reply[8], *blockdata, blockdata.getSize()); memcpy(&reply[8], *blockdata, blockdata.getSize());
//dstream<<"Sending block: packet size: "<<replysize<<std::endl;
/* /*
Send packet Send packet
@ -1832,107 +1884,6 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
m_con.Send(peer_id, 1, reply, true); m_con.Send(peer_id, 1, reply, true);
} }
/*void Server::SendBlock(u16 peer_id, MapBlock *block, u8 ver)
{
JMutexAutoLock conlock(m_con_mutex);
SendBlockNoLock(peer_id, block, ver);
}*/
#if 0
void Server::SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver)
{
DSTACK(__FUNCTION_NAME);
dstream<<"Server sending sector meta of "
<<ps.getSize()<<" sectors"<<std::endl;
core::list<v2s16>::Iterator i = ps.begin();
core::list<v2s16> sendlist;
for(;;)
{
if(sendlist.size() == 255 || i == ps.end())
{
if(sendlist.size() == 0)
break;
/*
[0] u16 command
[2] u8 sector count
[3...] v2s16 pos + sector metadata
*/
std::ostringstream os(std::ios_base::binary);
u8 buf[4];
writeU16(buf, TOCLIENT_SECTORMETA);
os.write((char*)buf, 2);
writeU8(buf, sendlist.size());
os.write((char*)buf, 1);
for(core::list<v2s16>::Iterator
j = sendlist.begin();
j != sendlist.end(); j++)
{
// Write position
writeV2S16(buf, *j);
os.write((char*)buf, 4);
/*
Write ClientMapSector metadata
*/
/*
[0] u8 serialization version
[1] s16 corners[0]
[3] s16 corners[1]
[5] s16 corners[2]
[7] s16 corners[3]
size = 9
In which corners are in these positions
v2s16(0,0),
v2s16(1,0),
v2s16(1,1),
v2s16(0,1),
*/
// Write version
writeU8(buf, ver);
os.write((char*)buf, 1);
// Write corners
// TODO: Get real values
s16 corners[4];
((ServerMap&)m_env.getMap()).getSectorCorners(*j, corners);
writeS16(buf, corners[0]);
os.write((char*)buf, 2);
writeS16(buf, corners[1]);
os.write((char*)buf, 2);
writeS16(buf, corners[2]);
os.write((char*)buf, 2);
writeS16(buf, corners[3]);
os.write((char*)buf, 2);
}
SharedBuffer<u8> data((u8*)os.str().c_str(), os.str().size());
/*dstream<<"Server::SendSectorMeta(): sending packet"
" with "<<sendlist.size()<<" sectors"<<std::endl;*/
m_con.Send(peer_id, 1, data, true);
if(i == ps.end())
break;
sendlist.clear();
}
sendlist.push_back(*i);
i++;
}
}
#endif
core::list<PlayerInfo> Server::getPlayerInfo() core::list<PlayerInfo> Server::getPlayerInfo()
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -2039,11 +1990,11 @@ void Server::peerAdded(con::Peer *peer)
if(g_settings.getBool("creative_mode")) if(g_settings.getBool("creative_mode"))
{ {
// Give all materials // Give all materials
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE); assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++) for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
{ {
// Skip some materials // Skip some materials
if(i == MATERIAL_OCEAN) if(i == CONTENT_OCEAN)
continue; continue;
InventoryItem *item = new MaterialItem(i, 1); InventoryItem *item = new MaterialItem(i, 1);
@ -2272,4 +2223,27 @@ RemoteClient* Server::getClient(u16 peer_id)
return n->getValue(); return n->getValue();
} }
void Server::UpdateBlockWaterPressure(MapBlock *block,
core::map<v3s16, MapBlock*> &modified_blocks)
{
MapVoxelManipulator v(&m_env.getMap());
v.m_disable_water_climb =
g_settings.getBool("disable_water_climb");
VoxelArea area(block->getPosRelative(),
block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
try
{
v.updateAreaWaterPressure(area, m_flow_active_nodes);
}
catch(ProcessingLimitException &e)
{
dstream<<"Processing limit reached (1)"<<std::endl;
}
v.blitBack(modified_blocks);
}

@ -275,7 +275,7 @@ public:
u8 pending_serialization_version; u8 pending_serialization_version;
RemoteClient(): RemoteClient():
m_time_from_building(0.0) m_time_from_building(9999)
//m_num_blocks_in_emerge_queue(0) //m_num_blocks_in_emerge_queue(0)
{ {
peer_id = 0; peer_id = 0;
@ -450,10 +450,18 @@ private:
// When called, connection mutex should be locked // When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id); RemoteClient* getClient(u16 peer_id);
/*
Update water pressure.
This also adds suitable nodes to active_nodes.
environment has to be locked when calling.
*/
void UpdateBlockWaterPressure(MapBlock *block,
core::map<v3s16, MapBlock*> &modified_blocks);
// NOTE: If connection and environment are both to be locked, // NOTE: If connection and environment are both to be locked,
// environment shall be locked first. // environment shall be locked first.
JMutex m_env_mutex; JMutex m_env_mutex;
Environment m_env; Environment m_env;

@ -133,11 +133,11 @@ struct TestMapNode
MapNode n; MapNode n;
// Default values // Default values
assert(n.d == MATERIAL_AIR); assert(n.d == CONTENT_AIR);
assert(n.getLight() == 0); assert(n.getLight() == 0);
// Transparency // Transparency
n.d = MATERIAL_AIR; n.d = CONTENT_AIR;
assert(n.light_propagates() == true); assert(n.light_propagates() == true);
n.d = 0; n.d = 0;
assert(n.light_propagates() == false); assert(n.light_propagates() == false);
@ -243,11 +243,11 @@ struct TestVoxelManipulator
MapNode n; MapNode n;
//n.pressure = size.Y - y; //n.pressure = size.Y - y;
if(*p == '#') if(*p == '#')
n.d = MATERIAL_STONE; n.d = CONTENT_STONE;
else if(*p == '.') else if(*p == '.')
n.d = MATERIAL_WATER; n.d = CONTENT_WATER;
else if(*p == ' ') else if(*p == ' ')
n.d = MATERIAL_AIR; n.d = CONTENT_AIR;
else else
assert(0); assert(0);
v.setNode(v3s16(x,y,z), n); v.setNode(v3s16(x,y,z), n);
@ -262,8 +262,12 @@ struct TestVoxelManipulator
v.print(dstream, VOXELPRINT_WATERPRESSURE); v.print(dstream, VOXELPRINT_WATERPRESSURE);
s16 highest_y = -32768; s16 highest_y = -32768;
assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == -1); /*
assert(highest_y == 3); NOTE: These are commented out because this behaviour is changed
all the time
*/
//assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == -1);
//assert(highest_y == 3);
/*assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == 3); /*assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == 3);
//assert(highest_y == 3);*/ //assert(highest_y == 3);*/
@ -365,11 +369,11 @@ 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=MATERIAL_AIR and .getLight() = 0 // .d=CONTENT_AIR 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 == MATERIAL_AIR); assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
assert(b.getNode(v3s16(x,y,z)).getLight() == 0); assert(b.getNode(v3s16(x,y,z)).getLight() == 0);
} }
@ -385,7 +389,7 @@ struct TestMapBlock
assert(b.isValidPositionParent(v3s16(0,0,0)) == true); assert(b.isValidPositionParent(v3s16(0,0,0)) == true);
assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true); assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true);
n = b.getNodeParent(v3s16(0,MAP_BLOCKSIZE-1,0)); n = b.getNodeParent(v3s16(0,MAP_BLOCKSIZE-1,0));
assert(n.d == MATERIAL_AIR); assert(n.d == CONTENT_AIR);
// ...but outside the block they should be invalid // ...but outside the block they should be invalid
assert(b.isValidPositionParent(v3s16(-121,2341,0)) == false); assert(b.isValidPositionParent(v3s16(-121,2341,0)) == false);
@ -420,8 +424,8 @@ struct TestMapBlock
n.d = 4; n.d = 4;
b.setNode(p, n); b.setNode(p, n);
assert(b.getNode(p).d == 4); assert(b.getNode(p).d == 4);
assert(b.getNodeMaterial(p) == 4); assert(b.getNodeTile(p) == 4);
assert(b.getNodeMaterial(v3s16(-1,-1,0)) == 5); assert(b.getNodeTile(v3s16(-1,-1,0)) == 5);
/* /*
propagateSunlight() propagateSunlight()
@ -442,7 +446,7 @@ struct TestMapBlock
*/ */
parent.position_valid = true; parent.position_valid = true;
b.setIsUnderground(false); b.setIsUnderground(false);
parent.node.d = MATERIAL_AIR; parent.node.d = CONTENT_AIR;
parent.node.setLight(LIGHT_SUN); parent.node.setLight(LIGHT_SUN);
core::map<v3s16, bool> light_sources; core::map<v3s16, bool> light_sources;
// The bottom block is invalid, because we have a shadowing node // The bottom block is invalid, because we have a shadowing node
@ -493,7 +497,7 @@ struct TestMapBlock
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++){
MapNode n; MapNode n;
n.d = MATERIAL_AIR; n.d = CONTENT_AIR;
n.setLight(0); n.setLight(0);
b.setNode(v3s16(x,y,z), n); b.setNode(v3s16(x,y,z), n);
} }

@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <jmutex.h>
#include <jmutexautolock.h>
extern const v3s16 g_26dirs[26]; extern const v3s16 g_26dirs[26];
@ -808,5 +810,45 @@ private:
core::map<std::string, std::string> m_settings; core::map<std::string, std::string> m_settings;
}; };
/*
A thread-safe texture cache.
This is used so that irrlicht doesn't get called from many threads
*/
class TextureCache
{
public:
TextureCache()
{
m_mutex.Init();
assert(m_mutex.IsInitialized());
}
void set(std::string name, video::ITexture *texture)
{
JMutexAutoLock lock(m_mutex);
m_textures[name] = texture;
}
video::ITexture* get(std::string name)
{
JMutexAutoLock lock(m_mutex);
core::map<std::string, video::ITexture*>::Node *n;
n = m_textures.find(name);
if(n != NULL)
return n->getValue();
return NULL;
}
private:
core::map<std::string, video::ITexture*> m_textures;
JMutex m_mutex;
};
#endif #endif

@ -41,6 +41,7 @@ VoxelManipulator::VoxelManipulator():
m_data(NULL), m_data(NULL),
m_flags(NULL) m_flags(NULL)
{ {
m_disable_water_climb = false;
} }
VoxelManipulator::~VoxelManipulator() VoxelManipulator::~VoxelManipulator()
@ -103,13 +104,13 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
} }
else if(mode == VOXELPRINT_WATERPRESSURE) else if(mode == VOXELPRINT_WATERPRESSURE)
{ {
if(m == MATERIAL_WATER) if(m == CONTENT_WATER)
{ {
c = 'w'; c = 'w';
if(pr <= 9) if(pr <= 9)
c = pr + '0'; c = pr + '0';
} }
else if(m == MATERIAL_AIR) else if(liquid_replaces_content(m))
{ {
c = ' '; c = ' ';
} }
@ -249,7 +250,7 @@ void VoxelManipulator::interpolate(VoxelArea area)
s16 total = 0; s16 total = 0;
s16 airness = 0; s16 airness = 0;
u8 m = MATERIAL_IGNORE; u8 m = CONTENT_IGNORE;
for(s16 i=0; i<8; i++) for(s16 i=0; i<8; i++)
//for(s16 i=0; i<26; i++) //for(s16 i=0; i<26; i++)
@ -263,17 +264,17 @@ void VoxelManipulator::interpolate(VoxelArea area)
MapNode &n = m_data[m_area.index(p2)]; MapNode &n = m_data[m_area.index(p2)];
airness += (n.d == MATERIAL_AIR) ? 1 : -1; airness += (n.d == CONTENT_AIR) ? 1 : -1;
total++; total++;
if(m == MATERIAL_IGNORE && n.d != MATERIAL_AIR) if(m == CONTENT_IGNORE && n.d != CONTENT_AIR)
m = n.d; m = n.d;
} }
// 1 if air, 0 if not // 1 if air, 0 if not
buf[area.index(p)] = airness > -total/2 ? MATERIAL_AIR : m; buf[area.index(p)] = airness > -total/2 ? CONTENT_AIR : m;
//buf[area.index(p)] = airness > -total ? MATERIAL_AIR : m; //buf[area.index(p)] = airness > -total ? CONTENT_AIR : m;
//buf[area.index(p)] = airness >= -7 ? MATERIAL_AIR : m; //buf[area.index(p)] = airness >= -7 ? CONTENT_AIR : m;
} }
for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++) for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++)
@ -366,13 +367,14 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
continue; continue;
MapNode &n = m_data[m_area.index(p2)]; MapNode &n = m_data[m_area.index(p2)];
// Ignore non-liquid nodes // Ignore non-liquid nodes
if(material_liquid(n.d) == false) if(content_liquid(n.d) == false)
continue; continue;
int pr; int pr;
// If at ocean surface // If at ocean surface
if(n.pressure == 1 && n.d == MATERIAL_OCEAN) if(n.pressure == 1 && n.d == CONTENT_OCEAN)
//if(n.pressure == 1) // Causes glitches but is fast
{ {
pr = 1; pr = 1;
} }
@ -463,12 +465,15 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
NOTE: Do not remove anything from there. We cannot know NOTE: Do not remove anything from there. We cannot know
here if some other neighbor of it causes flow. here if some other neighbor of it causes flow.
*/ */
if(n.d == MATERIAL_AIR) if(liquid_replaces_content(n.d))
{ {
bool pressure_causes_flow = false; bool pressure_causes_flow = false;
// If block is at top // If empty block is at top
if(i == 0) if(i == 0)
{ {
if(m_disable_water_climb)
continue;
//if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2) //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
if(pr >= 3) if(pr >= 3)
pressure_causes_flow = true; pressure_causes_flow = true;
@ -495,7 +500,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
} }
// Ignore non-liquid nodes // Ignore non-liquid nodes
if(material_liquid(n.d) == false) if(content_liquid(n.d) == false)
continue; continue;
int pr2 = pr; int pr2 = pr;
@ -511,6 +516,12 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
if(pr2 < 255) if(pr2 < 255)
pr2++; pr2++;
} }
/*if(m_disable_water_climb)
{
if(pr2 > 3)
pr2 = 3;
}*/
// Ignore if correct pressure is already set and is not on // Ignore if correct pressure is already set and is not on
// request_area. // request_area.
@ -556,7 +567,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
continue; continue;
MapNode &n = m_data[m_area.index(p)]; MapNode &n = m_data[m_area.index(p)];
// Ignore non-liquid nodes // Ignore non-liquid nodes
if(material_liquid(n.d) == false) if(content_liquid(n.d) == false)
continue; continue;
if(checked2_clear == false) if(checked2_clear == false)
@ -654,14 +665,18 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED)) if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
return false; return false;
MapNode &n = m_data[m_area.index(removed_pos)]; MapNode &n = m_data[m_area.index(removed_pos)];
// Water can move only to air // Ignore nodes to which the water can't go
if(n.d != MATERIAL_AIR) if(liquid_replaces_content(n.d) == false)
return false; return false;
} }
s32 i; s32 i;
for(i=0; i<6; i++) for(i=0; i<6; i++)
{ {
// Don't raise water from bottom
if(m_disable_water_climb && i == 5)
continue;
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z); p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
u8 f = m_flags[m_area.index(p)]; u8 f = m_flags[m_area.index(p)];
@ -670,7 +685,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
continue; continue;
MapNode &n = m_data[m_area.index(p)]; MapNode &n = m_data[m_area.index(p)];
// Only liquid nodes can move // Only liquid nodes can move
if(material_liquid(n.d) == false) if(content_liquid(n.d) == false)
continue; continue;
// If block is at top, select it always // If block is at top, select it always
if(i == 0) if(i == 0)
@ -704,7 +719,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
u8 m = m_data[m_area.index(p)].d; u8 m = m_data[m_area.index(p)].d;
u8 f = m_flags[m_area.index(p)]; u8 f = m_flags[m_area.index(p)];
if(m == MATERIAL_OCEAN) if(m == CONTENT_OCEAN)
from_ocean = true; from_ocean = true;
// Move air bubble if not taking water from ocean // Move air bubble if not taking water from ocean
@ -714,9 +729,23 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)]; m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
} }
/*
This has to be done to copy the brightness of a light source
correctly. Otherwise unspreadLight will fuck up when water
has replaced a light source.
*/
u8 light = m_data[m_area.index(removed_pos)].getLight();
m_data[m_area.index(removed_pos)].d = m; m_data[m_area.index(removed_pos)].d = m;
m_flags[m_area.index(removed_pos)] = f; m_flags[m_area.index(removed_pos)] = f;
m_data[m_area.index(removed_pos)].setLight(light);
/*// NOTE: HACK: This has to be set to LIGHT_MAX so that
// unspreadLight will clear all light that came from this node.
// Otherwise there will be weird bugs
m_data[m_area.index(removed_pos)].setLight(LIGHT_MAX);*/
// Mark removed_pos checked // Mark removed_pos checked
m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED; m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
@ -728,7 +757,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
/* /*
NOTE: This does not work as-is NOTE: This does not work as-is
if(m == MATERIAL_OCEAN) if(m == CONTENT_OCEAN)
{ {
// If block was raised to surface, increase pressure of // If block was raised to surface, increase pressure of
// source node // source node
@ -795,6 +824,10 @@ find_again:
// They are checked in reverse order compared to the previous loop. // They are checked in reverse order compared to the previous loop.
for(s32 i=5; i>=0; i--) for(s32 i=5; i>=0; i--)
{ {
// Don't try to flow to top
if(m_disable_water_climb && i == 0)
continue;
//v3s16 p = removed_pos + dirs[i]; //v3s16 p = removed_pos + dirs[i];
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z); p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
@ -804,7 +837,7 @@ find_again:
continue; continue;
MapNode &n = m_data[m_area.index(p)]; MapNode &n = m_data[m_area.index(p)];
// Water can only move to air // Water can only move to air
if(n.d != MATERIAL_AIR) if(liquid_replaces_content(n.d) == false)
continue; continue;
// Flow water to node // Flow water to node

@ -502,6 +502,12 @@ public:
//TODO: Would these make any speed improvement? //TODO: Would these make any speed improvement?
//bool m_pressure_route_valid; //bool m_pressure_route_valid;
//v3s16 m_pressure_route_surface; //v3s16 m_pressure_route_surface;
/*
Some settings
*/
bool m_disable_water_climb;
private: private:
}; };