mirror of
https://github.com/moparisthebest/minetest
synced 2024-11-11 11:55:03 -05:00
working nicely
This commit is contained in:
parent
47a593b519
commit
571fb14f94
@ -33,6 +33,12 @@ cp -r data/sign.png $PACKAGEPATH/data/
|
||||
cp -r data/sign_back.png $PACKAGEPATH/data/
|
||||
cp -r data/rat.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
|
||||
|
||||
|
@ -54,5 +54,8 @@
|
||||
#max_simultaneous_block_sends_server_total = 4
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
|
@ -142,9 +142,9 @@ void Environment::step(float dtime)
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
|
||||
try{
|
||||
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);
|
||||
|
||||
// Update mesh on client
|
||||
|
@ -101,4 +101,47 @@ u8 light_decode_table[LIGHT_MAX+1] =
|
||||
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,
|
||||
};*/
|
||||
|
||||
|
||||
|
177
src/main.cpp
177
src/main.cpp
@ -186,13 +186,11 @@ SUGG: Implement a "Fast check queue" (a queue with a map for checking
|
||||
TODO: Proper looking torches.
|
||||
- Signs could be done in the same way?
|
||||
|
||||
TODO: A mapper to map contents to tile names (for each side)
|
||||
|
||||
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;
|
||||
|
||||
const char *g_material_filenames[MATERIALS_COUNT] =
|
||||
const char *g_content_filenames[MATERIALS_COUNT] =
|
||||
{
|
||||
"../data/stone.png",
|
||||
"../data/grass.png",
|
||||
"../data/water.png",
|
||||
"../data/light.png",
|
||||
"../data/torch_on_floor.png",
|
||||
"../data/tree.png",
|
||||
"../data/leaves.png",
|
||||
"../data/grass_footsteps.png",
|
||||
"../data/mese.png",
|
||||
"../data/mud.png",
|
||||
"../data/water.png", // ocean
|
||||
"../data/water.png", // CONTENT_OCEAN
|
||||
};
|
||||
|
||||
// Material cache
|
||||
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
|
||||
JMutex g_range_mutex;
|
||||
@ -320,20 +322,22 @@ void set_default_settings()
|
||||
g_settings.set("random_input", "false");
|
||||
g_settings.set("client_delete_unused_sectors_timeout", "1200");
|
||||
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
|
||||
g_settings.set("creative_mode", "false");
|
||||
g_settings.set("heightmap_blocksize", "128");
|
||||
g_settings.set("height_randmax", "constant 70.0");
|
||||
g_settings.set("heightmap_blocksize", "32");
|
||||
g_settings.set("height_randmax", "constant 50.0");
|
||||
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("ravines_amount", "1.0");
|
||||
g_settings.set("objectdata_interval", "0.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_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)
|
||||
{
|
||||
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++;
|
||||
else
|
||||
g_selected_material = 0;*/
|
||||
@ -1297,7 +1301,7 @@ int main(int argc, char *argv[])
|
||||
g_materials[i].Lighting = false;
|
||||
g_materials[i].BackfaceCulling = false;
|
||||
|
||||
const char *filename = g_material_filenames[i];
|
||||
const char *filename = g_content_filenames[i];
|
||||
if(filename != NULL){
|
||||
video::ITexture *t = driver->getTexture(filename);
|
||||
if(t == NULL){
|
||||
@ -1313,9 +1317,9 @@ int main(int argc, char *argv[])
|
||||
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
|
||||
}
|
||||
|
||||
g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
//g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
|
||||
g_materials[MATERIAL_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
//g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
|
||||
g_materials[CONTENT_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
|
||||
/*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.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);
|
||||
}*/
|
||||
|
||||
// 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;
|
||||
@ -1381,6 +1395,23 @@ int main(int argc, char *argv[])
|
||||
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
|
||||
*/
|
||||
@ -1862,14 +1893,19 @@ int main(int argc, char *argv[])
|
||||
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
|
||||
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
|
||||
|
||||
for(s16 y = ystart; y <= yend; y++){
|
||||
for(s16 z = zstart; z <= zend; z++){
|
||||
for(s16 y = ystart; y <= yend; y++)
|
||||
for(s16 z = zstart; z <= zend; z++)
|
||||
for(s16 x = xstart; x <= xend; x++)
|
||||
{
|
||||
try{
|
||||
if(material_pointable(client.getNode(v3s16(x,y,z)).d) == false)
|
||||
MapNode n;
|
||||
try
|
||||
{
|
||||
n = client.getNode(v3s16(x,y,z));
|
||||
if(content_pointable(n.d) == false)
|
||||
continue;
|
||||
}catch(InvalidPositionException &e){
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1878,26 +1914,80 @@ int main(int argc, char *argv[])
|
||||
|
||||
f32 d = 0.01;
|
||||
|
||||
v3s16 directions[6] = {
|
||||
v3s16 dirs[6] = {
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,0,-1),
|
||||
v3s16(0,-1,0),
|
||||
v3s16(-1,0,0),
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(0,-1,0), // bottom
|
||||
v3s16(-1,0,0), // left
|
||||
};
|
||||
|
||||
for(u16 i=0; i<6; i++){
|
||||
//{u16 i=3;
|
||||
v3f dir_f = v3f(directions[i].X,
|
||||
directions[i].Y, directions[i].Z);
|
||||
/*
|
||||
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();
|
||||
|
||||
core::aabbox3d<f32> box;
|
||||
|
||||
// bottom
|
||||
if(dir == v3s16(0,-1,0))
|
||||
{
|
||||
box = core::aabbox3d<f32>(
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
if(distance < mindistance)
|
||||
{
|
||||
if(box.intersectsWithLine(shootline))
|
||||
{
|
||||
nodefound = true;
|
||||
nodepos = np;
|
||||
neighbourpos = np;
|
||||
mindistance = distance;
|
||||
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){
|
||||
//std::cout<<DTIME<<"for centerpoint=("<<centerpoint.X<<","<<centerpoint.Y<<","<<centerpoint.Z<<"): distance < mindistance"<<std::endl;
|
||||
//std::cout<<DTIME<<"npf=("<<npf.X<<","<<npf.Y<<","<<npf.Z<<")"<<std::endl;
|
||||
if(distance < mindistance)
|
||||
{
|
||||
core::CMatrix4<f32> m;
|
||||
m.buildRotateFromTo(v3f(0,0,1), dir_f);
|
||||
|
||||
@ -1907,26 +1997,27 @@ int main(int argc, char *argv[])
|
||||
v3f(-BS/2, -BS/2, BS/2+d)
|
||||
};
|
||||
|
||||
for(u16 j=0; j<2; j++){
|
||||
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)){
|
||||
if(facebox.intersectsWithLine(shootline))
|
||||
{
|
||||
nodefound = true;
|
||||
nodepos = np;
|
||||
neighbourpos = np + directions[i];
|
||||
neighbourpos = np + dirs[i];
|
||||
mindistance = distance;
|
||||
nodefacebox = facebox;
|
||||
}
|
||||
}
|
||||
}
|
||||
}}}
|
||||
} // if distance < mindistance
|
||||
} // for dirs
|
||||
} // regular block
|
||||
} // for coords
|
||||
|
||||
if(nodefound)
|
||||
{
|
||||
|
@ -55,7 +55,9 @@ extern std::ostream *derr_server_ptr;
|
||||
// This header is only for MATERIALS_COUNT
|
||||
#include "mapnode.h"
|
||||
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;
|
||||
|
||||
|
176
src/map.cpp
176
src/map.cpp
@ -510,6 +510,10 @@ void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
|
||||
light_sources.remove(n2pos);
|
||||
}*/
|
||||
}
|
||||
|
||||
/*// DEBUG
|
||||
if(light_sources.find(n2pos) != NULL)
|
||||
light_sources.remove(n2pos);*/
|
||||
}
|
||||
else{
|
||||
light_sources.insert(n2pos, true);
|
||||
@ -912,6 +916,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
|
||||
// Yes, add it to light_sources... somehow.
|
||||
// It has to be added at somewhere above, in the loop.
|
||||
// TODO
|
||||
// NOTE: This actually works quite fine without it
|
||||
// - Find out why it works
|
||||
|
||||
{
|
||||
//TimeTaker timer("spreadLight", g_device);
|
||||
@ -1048,7 +1054,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||
v3s16 toppos = p + v3s16(0,1,0);
|
||||
|
||||
// Node will be replaced with this
|
||||
u8 replace_material = MATERIAL_AIR;
|
||||
u8 replace_material = CONTENT_AIR;
|
||||
|
||||
// NOTE: Water is now managed elsewhere
|
||||
#if 0
|
||||
@ -1099,7 +1105,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||
if(
|
||||
c > highest_ranking ||
|
||||
// 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;*/
|
||||
|
||||
const s32 ued = 4;
|
||||
//const s32 ued = 8;
|
||||
bool underground_emptiness[ued*ued*ued];
|
||||
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
|
||||
// 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 highest_ground_y = -32768;
|
||||
|
||||
// DEBUG
|
||||
//sector->printHeightmaps();
|
||||
@ -1755,14 +1835,19 @@ MapBlock * ServerMap::emergeBlock(
|
||||
//avg_ground_y += surface_y;
|
||||
if(surface_y < lowest_ground_y)
|
||||
lowest_ground_y = surface_y;
|
||||
if(surface_y > highest_ground_y)
|
||||
highest_ground_y = surface_y;
|
||||
|
||||
s32 surface_depth = 0;
|
||||
|
||||
float slope = sector->getSlope(v2s16(x0,z0)).getLength();
|
||||
|
||||
float min_slope = 0.45;
|
||||
float max_slope = 0.85;
|
||||
float min_slope_depth = 5.0;
|
||||
//float min_slope = 0.45;
|
||||
//float max_slope = 0.85;
|
||||
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;
|
||||
if(slope < min_slope)
|
||||
surface_depth = min_slope_depth;
|
||||
@ -1783,33 +1868,55 @@ MapBlock * ServerMap::emergeBlock(
|
||||
*/
|
||||
if(real_y > surface_y)
|
||||
n.setLight(LIGHT_SUN);
|
||||
|
||||
/*
|
||||
Calculate material
|
||||
*/
|
||||
|
||||
// If node is very low
|
||||
if(real_y <= surface_y - 7){
|
||||
/*if(real_y <= surface_y - 7)
|
||||
{
|
||||
// Create dungeons
|
||||
if(underground_emptiness[
|
||||
ued*ued*(z0*ued/MAP_BLOCKSIZE)
|
||||
+ued*(y0*ued/MAP_BLOCKSIZE)
|
||||
+(x0*ued/MAP_BLOCKSIZE)])
|
||||
{
|
||||
n.d = MATERIAL_AIR;
|
||||
n.d = CONTENT_AIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
n.d = MATERIAL_STONE;
|
||||
n.d = CONTENT_STONE;
|
||||
}
|
||||
}
|
||||
// If node is under surface level
|
||||
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
|
||||
else if(real_y <= surface_y)
|
||||
{
|
||||
// If under water level, it's mud
|
||||
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
|
||||
n.d = material;
|
||||
@ -1819,13 +1926,12 @@ MapBlock * ServerMap::emergeBlock(
|
||||
// If under water level, it's water
|
||||
if(real_y < WATER_LEVEL)
|
||||
{
|
||||
//n.d = MATERIAL_WATER;
|
||||
n.d = MATERIAL_OCEAN;
|
||||
n.d = water_material;
|
||||
n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
|
||||
}
|
||||
// else air
|
||||
else
|
||||
n.d = MATERIAL_AIR;
|
||||
n.d = CONTENT_AIR;
|
||||
}
|
||||
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
|
||||
// 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);
|
||||
|
||||
/*
|
||||
Force lighting update if underground.
|
||||
This is needed because of ravines.
|
||||
Force lighting update if some part of block is underground
|
||||
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;
|
||||
}
|
||||
@ -1867,15 +1975,15 @@ MapBlock * ServerMap::emergeBlock(
|
||||
);
|
||||
|
||||
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)
|
||||
block->setNode(cp, n);
|
||||
|
||||
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)
|
||||
block->setNode(cp+g_26dirs[i], n);
|
||||
}
|
||||
@ -1897,7 +2005,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
);
|
||||
|
||||
// Check that the place is empty
|
||||
//if(!is_ground_material(block->getNode(cp).d))
|
||||
//if(!is_ground_content(block->getNode(cp).d))
|
||||
if(1)
|
||||
{
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
|
||||
@ -1978,7 +2086,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
p + v3s16(0,0,0), &changed_blocks_sector))
|
||||
{
|
||||
MapNode n;
|
||||
n.d = MATERIAL_LIGHT;
|
||||
n.d = CONTENT_LIGHT;
|
||||
sector->setNode(p, n);
|
||||
objects_to_remove.push_back(p);
|
||||
}
|
||||
@ -1991,13 +2099,13 @@ MapBlock * ServerMap::emergeBlock(
|
||||
&changed_blocks_sector))
|
||||
{
|
||||
MapNode n;
|
||||
n.d = MATERIAL_TREE;
|
||||
n.d = CONTENT_TREE;
|
||||
sector->setNode(p+v3s16(0,0,0), n);
|
||||
sector->setNode(p+v3s16(0,1,0), n);
|
||||
sector->setNode(p+v3s16(0,2,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);
|
||||
|
||||
@ -2032,7 +2140,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
p + v3s16(0,0,0), &changed_blocks_sector))
|
||||
{
|
||||
MapNode n;
|
||||
n.d = MATERIAL_LEAVES;
|
||||
n.d = CONTENT_LEAVES;
|
||||
sector->setNode(p+v3s16(0,0,0), n);
|
||||
|
||||
objects_to_remove.push_back(p);
|
||||
@ -2047,9 +2155,9 @@ MapBlock * ServerMap::emergeBlock(
|
||||
&changed_blocks_sector))
|
||||
{
|
||||
MapNode n;
|
||||
n.d = MATERIAL_STONE;
|
||||
n.d = CONTENT_STONE;
|
||||
MapNode n2;
|
||||
n2.d = MATERIAL_AIR;
|
||||
n2.d = CONTENT_AIR;
|
||||
s16 depth = maxdepth + (rand()%10);
|
||||
s16 z = 0;
|
||||
s16 minz = -6 - (-2);
|
||||
@ -2067,22 +2175,22 @@ MapBlock * ServerMap::emergeBlock(
|
||||
<<std::endl;*/
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -3100,7 +3208,7 @@ void ClientMap::updateMesh()
|
||||
/*dstream<<"mesh_old refcount="<<mesh_old->getReferenceCount()
|
||||
<<std::endl;
|
||||
scene::IMeshBuffer *buf = mesh_new->getMeshBuffer
|
||||
(g_materials[MATERIAL_GRASS]);
|
||||
(g_materials[CONTENT_GRASS]);
|
||||
if(buf != NULL)
|
||||
dstream<<"grass buf refcount="<<buf->getReferenceCount()
|
||||
<<std::endl;*/
|
||||
|
157
src/mapblock.cpp
157
src/mapblock.cpp
@ -111,7 +111,7 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p,
|
||||
|
||||
u8 alpha = 255;
|
||||
|
||||
if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
|
||||
if(material == CONTENT_WATER || material == CONTENT_OCEAN)
|
||||
{
|
||||
alpha = 128;
|
||||
}
|
||||
@ -152,7 +152,11 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
|
||||
MapNode n = getNodeParent(p);
|
||||
MapNode n2 = getNodeParent(p + face_dir);
|
||||
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();
|
||||
else
|
||||
light = n2.getLight();
|
||||
@ -173,18 +177,18 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
|
||||
|
||||
/*
|
||||
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{
|
||||
MapNode n = getNodeParent(p);
|
||||
|
||||
return content_cube_material(n.d);
|
||||
return content_tile(n.d);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
return MATERIAL_IGNORE;
|
||||
return CONTENT_IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,82 +220,82 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
|
||||
*/
|
||||
u8 light = getFaceLight(p, face_dir);
|
||||
|
||||
u16 continuous_materials_count = 0;
|
||||
u16 continuous_tiles_count = 0;
|
||||
|
||||
u8 material0 = getNodeMaterial(p);
|
||||
u8 material1 = getNodeMaterial(p + face_dir);
|
||||
u8 tile0 = getNodeTile(p);
|
||||
u8 tile1 = getNodeTile(p + face_dir);
|
||||
|
||||
for(u16 j=0; j<length; j++)
|
||||
{
|
||||
bool next_is_different = true;
|
||||
|
||||
v3s16 p_next;
|
||||
u8 material0_next = 0;
|
||||
u8 material1_next = 0;
|
||||
u8 tile0_next = 0;
|
||||
u8 tile1_next = 0;
|
||||
u8 light_next = 0;
|
||||
|
||||
if(j != length - 1){
|
||||
p_next = p + translate_dir;
|
||||
material0_next = getNodeMaterial(p_next);
|
||||
material1_next = getNodeMaterial(p_next + face_dir);
|
||||
tile0_next = getNodeTile(p_next);
|
||||
tile1_next = getNodeTile(p_next + face_dir);
|
||||
light_next = getFaceLight(p_next, face_dir);
|
||||
|
||||
if(material0_next == material0
|
||||
&& material1_next == material1
|
||||
if(tile0_next == tile0
|
||||
&& tile1_next == tile1
|
||||
&& light_next == light)
|
||||
{
|
||||
next_is_different = false;
|
||||
}
|
||||
}
|
||||
|
||||
continuous_materials_count++;
|
||||
continuous_tiles_count++;
|
||||
|
||||
if(next_is_different)
|
||||
{
|
||||
/*
|
||||
Create a face if there should be one
|
||||
*/
|
||||
u8 mf = face_materials(material0, material1);
|
||||
u8 mf = face_contents(tile0, tile1);
|
||||
|
||||
if(mf != 0)
|
||||
{
|
||||
// Floating point conversion of the position vector
|
||||
v3f pf(p.X, p.Y, p.Z);
|
||||
// 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);
|
||||
if(translate_dir.X != 0){
|
||||
scale.X = continuous_materials_count;
|
||||
scale.X = continuous_tiles_count;
|
||||
}
|
||||
if(translate_dir.Y != 0){
|
||||
scale.Y = continuous_materials_count;
|
||||
scale.Y = continuous_tiles_count;
|
||||
}
|
||||
if(translate_dir.Z != 0){
|
||||
scale.Z = continuous_materials_count;
|
||||
scale.Z = continuous_tiles_count;
|
||||
}
|
||||
|
||||
FastFace *f;
|
||||
|
||||
// If node at sp (material0) is more solid
|
||||
// If node at sp (tile0) is more solid
|
||||
if(mf == 1)
|
||||
{
|
||||
f = makeFastFace(material0, light,
|
||||
f = makeFastFace(tile0, light,
|
||||
sp, face_dir_f, scale,
|
||||
posRelative_f);
|
||||
}
|
||||
// If node at sp is less solid (mf == 2)
|
||||
else
|
||||
{
|
||||
f = makeFastFace(material1, light,
|
||||
f = makeFastFace(tile1, light,
|
||||
sp+face_dir_f, -1*face_dir_f, scale,
|
||||
posRelative_f);
|
||||
}
|
||||
dest.push_back(f);
|
||||
}
|
||||
|
||||
continuous_materials_count = 0;
|
||||
material0 = material0_next;
|
||||
material1 = material1_next;
|
||||
continuous_tiles_count = 0;
|
||||
tile0 = tile0_next;
|
||||
tile1 = tile1_next;
|
||||
light = light_next;
|
||||
}
|
||||
|
||||
@ -451,6 +455,8 @@ void MapBlock::updateMesh()
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
|
||||
mesh_new = new scene::SMesh();
|
||||
|
||||
if(fastfaces_new->getSize() > 0)
|
||||
{
|
||||
MeshCollector collector;
|
||||
@ -467,8 +473,6 @@ void MapBlock::updateMesh()
|
||||
indices, 6);
|
||||
}
|
||||
|
||||
mesh_new = new scene::SMesh();
|
||||
|
||||
collector.fillMesh(mesh_new);
|
||||
|
||||
// Use VBO for mesh (this just would set this for ever buffer)
|
||||
@ -495,13 +499,103 @@ void MapBlock::updateMesh()
|
||||
/*
|
||||
Add special graphics:
|
||||
- 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 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
for(s16 x=0; x<MAP_BLOCKSIZE; x++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*void getPseudoObjects(v3f origin, f32 max_d,
|
||||
core::array<DistanceSortedObject> &dest)
|
||||
{
|
||||
}*/
|
||||
|
||||
/*
|
||||
Serialization
|
||||
*/
|
||||
|
@ -288,11 +288,7 @@ public:
|
||||
|
||||
u8 getFaceLight(v3s16 p, v3s16 face_dir);
|
||||
|
||||
/*
|
||||
Gets node material from any place relative to block.
|
||||
Returns MATERIAL_AIR if doesn't exist.
|
||||
*/
|
||||
u8 getNodeMaterial(v3s16 p);
|
||||
u8 getNodeTile(v3s16 p);
|
||||
|
||||
/*
|
||||
startpos:
|
||||
@ -376,6 +372,9 @@ public:
|
||||
m_objects.getObjects(origin, max_d, dest);
|
||||
}
|
||||
|
||||
/*void getPseudoObjects(v3f origin, f32 max_d,
|
||||
core::array<DistanceSortedObject> &dest);*/
|
||||
|
||||
s32 getObjectCount()
|
||||
{
|
||||
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++)
|
||||
{
|
||||
try{
|
||||
if(material_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
|
||||
if(content_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
|
||||
== false)
|
||||
continue;
|
||||
}
|
||||
|
@ -28,13 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "constants.h"
|
||||
#include "debug.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MAPBLOCKOBJECT_TYPE_TEST=0,
|
||||
MAPBLOCKOBJECT_TYPE_TEST2=1,
|
||||
MAPBLOCKOBJECT_TYPE_SIGN=2,
|
||||
MAPBLOCKOBJECT_TYPE_RAT=3,
|
||||
};
|
||||
#define MAPBLOCKOBJECT_TYPE_TEST 0
|
||||
#define MAPBLOCKOBJECT_TYPE_TEST2 1
|
||||
#define MAPBLOCKOBJECT_TYPE_SIGN 2
|
||||
#define MAPBLOCKOBJECT_TYPE_RAT 3
|
||||
// Used for handling selecting special stuff
|
||||
//#define MAPBLOCKOBJECT_TYPE_PSEUDO 4
|
||||
|
||||
class MapBlock;
|
||||
|
||||
@ -170,6 +169,57 @@ protected:
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
205
src/mapnode.h
205
src/mapnode.h
@ -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
|
||||
out-of-map in the game map.
|
||||
*/
|
||||
#define MATERIAL_IGNORE 255
|
||||
#define MATERIAL_IGNORE_DEFAULT_PARAM 0
|
||||
#define CONTENT_IGNORE 255
|
||||
#define CONTENT_IGNORE_DEFAULT_PARAM 0
|
||||
|
||||
/*
|
||||
The common material through which the player can walk and which
|
||||
is transparent to light
|
||||
*/
|
||||
#define MATERIAL_AIR 254
|
||||
#define CONTENT_AIR 254
|
||||
|
||||
/*
|
||||
Materials-todo:
|
||||
|
||||
Suggested materials:
|
||||
GRAVEL
|
||||
- Dynamics of gravel: if there is a drop of more than two
|
||||
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
|
||||
USEFUL_MATERIAL_COUNT
|
||||
USEFUL_CONTENT_COUNT
|
||||
};
|
||||
|
||||
/*
|
||||
If true, the material allows light propagation and brightness is stored
|
||||
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.
|
||||
*/
|
||||
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
|
||||
2: Opaque
|
||||
*/
|
||||
inline u8 material_solidness(u8 m)
|
||||
inline u8 content_solidness(u8 m)
|
||||
{
|
||||
if(m == MATERIAL_AIR)
|
||||
if(m == CONTENT_AIR)
|
||||
return 0;
|
||||
if(m == MATERIAL_WATER || m == MATERIAL_OCEAN)
|
||||
if(m == CONTENT_WATER || m == CONTENT_OCEAN)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Objects collide with walkable materials
|
||||
inline bool material_walkable(u8 m)
|
||||
// Objects collide with walkable contents
|
||||
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
|
||||
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
|
||||
inline bool material_pointable(u8 m)
|
||||
// Pointable contents can be pointed to in the map
|
||||
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)
|
||||
return MATERIAL_AIR;
|
||||
if(c == CONTENT_IGNORE || c == CONTENT_LIGHT)
|
||||
return CONTENT_AIR;
|
||||
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
|
||||
*/
|
||||
inline bool is_ground_material(u8 m)
|
||||
inline bool is_ground_content(u8 m)
|
||||
{
|
||||
return(
|
||||
m == MATERIAL_STONE ||
|
||||
m == MATERIAL_GRASS ||
|
||||
m == MATERIAL_GRASS_FOOTSTEPS ||
|
||||
m == MATERIAL_MESE ||
|
||||
m == MATERIAL_MUD
|
||||
m == CONTENT_STONE ||
|
||||
m == CONTENT_GRASS ||
|
||||
m == CONTENT_GRASS_FOOTSTEPS ||
|
||||
m == CONTENT_MESE ||
|
||||
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:
|
||||
0: No face
|
||||
1: Face uses m1's material
|
||||
2: Face uses m2's material
|
||||
1: Face uses m1's content
|
||||
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;
|
||||
|
||||
bool materials_differ = (m1 != m2);
|
||||
bool solidness_differs = (material_solidness(m1) != material_solidness(m2));
|
||||
bool makes_face = materials_differ && solidness_differs;
|
||||
bool contents_differ = (m1 != m2);
|
||||
bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
|
||||
bool makes_face = contents_differ && solidness_differs;
|
||||
|
||||
if(makes_face == false)
|
||||
return 0;
|
||||
|
||||
if(material_solidness(m1) > material_solidness(m2))
|
||||
if(content_solidness(m1) > content_solidness(m2))
|
||||
return 1;
|
||||
else
|
||||
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
|
||||
{
|
||||
//TODO: block type to differ from material
|
||||
// (e.g. grass edges or something)
|
||||
// block type
|
||||
// Content
|
||||
u8 d;
|
||||
|
||||
/*
|
||||
@ -212,14 +273,26 @@ struct MapNode
|
||||
*/
|
||||
s8 param;
|
||||
|
||||
union
|
||||
{
|
||||
/*
|
||||
Pressure for liquids
|
||||
*/
|
||||
u8 pressure;
|
||||
|
||||
/*
|
||||
Direction for torches and other stuff.
|
||||
If possible, packed with packDir.
|
||||
*/
|
||||
u8 dir;
|
||||
};
|
||||
|
||||
MapNode(const MapNode & 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;
|
||||
param = a_param;
|
||||
@ -235,17 +308,17 @@ struct MapNode
|
||||
|
||||
bool light_propagates()
|
||||
{
|
||||
return light_propagates_material(d);
|
||||
return light_propagates_content(d);
|
||||
}
|
||||
|
||||
bool sunlight_propagates()
|
||||
{
|
||||
return sunlight_propagates_material(d);
|
||||
return sunlight_propagates_content(d);
|
||||
}
|
||||
|
||||
u8 solidness()
|
||||
{
|
||||
return material_solidness(d);
|
||||
return content_solidness(d);
|
||||
}
|
||||
|
||||
u8 light_source()
|
||||
@ -253,7 +326,7 @@ struct MapNode
|
||||
/*
|
||||
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 0;
|
||||
@ -261,7 +334,7 @@ struct MapNode
|
||||
|
||||
u8 getLight()
|
||||
{
|
||||
// Select the brightest of [light_source, transparent_light]
|
||||
// Select the brightest of [light source, propagated light]
|
||||
u8 light = 0;
|
||||
if(light_propagates())
|
||||
light = param & 0x0f;
|
||||
|
@ -72,12 +72,12 @@ void Player::move(f32 dtime, Map &map)
|
||||
if(in_water)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
@ -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 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++){
|
||||
try{
|
||||
if(material_walkable(map.getNode(v3s16(x,y,z)).d) == false){
|
||||
if(content_walkable(map.getNode(v3s16(x,y,z)).d) == false){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
266
src/server.cpp
266
src/server.cpp
@ -95,6 +95,8 @@ void * EmergeThread::Thread()
|
||||
|
||||
//derr_server<<"EmergeThread::Thread(): running"<<std::endl;
|
||||
|
||||
//TimeTaker timer("block emerge", g_device);
|
||||
|
||||
/*
|
||||
Try to emerge it from somewhere.
|
||||
|
||||
@ -185,39 +187,32 @@ void * EmergeThread::Thread()
|
||||
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
|
||||
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();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
MapBlock *block = i.getNode()->getValue();
|
||||
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()
|
||||
@ -1017,9 +1012,11 @@ void Server::AsyncRunStep()
|
||||
|
||||
{
|
||||
|
||||
JMutexAutoLock lock(m_env_mutex);
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
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);
|
||||
|
||||
@ -1039,7 +1036,7 @@ void Server::AsyncRunStep()
|
||||
MapBlock *block = i.getNode()->getValue();
|
||||
modified_blocks.insert(block->getPos(), block);
|
||||
}
|
||||
}
|
||||
} // envlock
|
||||
|
||||
/*
|
||||
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
|
||||
material = m_env.getMap().getNode(p_under).d;
|
||||
// If it's not diggable, do nothing
|
||||
if(material_diggable(material) == false)
|
||||
if(content_diggable(material) == false)
|
||||
{
|
||||
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
|
||||
|
||||
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));
|
||||
|
||||
@ -1575,15 +1574,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
*/
|
||||
if(std::string("MaterialItem") == item->getName())
|
||||
{
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
|
||||
MapNode n;
|
||||
n.d = mitem->getMaterial();
|
||||
|
||||
try{
|
||||
// Don't add a node if this is not a free space
|
||||
MapNode n2 = m_env.getMap().getNode(p_over);
|
||||
if(material_buildable_to(n2.d) == false)
|
||||
if(content_buildable_to(n2.d) == false)
|
||||
return;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
@ -1596,17 +1590,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Reset build time counter
|
||||
getClient(peer->id)->m_time_from_building.set(0.0);
|
||||
|
||||
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);
|
||||
}
|
||||
// Create node data
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
MapNode n;
|
||||
n.d = mitem->getMaterial();
|
||||
if(content_directional(n.d))
|
||||
n.dir = packDir(p_under - p_over);
|
||||
|
||||
#if 1
|
||||
// Create packet
|
||||
u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
|
||||
SharedBuffer<u8> reply(replysize);
|
||||
@ -1618,6 +1609,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Send as reliable
|
||||
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.
|
||||
|
||||
@ -1625,6 +1630,49 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
*/
|
||||
core::map<v3s16, MapBlock*> 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
|
||||
@ -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
|
||||
|
||||
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));
|
||||
|
||||
@ -1826,113 +1876,14 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
|
||||
writeS16(&reply[6], p.Z);
|
||||
memcpy(&reply[8], *blockdata, blockdata.getSize());
|
||||
|
||||
//dstream<<"Sending block: packet size: "<<replysize<<std::endl;
|
||||
|
||||
/*
|
||||
Send packet
|
||||
*/
|
||||
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()
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
@ -2039,11 +1990,11 @@ void Server::peerAdded(con::Peer *peer)
|
||||
if(g_settings.getBool("creative_mode"))
|
||||
{
|
||||
// Give all materials
|
||||
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
|
||||
for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++)
|
||||
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
|
||||
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
|
||||
{
|
||||
// Skip some materials
|
||||
if(i == MATERIAL_OCEAN)
|
||||
if(i == CONTENT_OCEAN)
|
||||
continue;
|
||||
|
||||
InventoryItem *item = new MaterialItem(i, 1);
|
||||
@ -2272,4 +2223,27 @@ RemoteClient* Server::getClient(u16 peer_id)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
12
src/server.h
12
src/server.h
@ -275,7 +275,7 @@ public:
|
||||
u8 pending_serialization_version;
|
||||
|
||||
RemoteClient():
|
||||
m_time_from_building(0.0)
|
||||
m_time_from_building(9999)
|
||||
//m_num_blocks_in_emerge_queue(0)
|
||||
{
|
||||
peer_id = 0;
|
||||
@ -451,9 +451,17 @@ private:
|
||||
// When called, connection mutex should be locked
|
||||
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,
|
||||
// environment shall be locked first.
|
||||
|
||||
JMutex m_env_mutex;
|
||||
Environment m_env;
|
||||
|
||||
|
32
src/test.cpp
32
src/test.cpp
@ -133,11 +133,11 @@ struct TestMapNode
|
||||
MapNode n;
|
||||
|
||||
// Default values
|
||||
assert(n.d == MATERIAL_AIR);
|
||||
assert(n.d == CONTENT_AIR);
|
||||
assert(n.getLight() == 0);
|
||||
|
||||
// Transparency
|
||||
n.d = MATERIAL_AIR;
|
||||
n.d = CONTENT_AIR;
|
||||
assert(n.light_propagates() == true);
|
||||
n.d = 0;
|
||||
assert(n.light_propagates() == false);
|
||||
@ -243,11 +243,11 @@ struct TestVoxelManipulator
|
||||
MapNode n;
|
||||
//n.pressure = size.Y - y;
|
||||
if(*p == '#')
|
||||
n.d = MATERIAL_STONE;
|
||||
n.d = CONTENT_STONE;
|
||||
else if(*p == '.')
|
||||
n.d = MATERIAL_WATER;
|
||||
n.d = CONTENT_WATER;
|
||||
else if(*p == ' ')
|
||||
n.d = MATERIAL_AIR;
|
||||
n.d = CONTENT_AIR;
|
||||
else
|
||||
assert(0);
|
||||
v.setNode(v3s16(x,y,z), n);
|
||||
@ -262,8 +262,12 @@ struct TestVoxelManipulator
|
||||
v.print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||
|
||||
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(highest_y == 3);*/
|
||||
|
||||
@ -365,11 +369,11 @@ struct TestMapBlock
|
||||
assert(b.getChangedFlag() == false);
|
||||
|
||||
// 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 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -385,7 +389,7 @@ struct TestMapBlock
|
||||
assert(b.isValidPositionParent(v3s16(0,0,0)) == true);
|
||||
assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true);
|
||||
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
|
||||
assert(b.isValidPositionParent(v3s16(-121,2341,0)) == false);
|
||||
@ -420,8 +424,8 @@ struct TestMapBlock
|
||||
n.d = 4;
|
||||
b.setNode(p, n);
|
||||
assert(b.getNode(p).d == 4);
|
||||
assert(b.getNodeMaterial(p) == 4);
|
||||
assert(b.getNodeMaterial(v3s16(-1,-1,0)) == 5);
|
||||
assert(b.getNodeTile(p) == 4);
|
||||
assert(b.getNodeTile(v3s16(-1,-1,0)) == 5);
|
||||
|
||||
/*
|
||||
propagateSunlight()
|
||||
@ -442,7 +446,7 @@ struct TestMapBlock
|
||||
*/
|
||||
parent.position_valid = true;
|
||||
b.setIsUnderground(false);
|
||||
parent.node.d = MATERIAL_AIR;
|
||||
parent.node.d = CONTENT_AIR;
|
||||
parent.node.setLight(LIGHT_SUN);
|
||||
core::map<v3s16, bool> light_sources;
|
||||
// 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 x=0; x<MAP_BLOCKSIZE; x++){
|
||||
MapNode n;
|
||||
n.d = MATERIAL_AIR;
|
||||
n.d = CONTENT_AIR;
|
||||
n.setLight(0);
|
||||
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 <string>
|
||||
#include <sstream>
|
||||
#include <jmutex.h>
|
||||
#include <jmutexautolock.h>
|
||||
|
||||
extern const v3s16 g_26dirs[26];
|
||||
|
||||
@ -808,5 +810,45 @@ private:
|
||||
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
|
||||
|
||||
|
@ -41,6 +41,7 @@ VoxelManipulator::VoxelManipulator():
|
||||
m_data(NULL),
|
||||
m_flags(NULL)
|
||||
{
|
||||
m_disable_water_climb = false;
|
||||
}
|
||||
|
||||
VoxelManipulator::~VoxelManipulator()
|
||||
@ -103,13 +104,13 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
|
||||
}
|
||||
else if(mode == VOXELPRINT_WATERPRESSURE)
|
||||
{
|
||||
if(m == MATERIAL_WATER)
|
||||
if(m == CONTENT_WATER)
|
||||
{
|
||||
c = 'w';
|
||||
if(pr <= 9)
|
||||
c = pr + '0';
|
||||
}
|
||||
else if(m == MATERIAL_AIR)
|
||||
else if(liquid_replaces_content(m))
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
@ -249,7 +250,7 @@ void VoxelManipulator::interpolate(VoxelArea area)
|
||||
|
||||
s16 total = 0;
|
||||
s16 airness = 0;
|
||||
u8 m = MATERIAL_IGNORE;
|
||||
u8 m = CONTENT_IGNORE;
|
||||
|
||||
for(s16 i=0; i<8; 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)];
|
||||
|
||||
airness += (n.d == MATERIAL_AIR) ? 1 : -1;
|
||||
airness += (n.d == CONTENT_AIR) ? 1 : -1;
|
||||
total++;
|
||||
|
||||
if(m == MATERIAL_IGNORE && n.d != MATERIAL_AIR)
|
||||
if(m == CONTENT_IGNORE && n.d != CONTENT_AIR)
|
||||
m = n.d;
|
||||
}
|
||||
|
||||
// 1 if air, 0 if not
|
||||
buf[area.index(p)] = airness > -total/2 ? MATERIAL_AIR : m;
|
||||
//buf[area.index(p)] = airness > -total ? MATERIAL_AIR : m;
|
||||
//buf[area.index(p)] = airness >= -7 ? MATERIAL_AIR : m;
|
||||
buf[area.index(p)] = airness > -total/2 ? CONTENT_AIR : m;
|
||||
//buf[area.index(p)] = airness > -total ? CONTENT_AIR : m;
|
||||
//buf[area.index(p)] = airness >= -7 ? CONTENT_AIR : m;
|
||||
}
|
||||
|
||||
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;
|
||||
MapNode &n = m_data[m_area.index(p2)];
|
||||
// Ignore non-liquid nodes
|
||||
if(material_liquid(n.d) == false)
|
||||
if(content_liquid(n.d) == false)
|
||||
continue;
|
||||
|
||||
int pr;
|
||||
|
||||
// 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;
|
||||
}
|
||||
@ -463,12 +465,15 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
NOTE: Do not remove anything from there. We cannot know
|
||||
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;
|
||||
// If block is at top
|
||||
// If empty block is at top
|
||||
if(i == 0)
|
||||
{
|
||||
if(m_disable_water_climb)
|
||||
continue;
|
||||
|
||||
//if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
|
||||
if(pr >= 3)
|
||||
pressure_causes_flow = true;
|
||||
@ -495,7 +500,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
}
|
||||
|
||||
// Ignore non-liquid nodes
|
||||
if(material_liquid(n.d) == false)
|
||||
if(content_liquid(n.d) == false)
|
||||
continue;
|
||||
|
||||
int pr2 = pr;
|
||||
@ -512,6 +517,12 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
pr2++;
|
||||
}
|
||||
|
||||
/*if(m_disable_water_climb)
|
||||
{
|
||||
if(pr2 > 3)
|
||||
pr2 = 3;
|
||||
}*/
|
||||
|
||||
// Ignore if correct pressure is already set and is not on
|
||||
// request_area.
|
||||
// Thus, request_area can be used for updating as much
|
||||
@ -556,7 +567,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
|
||||
continue;
|
||||
MapNode &n = m_data[m_area.index(p)];
|
||||
// Ignore non-liquid nodes
|
||||
if(material_liquid(n.d) == false)
|
||||
if(content_liquid(n.d) == false)
|
||||
continue;
|
||||
|
||||
if(checked2_clear == false)
|
||||
@ -654,14 +665,18 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
||||
return false;
|
||||
MapNode &n = m_data[m_area.index(removed_pos)];
|
||||
// Water can move only to air
|
||||
if(n.d != MATERIAL_AIR)
|
||||
// Ignore nodes to which the water can't go
|
||||
if(liquid_replaces_content(n.d) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 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);
|
||||
|
||||
u8 f = m_flags[m_area.index(p)];
|
||||
@ -670,7 +685,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
continue;
|
||||
MapNode &n = m_data[m_area.index(p)];
|
||||
// Only liquid nodes can move
|
||||
if(material_liquid(n.d) == false)
|
||||
if(content_liquid(n.d) == false)
|
||||
continue;
|
||||
// If block is at top, select it always
|
||||
if(i == 0)
|
||||
@ -704,7 +719,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
u8 m = m_data[m_area.index(p)].d;
|
||||
u8 f = m_flags[m_area.index(p)];
|
||||
|
||||
if(m == MATERIAL_OCEAN)
|
||||
if(m == CONTENT_OCEAN)
|
||||
from_ocean = true;
|
||||
|
||||
// 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)];
|
||||
}
|
||||
|
||||
/*
|
||||
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_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
|
||||
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
|
||||
if(m == MATERIAL_OCEAN)
|
||||
if(m == CONTENT_OCEAN)
|
||||
{
|
||||
// If block was raised to surface, increase pressure of
|
||||
// source node
|
||||
@ -795,6 +824,10 @@ find_again:
|
||||
// They are checked in reverse order compared to the previous loop.
|
||||
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];
|
||||
p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
|
||||
|
||||
@ -804,7 +837,7 @@ find_again:
|
||||
continue;
|
||||
MapNode &n = m_data[m_area.index(p)];
|
||||
// Water can only move to air
|
||||
if(n.d != MATERIAL_AIR)
|
||||
if(liquid_replaces_content(n.d) == false)
|
||||
continue;
|
||||
|
||||
// Flow water to node
|
||||
|
@ -502,6 +502,12 @@ public:
|
||||
//TODO: Would these make any speed improvement?
|
||||
//bool m_pressure_route_valid;
|
||||
//v3s16 m_pressure_route_surface;
|
||||
|
||||
/*
|
||||
Some settings
|
||||
*/
|
||||
bool m_disable_water_climb;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user