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
#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
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;
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
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,
+};*/
+
TODO: Proper looking torches.\r
- Signs could be done in the same way?\r
\r
+TODO: A mapper to map contents to tile names (for each side)\r
+\r
Doing now:\r
======================================================================\r
\r
-TODO: A system for showing some nodes in some other way than cubes\r
- - Needed for torches\r
- - Also for signs, stairs, etc\r
-\r
======================================================================\r
\r
*/\r
\r
IrrlichtDevice *g_device = NULL;\r
\r
-const char *g_material_filenames[MATERIALS_COUNT] =\r
+const char *g_content_filenames[MATERIALS_COUNT] =\r
{\r
"../data/stone.png",\r
"../data/grass.png",\r
"../data/water.png",\r
- "../data/light.png",\r
+ "../data/torch_on_floor.png",\r
"../data/tree.png",\r
"../data/leaves.png",\r
"../data/grass_footsteps.png",\r
"../data/mese.png",\r
"../data/mud.png",\r
- "../data/water.png", // ocean\r
+ "../data/water.png", // CONTENT_OCEAN\r
};\r
\r
+// Material cache\r
video::SMaterial g_materials[MATERIALS_COUNT];\r
-//video::SMaterial g_mesh_materials[3];\r
+\r
+// Texture cache\r
+TextureCache g_texturecache;\r
+\r
\r
// All range-related stuff below is locked behind this\r
JMutex g_range_mutex;\r
g_settings.set("random_input", "false");\r
g_settings.set("client_delete_unused_sectors_timeout", "1200");\r
g_settings.set("max_block_send_distance", "8");\r
- g_settings.set("max_block_generate_distance", "5");\r
+ g_settings.set("max_block_generate_distance", "6");\r
\r
// Server stuff\r
g_settings.set("creative_mode", "false");\r
- g_settings.set("heightmap_blocksize", "128");\r
- g_settings.set("height_randmax", "constant 70.0");\r
+ g_settings.set("heightmap_blocksize", "32");\r
+ g_settings.set("height_randmax", "constant 50.0");\r
g_settings.set("height_randfactor", "constant 0.6");\r
- g_settings.set("height_base", "linear 0 35 0");\r
+ g_settings.set("height_base", "linear 0 0 0");\r
g_settings.set("plants_amount", "1.0");\r
g_settings.set("ravines_amount", "1.0");\r
g_settings.set("objectdata_interval", "0.2");\r
g_settings.set("active_object_range", "2");\r
g_settings.set("max_simultaneous_block_sends_per_client", "1");\r
g_settings.set("max_simultaneous_block_sends_server_total", "4");\r
+ g_settings.set("disable_water_climb", "true");\r
+ g_settings.set("endless_water", "true");\r
}\r
\r
/*\r
if(counter1 < 0.0)\r
{\r
counter1 = 0.1*Rand(1,10);\r
- /*if(g_selected_material < USEFUL_MATERIAL_COUNT-1)\r
+ /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)\r
g_selected_material++;\r
else\r
g_selected_material = 0;*/\r
g_materials[i].Lighting = false;\r
g_materials[i].BackfaceCulling = false;\r
\r
- const char *filename = g_material_filenames[i];\r
+ const char *filename = g_content_filenames[i];\r
if(filename != NULL){\r
video::ITexture *t = driver->getTexture(filename);\r
if(t == NULL){\r
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);\r
}\r
\r
- g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
- //g_materials[MATERIAL_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
- g_materials[MATERIAL_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
+ g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
+ //g_materials[CONTENT_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
+ g_materials[CONTENT_OCEAN].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;\r
\r
/*g_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));\r
g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));\r
g_mesh_materials[i].setFlag(video::EMF_FOG_ENABLE, true);\r
}*/\r
\r
- // Make a scope here for the client so that it gets removed\r
- // before the irrlicht device\r
+ /*\r
+ Preload some random textures that are used in threads\r
+ */\r
+ \r
+ g_texturecache.set("torch", driver->getTexture("../data/torch.png"));\r
+ g_texturecache.set("torch_on_floor", driver->getTexture("../data/torch_on_floor.png"));\r
+ g_texturecache.set("torch_on_ceiling", driver->getTexture("../data/torch_on_ceiling.png"));\r
+\r
+ /*\r
+ Make a scope here for the client so that it gets removed\r
+ before the irrlicht device\r
+ */\r
{\r
\r
std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
std::cout<<DTIME<<"Timed out."<<std::endl;\r
return 0;\r
}\r
+\r
+ /*\r
+ Create skybox\r
+ */\r
+ scene::ISceneNode* skybox = smgr->addSkyBoxSceneNode(\r
+ driver->getTexture("../data/skybox2.png"),\r
+ driver->getTexture("../data/skybox3.png"),\r
+ driver->getTexture("../data/skybox1.png"),\r
+ driver->getTexture("../data/skybox1.png"),\r
+ driver->getTexture("../data/skybox1.png"),\r
+ driver->getTexture("../data/skybox1.png"));\r
+ /* driver->getTexture("../data/irrlicht2_up.jpg"),\r
+ driver->getTexture("../data/irrlicht2_dn.jpg"),\r
+ driver->getTexture("../data/irrlicht2_lf.jpg"),\r
+ driver->getTexture("../data/irrlicht2_rt.jpg"),\r
+ driver->getTexture("../data/irrlicht2_ft.jpg"),\r
+ driver->getTexture("../data/irrlicht2_bk.jpg"));*/\r
\r
/*\r
Create the camera node\r
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
\r
- for(s16 y = ystart; y <= yend; y++){\r
- for(s16 z = zstart; z <= zend; z++){\r
+ for(s16 y = ystart; y <= yend; y++)\r
+ for(s16 z = zstart; z <= zend; z++)\r
for(s16 x = xstart; x <= xend; x++)\r
{\r
- try{\r
- if(material_pointable(client.getNode(v3s16(x,y,z)).d) == false)\r
+ MapNode n;\r
+ try\r
+ {\r
+ n = client.getNode(v3s16(x,y,z));\r
+ if(content_pointable(n.d) == false)\r
continue;\r
- }catch(InvalidPositionException &e){\r
+ }\r
+ catch(InvalidPositionException &e)\r
+ {\r
continue;\r
}\r
\r
\r
f32 d = 0.01;\r
\r
- v3s16 directions[6] = {\r
+ v3s16 dirs[6] = {\r
v3s16(0,0,1), // back\r
v3s16(0,1,0), // top\r
v3s16(1,0,0), // right\r
- v3s16(0,0,-1),\r
- v3s16(0,-1,0),\r
- v3s16(-1,0,0),\r
+ v3s16(0,0,-1), // front\r
+ v3s16(0,-1,0), // bottom\r
+ v3s16(-1,0,0), // left\r
};\r
+ \r
+ /*\r
+ Meta-objects\r
+ */\r
+ if(n.d == CONTENT_LIGHT)\r
+ {\r
+ v3s16 dir = unpackDir(n.dir);\r
+ v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
+ dir_f *= BS/2 - BS/6 - BS/20;\r
+ v3f cpf = npf + dir_f;\r
+ f32 distance = (cpf - camera_position).getLength();\r
\r
- for(u16 i=0; i<6; i++){\r
- //{u16 i=3;\r
- v3f dir_f = v3f(directions[i].X,\r
- directions[i].Y, directions[i].Z);\r
- v3f centerpoint = npf + dir_f * BS/2;\r
- f32 distance =\r
- (centerpoint - camera_position).getLength();\r
+ core::aabbox3d<f32> box;\r
\r
- if(distance < mindistance){\r
- //std::cout<<DTIME<<"for centerpoint=("<<centerpoint.X<<","<<centerpoint.Y<<","<<centerpoint.Z<<"): distance < mindistance"<<std::endl;\r
- //std::cout<<DTIME<<"npf=("<<npf.X<<","<<npf.Y<<","<<npf.Z<<")"<<std::endl;\r
- core::CMatrix4<f32> m;\r
- m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
-\r
- // This is the back face\r
- v3f corners[2] = {\r
- v3f(BS/2, BS/2, BS/2),\r
- v3f(-BS/2, -BS/2, BS/2+d)\r
- };\r
- \r
- for(u16 j=0; j<2; j++){\r
- m.rotateVect(corners[j]);\r
- corners[j] += npf;\r
- //std::cout<<DTIME<<"box corners["<<j<<"]: ("<<corners[j].X<<","<<corners[j].Y<<","<<corners[j].Z<<")"<<std::endl;\r
- }\r
-\r
- //core::aabbox3d<f32> facebox(corners[0],corners[1]);\r
- core::aabbox3d<f32> facebox(corners[0]);\r
- facebox.addInternalPoint(corners[1]);\r
+ // bottom\r
+ if(dir == v3s16(0,-1,0))\r
+ {\r
+ box = core::aabbox3d<f32>(\r
+ npf - v3f(BS/6, BS/2, BS/6),\r
+ npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
+ );\r
+ }\r
+ // top\r
+ else if(dir == v3s16(0,1,0))\r
+ {\r
+ box = core::aabbox3d<f32>(\r
+ npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
+ npf + v3f(BS/6, BS/2, BS/6)\r
+ );\r
+ }\r
+ // side\r
+ else\r
+ {\r
+ box = core::aabbox3d<f32>(\r
+ cpf - v3f(BS/6, BS/3, BS/6),\r
+ cpf + v3f(BS/6, BS/3, BS/6)\r
+ );\r
+ }\r
\r
- if(facebox.intersectsWithLine(shootline)){\r
+ if(distance < mindistance)\r
+ {\r
+ if(box.intersectsWithLine(shootline))\r
+ {\r
nodefound = true;\r
nodepos = np;\r
- neighbourpos = np + directions[i];\r
+ neighbourpos = np;\r
mindistance = distance;\r
- nodefacebox = facebox;\r
+ nodefacebox = box;\r
}\r
}\r
}\r
- }}}\r
+ /*\r
+ Regular blocks\r
+ */\r
+ else\r
+ {\r
+ for(u16 i=0; i<6; i++)\r
+ {\r
+ v3f dir_f = v3f(dirs[i].X,\r
+ dirs[i].Y, dirs[i].Z);\r
+ v3f centerpoint = npf + dir_f * BS/2;\r
+ f32 distance =\r
+ (centerpoint - camera_position).getLength();\r
+ \r
+ if(distance < mindistance)\r
+ {\r
+ core::CMatrix4<f32> m;\r
+ m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
+\r
+ // This is the back face\r
+ v3f corners[2] = {\r
+ v3f(BS/2, BS/2, BS/2),\r
+ v3f(-BS/2, -BS/2, BS/2+d)\r
+ };\r
+ \r
+ for(u16 j=0; j<2; j++)\r
+ {\r
+ m.rotateVect(corners[j]);\r
+ corners[j] += npf;\r
+ }\r
+\r
+ core::aabbox3d<f32> facebox(corners[0]);\r
+ facebox.addInternalPoint(corners[1]);\r
+\r
+ if(facebox.intersectsWithLine(shootline))\r
+ {\r
+ nodefound = true;\r
+ nodepos = np;\r
+ neighbourpos = np + dirs[i];\r
+ mindistance = distance;\r
+ nodefacebox = facebox;\r
+ }\r
+ } // if distance < mindistance\r
+ } // for dirs\r
+ } // regular block\r
+ } // for coords\r
\r
if(nodefound)\r
{\r
// 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;
light_sources.remove(n2pos);
}*/
}
+
+ /*// DEBUG
+ if(light_sources.find(n2pos) != NULL)
+ light_sources.remove(n2pos);*/
}
else{
light_sources.insert(n2pos, true);
// Collect borders for unlighting
if(x==0 || x == MAP_BLOCKSIZE-1
- || y==0 || y == MAP_BLOCKSIZE-1
- || z==0 || z == MAP_BLOCKSIZE-1)
+ || y==0 || y == MAP_BLOCKSIZE-1
+ || z==0 || z == MAP_BLOCKSIZE-1)
{
v3s16 p_map = p + v3s16(
MAP_BLOCKSIZE*pos.X,
// 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);
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
if(
c > highest_ranking ||
// Prefer something else than air
- (c >= highest_ranking && m != MATERIAL_AIR)
+ (c >= highest_ranking && m != CONTENT_AIR)
)
{
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();
//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;
*/
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;
// 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);
}
*/
// 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;
}
);
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);
}
);
// 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));
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);
}
&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);
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);
&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);
<<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);
}
/*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;*/
u8 alpha = 255;
- if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
+ if(material == CONTENT_WATER || material == CONTENT_OCEAN)
{
alpha = 128;
}
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();
/*
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;
}
}
*/
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;
}
scene::SMesh *mesh_new = NULL;
+ mesh_new = new scene::SMesh();
+
if(fastfaces_new->getSize() > 0)
{
MeshCollector collector;
indices, 6);
}
- mesh_new = new scene::SMesh();
-
collector.fillMesh(mesh_new);
// Use VBO for mesh (this just would set this for ever buffer)
/*
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;
}
/*
getPosRelative(), data_size);
}
+/*void getPseudoObjects(v3f origin, f32 max_d,
+ core::array<DistanceSortedObject> &dest)
+{
+}*/
+
/*
Serialization
*/
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:
m_objects.getObjects(origin, max_d, dest);
}
+ /*void getPseudoObjects(v3f origin, f32 max_d,
+ core::array<DistanceSortedObject> &dest);*/
+
s32 getObjectCount()
{
return m_objects.getCount();
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;
}
#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;
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:
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);
}
/*
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;
/*
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
*/
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)
{
*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;
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()
/*
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;
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;
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)
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;
}
}
v3s16 &p = q->pos;
//derr_server<<"EmergeThread::Thread(): running"<<std::endl;
+
+ //TimeTaker timer("block emerge", g_device);
/*
Try to emerge it from somewhere.
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()
{
- 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);
MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block);
}
- }
+ } // envlock
/*
Set the modified blocks unsent for all the clients
// 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;
}
// 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));
*/
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)
// 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);
// 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.
*/
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
// 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));
writeS16(&reply[4], p.Y);
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);
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);
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);
+}
+
+
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;
// 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;
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);
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);
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);*/
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);
}
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);
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()
*/
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
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);
}
#include <fstream>
#include <string>
#include <sstream>
+#include <jmutex.h>
+#include <jmutexautolock.h>
extern const v3s16 g_26dirs[26];
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
m_data(NULL),
m_flags(NULL)
{
+ m_disable_water_climb = false;
}
VoxelManipulator::~VoxelManipulator()
}
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 = ' ';
}
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++)
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++)
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;
}
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;
}
// Ignore non-liquid nodes
- if(material_liquid(n.d) == false)
+ if(content_liquid(n.d) == false)
continue;
int pr2 = pr;
if(pr2 < 255)
pr2++;
}
+
+ /*if(m_disable_water_climb)
+ {
+ if(pr2 > 3)
+ pr2 = 3;
+ }*/
// Ignore if correct pressure is already set and is not on
// request_area.
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)
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)];
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)
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
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;
/*
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
// 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);
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
//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:
};