aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2011-01-17 21:15:31 +0200
committerPerttu Ahola <celeron55@gmail.com>2011-01-17 21:15:31 +0200
commitd44abdab17f6ad7a05ddc08d418af35e9cabddef (patch)
treee20567656ca78a53bec39228f8feba54aa54475d /src
parent0fa0e0752a28eeb43195f2288c018d5c0b24520b (diff)
downloadminetest-d44abdab17f6ad7a05ddc08d418af35e9cabddef.tar.gz
minetest-d44abdab17f6ad7a05ddc08d418af35e9cabddef.tar.bz2
minetest-d44abdab17f6ad7a05ddc08d418af35e9cabddef.zip
minecraft-style water done (but no texture animation or sound)
Diffstat (limited to 'src')
-rw-r--r--src/constants.h6
-rw-r--r--src/defaultsettings.cpp4
-rw-r--r--src/light.h3
-rw-r--r--src/main.cpp11
-rw-r--r--src/map.cpp389
-rw-r--r--src/map.h2
-rw-r--r--src/mapblock.cpp325
-rw-r--r--src/mapblock.h3
-rw-r--r--src/mapnode.cpp3
-rw-r--r--src/mapnode.h24
-rw-r--r--src/server.cpp52
-rw-r--r--src/server.h3
-rw-r--r--src/utility.h8
13 files changed, 769 insertions, 64 deletions
diff --git a/src/constants.h b/src/constants.h
index fc8007602..3cb285065 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -97,7 +97,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#define MAX_OBJECTDATA_SIZE 450
-#define WATER_LEVEL (0)
+/*
+ This is good to be a bit different than 0 so that water level
+ is not between to MapBlocks
+*/
+#define WATER_LEVEL 3
// Length of cracking animation in count of images
#define CRACK_ANIMATION_LENGTH 5
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index b7b7013d1..c11159f1d 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -62,8 +62,8 @@ void set_default_settings()
g_settings.setDefault("active_object_range", "2");
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
- g_settings.setDefault("water_moves", "true");
- g_settings.setDefault("disable_water_climb", "true");
+ //g_settings.setDefault("water_moves", "true");
+ //g_settings.setDefault("disable_water_climb", "true");
//g_settings.setDefault("endless_water", "true");
g_settings.setDefault("max_block_send_distance", "6");
g_settings.setDefault("max_block_generate_distance", "6");
diff --git a/src/light.h b/src/light.h
index 269948e86..888b6da50 100644
--- a/src/light.h
+++ b/src/light.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define LIGHT_HEADER
#include "common_irrlicht.h"
+#include "debug.h"
/*
Day/night cache:
@@ -78,7 +79,7 @@ inline u8 decode_light(u8 light)
return light_decode_table[LIGHT_MAX];
if(light > LIGHT_MAX)
- throw;
+ light = LIGHT_MAX;
return light_decode_table[light];
}
diff --git a/src/main.cpp b/src/main.cpp
index 61f791f86..3101583cf 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -116,12 +116,16 @@ TODO: Startup and configuration menu
Graphics:
+TODO:
+
TODO: Optimize day/night mesh updating somehow
- create copies of all textures for all lighting values and only
change texture for material?
- Umm... the collecting of the faces is the slow part
-> what about just changing the color values of the existing
meshbuffers? It should go quite fast.
+ - This is not easy; There'd need to be a buffer somewhere
+ that would contain the night and day lighting values.
TODO: Draw big amounts of torches better (that is, throw them in the
same meshbuffer (can the meshcollector class be used?))
@@ -129,9 +133,13 @@ TODO: Draw big amounts of torches better (that is, throw them in the
TODO: Combine MapBlock's face caches to so big pieces that VBO
gets used
- That is >500 vertices
+ - This is not easy; all the MapBlocks close to the player would
+ still need to be drawn separately and combining the blocks
+ would have to happen in a background thread
TODO: Make fetching sector's blocks more efficient when rendering
sectors that have very large amounts of blocks (on client)
+ - Is this necessary at all?
Configuration:
@@ -210,6 +218,9 @@ TODO: Map generator version 2
- There could be a certain height (to which mountains only reach)
where some minerals are found
+FIXME: The new pre-sunlight-propagation code messes up with initial
+ water lighting
+
Doing now:
======================================================================
diff --git a/src/map.cpp b/src/map.cpp
index 170868f10..612649100 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -926,6 +926,37 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
MapBlock *block = i.getNode()->getValue();
block->updateDayNightDiff();
}
+
+ /*
+ Add neighboring liquid nodes and the node itself if it is
+ liquid (=water node was added) to transform queue.
+ */
+ v3s16 dirs[7] = {
+ v3s16(0,0,0), // self
+ v3s16(0,0,1), // back
+ v3s16(0,1,0), // top
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(0,-1,0), // bottom
+ v3s16(-1,0,0), // left
+ };
+ for(u16 i=0; i<7; i++)
+ {
+ try
+ {
+
+ v3s16 p2 = p + dirs[i];
+
+ MapNode n2 = getNode(p2);
+ if(content_liquid(n2.d))
+ {
+ m_transforming_liquid.push_back(p2);
+ }
+
+ }catch(InvalidPositionException &e)
+ {
+ }
+ }
}
/*
@@ -1063,6 +1094,35 @@ void Map::removeNodeAndUpdate(v3s16 p,
MapBlock *block = i.getNode()->getValue();
block->updateDayNightDiff();
}
+
+ /*
+ Add neighboring liquid nodes to transform queue.
+ */
+ v3s16 dirs[6] = {
+ v3s16(0,0,1), // back
+ v3s16(0,1,0), // top
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(0,-1,0), // bottom
+ v3s16(-1,0,0), // left
+ };
+ for(u16 i=0; i<6; i++)
+ {
+ try
+ {
+
+ v3s16 p2 = p + dirs[i];
+
+ MapNode n2 = getNode(p2);
+ if(content_liquid(n2.d))
+ {
+ m_transforming_liquid.push_back(p2);
+ }
+
+ }catch(InvalidPositionException &e)
+ {
+ }
+ }
}
#ifndef SERVER
@@ -1303,6 +1363,276 @@ void Map::PrintInfo(std::ostream &out)
out<<"Map: ";
}
+#define WATER_DROP_BOOST 4
+
+void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
+{
+ DSTACK(__FUNCTION_NAME);
+ TimeTaker timer("transformLiquids()");
+
+ u32 loopcount = 0;
+ u32 initial_size = m_transforming_liquid.size();
+ while(m_transforming_liquid.size() != 0)
+ {
+ v3s16 p0 = m_transforming_liquid.pop_front();
+
+ MapNode n0 = getNode(p0);
+
+ // Don't deal with non-liquids
+ if(content_liquid(n0.d) == false)
+ continue;
+
+ bool is_source = !content_flowing_liquid(n0.d);
+
+ u8 liquid_level = 8;
+ if(is_source == false)
+ liquid_level = n0.param2 & 0x0f;
+
+ // Turn possible source into non-source
+ u8 nonsource_c = make_liquid_flowing(n0.d);
+
+ /*
+ If not source, check that some node flows into this one
+ and what is the level of liquid in this one
+ */
+ if(is_source == false)
+ {
+ s8 new_liquid_level_max = -1;
+
+ v3s16 dirs_from[5] = {
+ v3s16(0,1,0), // top
+ v3s16(0,0,1), // back
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(-1,0,0), // left
+ };
+ for(u16 i=0; i<5; i++)
+ {
+ try
+ {
+
+ bool from_top = (i==0);
+
+ v3s16 p2 = p0 + dirs_from[i];
+ MapNode n2 = getNode(p2);
+
+ if(content_liquid(n2.d))
+ {
+ u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+ // Check that the liquids are the same type
+ if(n2_nonsource_c != nonsource_c)
+ {
+ dstream<<"WARNING: Not handling: different liquids"
+ " collide"<<std::endl;
+ continue;
+ }
+ bool n2_is_source = !content_flowing_liquid(n2.d);
+ s8 n2_liquid_level = 8;
+ if(n2_is_source == false)
+ n2_liquid_level = n2.param2 & 0x07;
+
+ s8 new_liquid_level = -1;
+ if(from_top)
+ {
+ //new_liquid_level = 7;
+ if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
+ new_liquid_level = 7;
+ else
+ new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
+ }
+ else if(n2_liquid_level > 0)
+ {
+ new_liquid_level = n2_liquid_level - 1;
+ }
+
+ if(new_liquid_level > new_liquid_level_max)
+ new_liquid_level_max = new_liquid_level;
+ }
+
+ }catch(InvalidPositionException &e)
+ {
+ }
+ } //for
+
+ /*
+ If liquid level should be something else, update it and
+ add all the neighboring water nodes to the transform queue.
+ */
+ if(new_liquid_level_max != liquid_level)
+ {
+ if(new_liquid_level_max == -1)
+ {
+ // Remove water alltoghether
+ n0.d = CONTENT_AIR;
+ n0.param2 = 0;
+ setNode(p0, n0);
+ }
+ else
+ {
+ n0.param2 = new_liquid_level_max;
+ setNode(p0, n0);
+ }
+
+ // Block has been modified
+ {
+ v3s16 blockpos = getNodeBlockPos(p0);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block != NULL)
+ modified_blocks.insert(blockpos, block);
+ }
+
+ /*
+ Add neighboring non-source liquid nodes to transform queue.
+ */
+ v3s16 dirs[6] = {
+ v3s16(0,0,1), // back
+ v3s16(0,1,0), // top
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(0,-1,0), // bottom
+ v3s16(-1,0,0), // left
+ };
+ for(u16 i=0; i<6; i++)
+ {
+ try
+ {
+
+ v3s16 p2 = p0 + dirs[i];
+
+ MapNode n2 = getNode(p2);
+ if(content_flowing_liquid(n2.d))
+ {
+ m_transforming_liquid.push_back(p2);
+ }
+
+ }catch(InvalidPositionException &e)
+ {
+ }
+ }
+ }
+ }
+
+ // Get a new one from queue if the node has turned into non-water
+ if(content_liquid(n0.d) == false)
+ continue;
+
+ /*
+ Flow water from this node
+ */
+ v3s16 dirs_to[5] = {
+ 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(u16 i=0; i<5; i++)
+ {
+ try
+ {
+
+ bool to_bottom = (i == 0);
+
+ // If liquid is at lowest possible height, it's not going
+ // anywhere except down
+ if(liquid_level == 0 && to_bottom == false)
+ continue;
+
+ u8 liquid_next_level = 0;
+ // If going to bottom
+ if(to_bottom)
+ {
+ //liquid_next_level = 7;
+ if(liquid_level >= 7 - WATER_DROP_BOOST)
+ liquid_next_level = 7;
+ else
+ liquid_next_level = liquid_level + WATER_DROP_BOOST;
+ }
+ else
+ liquid_next_level = liquid_level - 1;
+
+ bool n2_changed = false;
+ bool flowed = false;
+
+ v3s16 p2 = p0 + dirs_to[i];
+
+ MapNode n2 = getNode(p2);
+
+ if(content_liquid(n2.d))
+ {
+ u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+ // Check that the liquids are the same type
+ if(n2_nonsource_c != nonsource_c)
+ {
+ dstream<<"WARNING: Not handling: different liquids"
+ " collide"<<std::endl;
+ continue;
+ }
+ bool n2_is_source = !content_flowing_liquid(n2.d);
+ u8 n2_liquid_level = 8;
+ if(n2_is_source == false)
+ n2_liquid_level = n2.param2 & 0x07;
+
+ if(to_bottom)
+ {
+ flowed = true;
+ }
+
+ if(n2_is_source)
+ {
+ // Just flow into the source, nothing changes.
+ // n2_changed is not set because destination didn't change
+ flowed = true;
+ }
+ else
+ {
+ if(liquid_next_level > liquid_level)
+ {
+ n2.param2 = liquid_next_level;
+ setNode(p2, n2);
+
+ n2_changed = true;
+ flowed = true;
+ }
+ }
+ }
+ else if(n2.d == CONTENT_AIR)
+ {
+ n2.d = nonsource_c;
+ n2.param2 = liquid_next_level;
+ setNode(p2, n2);
+
+ n2_changed = true;
+ flowed = true;
+ }
+
+ if(n2_changed)
+ {
+ m_transforming_liquid.push_back(p2);
+
+ v3s16 blockpos = getNodeBlockPos(p2);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block != NULL)
+ modified_blocks.insert(blockpos, block);
+ }
+
+ // If n2_changed to bottom, don't flow anywhere else
+ if(to_bottom && flowed)
+ break;
+
+ }catch(InvalidPositionException &e)
+ {
+ }
+ }
+
+ loopcount++;
+ //if(loopcount >= 100000)
+ if(loopcount >= initial_size * 1)
+ break;
+ }
+ dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
+}
+
/*
ServerMap
*/
@@ -1327,15 +1657,20 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
/*
NOTE: BEWARE: Too big amount of these will make map generation
slow. Especially those that are read by every block emerge.
+
+ Fetch times:
+ 1000 points: 2-3ms
+ 5000 points: 15ms
+ 15000 points: 40ms
*/
- for(u32 i=0; i<15000; i++)
+ for(u32 i=0; i<5000; i++)
{
/*u32 lim = MAP_GENERATION_LIMIT;
if(i < 400)
lim = 2000;*/
- u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 15000;
+ u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000;
v3s16 p(
-lim + myrand()%(lim*2),
@@ -1679,17 +2014,19 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
Get local attributes
*/
- //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
-
- // Get plant amount from attributes
- PointAttributeList *palist = m_padb.getList("plants_amount");
- assert(palist);
- /*float local_plants_amount =
- palist->getNearAttr(nodepos2d).getFloat();*/
- float local_plants_amount =
- palist->getInterpolatedFloat(nodepos2d);
-
- //dstream<<"emergeSector(): done."<<std::endl;
+ float local_plants_amount = 0.0;
+ {
+ //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
+ //TimeTaker attrtimer("emergeSector() attribute fetch");
+
+ // Get plant amount from attributes
+ PointAttributeList *palist = m_padb.getList("plants_amount");
+ assert(palist);
+ /*local_plants_amount =
+ palist->getNearAttr(nodepos2d).getFloat();*/
+ local_plants_amount =
+ palist->getInterpolatedFloat(nodepos2d);
+ }
/*
Generate sector heightmap
@@ -1988,6 +2325,12 @@ MapBlock * ServerMap::emergeBlock(
n.d = water_material;
n.setLight(LIGHTBANK_DAY,
diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
+ /*
+ Add to transforming liquid queue (in case it'd
+ start flowing)
+ */
+ v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
+ m_transforming_liquid.push_back(real_pos);
}
// else air
else
@@ -2692,7 +3035,8 @@ continue_generating:
core::map<v3s16, bool> light_sources;
bool black_air_left = false;
bool bottom_invalid =
- block->propagateSunlight(light_sources, true, &black_air_left);
+ block->propagateSunlight(light_sources, true,
+ &black_air_left, true);
// If sunlight didn't reach everywhere and part of block is
// above ground, lighting has to be properly updated
@@ -2700,6 +3044,11 @@ continue_generating:
{
lighting_invalidated_blocks[block->getPos()] = block;
}
+
+ if(bottom_invalid)
+ {
+ lighting_invalidated_blocks[block->getPos()] = block;
+ }
}
/*
@@ -2739,7 +3088,7 @@ continue_generating:
if(haxmode)
{
// Don't calculate lighting at all
- lighting_invalidated_blocks.clear();
+ //lighting_invalidated_blocks.clear();
}
return block;
@@ -3523,11 +3872,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
// Total distance
f32 d = blockpos_relative.getLength();
-
+
+#if 1
/*
- Draw the faces of the block
+ Update expired mesh
*/
-#if 1
+
bool mesh_expired = false;
{
@@ -3585,6 +3935,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
continue;
}*/
#endif
+ /*
+ Draw the faces of the block
+ */
{
JMutexAutoLock lock(block->mesh_mutex);
diff --git a/src/map.h b/src/map.h
index 5cee3b7c0..3b6b169e5 100644
--- a/src/map.h
+++ b/src/map.h
@@ -236,6 +236,8 @@ public:
// For debug printing
virtual void PrintInfo(std::ostream &out);
+
+ void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
/*
Variables
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index cf9114b20..8de81b774 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -146,6 +146,25 @@ u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
v3s16 face_dir)
{
try{
+ // DEBUG
+ /*{
+ if(n.d == CONTENT_WATER)
+ {
+ u8 l = n.param2*2;
+ if(l > LIGHT_MAX)
+ l = LIGHT_MAX;
+ return l;
+ }
+ if(n2.d == CONTENT_WATER)
+ {
+ u8 l = n2.param2*2;
+ if(l > LIGHT_MAX)
+ l = LIGHT_MAX;
+ return l;
+ }
+ }*/
+
+
u8 light;
u8 l1 = n.getLightBlend(daynight_ratio);
u8 l2 = n2.getLightBlend(daynight_ratio);
@@ -645,10 +664,10 @@ void MapBlock::updateMesh(u32 daynight_ratio)
mesh_new = new scene::SMesh();
+ MeshCollector collector;
+
if(fastfaces_new.size() > 0)
{
- MeshCollector collector;
-
for(u32 i=0; i<fastfaces_new.size(); i++)
{
FastFace &f = fastfaces_new[i];
@@ -685,16 +704,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
assert(0);
}
}
-
- collector.fillMesh(mesh_new);
-
- // Use VBO for mesh (this just would set this for ever buffer)
- // This will lead to infinite memory usage because or irrlicht.
- //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
-
- /*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
- <<"and uses "<<mesh_new->getMeshBufferCount()
- <<" materials (meshbuffers)"<<std::endl;*/
}
/*
@@ -714,8 +723,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
if(n.d == CONTENT_TORCH)
{
- //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- scene::SMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
@@ -746,36 +753,266 @@ void MapBlock::updateMesh(u32 daynight_ratio)
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::SMaterial material;
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
if(dir == v3s16(0,-1,0))
- buf->getMaterial().setTexture(0,
+ material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
else if(dir == v3s16(0,1,0))
- buf->getMaterial().setTexture(0,
+ material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str()));
// For backwards compatibility
else if(dir == v3s16(0,0,0))
- buf->getMaterial().setTexture(0,
+ material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
else
- buf->getMaterial().setTexture(0,
+ material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str()));
- // Add to mesh
- mesh_new->addMeshBuffer(buf);
- buf->drop();
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ collector.append(material, vertices, 4, indices, 6);
+ }
+ else if(n.d == CONTENT_WATER)
+ {
+ bool top_is_water = false;
+ try{
+ MapNode n = getNodeParent(v3s16(x,y+1,z));
+ if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
+ top_is_water = true;
+ }catch(InvalidPositionException &e){}
+
+ video::SColor c(128,255,255,255);
+
+ // Neighbor water levels (key = relative position)
+ // Includes current node
+ core::map<v3s16, f32> neighbor_levels;
+ core::map<v3s16, u8> neighbor_contents;
+ v3s16 neighbor_dirs[9] = {
+ v3s16(0,0,0),
+ v3s16(0,0,1),
+ v3s16(0,0,-1),
+ v3s16(1,0,0),
+ v3s16(-1,0,0),
+ v3s16(1,0,1),
+ v3s16(-1,0,-1),
+ v3s16(1,0,-1),
+ v3s16(-1,0,1),
+ };
+ for(u32 i=0; i<9; i++)
+ {
+ u8 content = CONTENT_AIR;
+ float level = -0.5 * BS;
+ try{
+ v3s16 p2 = p + neighbor_dirs[i];
+ MapNode n2 = getNodeParent(p2);
+
+ content = n2.d;
+
+ if(n2.d == CONTENT_WATERSOURCE)
+ level = 0.5 * BS;
+ else if(n2.d == CONTENT_WATER)
+ level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0) * BS;
+ }
+ catch(InvalidPositionException &e){}
+
+ neighbor_levels.insert(neighbor_dirs[i], level);
+ neighbor_contents.insert(neighbor_dirs[i], content);
+ }
+
+ //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
+ //float water_level = neighbor_levels[v3s16(0,0,0)];
+
+ // Corner heights (average between four waters)
+ f32 corner_levels[4];
+
+ v3s16 halfdirs[4] = {
+ v3s16(0,0,0),
+ v3s16(1,0,0),
+ v3s16(1,0,1),
+ v3s16(0,0,1),
+ };
+ for(u32 i=0; i<4; i++)
+ {
+ v3s16 cornerdir = halfdirs[i];
+ float cornerlevel = 0;
+ u32 valid_count = 0;
+ for(u32 j=0; j<4; j++)
+ {
+ v3s16 neighbordir = cornerdir - halfdirs[j];
+ u8 content = neighbor_contents[neighbordir];
+ // Special case for source nodes
+ if(content == CONTENT_WATERSOURCE)
+ {
+ cornerlevel = 0.5*BS;
+ valid_count = 1;
+ break;
+ }
+ else if(content == CONTENT_WATER)
+ {
+ cornerlevel += neighbor_levels[neighbordir];
+ valid_count++;
+ }
+ else if(content == CONTENT_AIR)
+ {
+ cornerlevel += -0.5*BS;
+ valid_count++;
+ }
+ }
+ if(valid_count > 0)
+ cornerlevel /= valid_count;
+ corner_levels[i] = cornerlevel;
+ }
+
+ /*
+ Generate sides
+ */
+
+ v3s16 side_dirs[4] = {
+ v3s16(1,0,0),
+ v3s16(-1,0,0),
+ v3s16(0,0,1),
+ v3s16(0,0,-1),
+ };
+ s16 side_corners[4][2] = {
+ {1, 2},
+ {3, 0},
+ {2, 3},
+ {0, 1},
+ };
+ for(u32 i=0; i<4; i++)
+ {
+ v3s16 dir = side_dirs[i];
+
+ //float neighbor_level = neighbor_levels[dir];
+ /*if(neighbor_level > -0.5*BS + 0.001)
+ continue;*/
+ /*if(neighbor_level > water_level - 0.1*BS)
+ continue;*/
+
+ u8 neighbor_content = neighbor_contents[dir];
+
+ if(neighbor_content != CONTENT_AIR
+ && neighbor_content != CONTENT_WATER)
+ continue;
+
+ bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
+
+ if(neighbor_is_water == true && top_is_water == false)
+ continue;
+
+ video::S3DVertex vertices[4] =
+ {
+ /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ };
+
+ if(top_is_water)
+ {
+ vertices[2].Pos.Y = 0.5*BS;
+ vertices[3].Pos.Y = 0.5*BS;
+ }
+ else
+ {
+ vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
+ vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
+ }
+
+ if(neighbor_is_water)
+ {
+ vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
+ vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
+ }
+ else
+ {
+ vertices[0].Pos.Y = -0.5*BS;
+ vertices[1].Pos.Y = -0.5*BS;
+ }
+
+ for(s32 j=0; j<4; j++)
+ {
+ if(dir == v3s16(0,0,1))
+ vertices[j].Pos.rotateXZBy(0);
+ if(dir == v3s16(0,0,-1))
+ vertices[j].Pos.rotateXZBy(180);
+ if(dir == v3s16(-1,0,0))
+ vertices[j].Pos.rotateXZBy(90);
+ if(dir == v3s16(1,0,-0))
+ vertices[j].Pos.rotateXZBy(-90);
+
+ vertices[j].Pos += intToFloat(p + getPosRelative());
+ }
+
+ // Set material
+ video::SMaterial material;
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ material.setTexture(0,
+ g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
+
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ collector.append(material, vertices, 4, indices, 6);
+ }
+
+ /*
+ Generate top side, if appropriate
+ */
+
+ if(top_is_water == false)
+ {
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ };
+
+ for(s32 i=0; i<4; i++)
+ {
+ //vertices[i].Pos.Y += water_level;
+ //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
+ vertices[i].Pos.Y += corner_levels[i];
+ vertices[i].Pos += intToFloat(p + getPosRelative());
+ }
+
+ // Set material
+ video::SMaterial material;
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ material.setTexture(0,
+ g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
+
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ collector.append(material, vertices, 4, indices, 6);
+ }
}
}
+
+ /*
+ Add stuff from collector to mesh
+ */
+ collector.fillMesh(mesh_new);
+
/*
Do some stuff to the mesh
*/
@@ -792,6 +1029,14 @@ void MapBlock::updateMesh(u32 daynight_ratio)
mesh_new = NULL;
}
+ // Use VBO for mesh (this just would set this for ever buffer)
+ // This will lead to infinite memory usage because or irrlicht.
+ //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
+
+ /*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
+ <<"and uses "<<mesh_new->getMeshBufferCount()
+ <<" materials (meshbuffers)"<<std::endl;*/
+
/*
Replace the mesh
*/
@@ -872,7 +1117,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
air is left in block.
*/
bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
- bool remove_light, bool *black_air_left)
+ bool remove_light, bool *black_air_left,
+ bool grow_grass)
{
// Whether the sunlight at the top of the bottom block is valid
bool block_below_is_valid = true;
@@ -962,10 +1208,23 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
}
else if(n.light_propagates() == false)
{
- // Turn mud into grass
- if(n.d == CONTENT_MUD && current_light == LIGHT_SUN)
+ if(grow_grass)
{
- n.d = CONTENT_GRASS;
+ bool upper_is_air = false;
+ try
+ {
+ if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
+ upper_is_air = true;
+ }
+ catch(InvalidPositionException &e)
+ {
+ }
+ // Turn mud into grass
+ if(upper_is_air && n.d == CONTENT_MUD
+ && current_light == LIGHT_SUN)
+ {
+ n.d = CONTENT_GRASS;
+ }
}
// A solid object is on the way.
diff --git a/src/mapblock.h b/src/mapblock.h
index e4f93a031..dd5277668 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -315,7 +315,8 @@ public:
// See comments in mapblock.cpp
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
- bool remove_light=false, bool *black_air_left=NULL);
+ bool remove_light=false, bool *black_air_left=NULL,
+ bool grow_grass=false);
// Copies data to VoxelManipulator to getPosRelative()
void copyTo(VoxelManipulator &dst);
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index de6953b78..59e40935c 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -35,7 +35,8 @@ u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] =
{
{TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE},
{TILE_GRASS,TILE_MUD,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS},
- {TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
+ //{TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
+ {TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE},
{TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE},
{TILE_TREE_TOP,TILE_TREE_TOP,TILE_TREE,TILE_TREE,TILE_TREE,TILE_TREE},
{TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES},
diff --git a/src/mapnode.h b/src/mapnode.h
index a759f807e..e3b921a66 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -108,7 +108,7 @@ inline bool sunlight_propagates_content(u8 m)
inline u8 content_solidness(u8 m)
{
// As of now, every pseudo node like torches are added to this
- if(m == CONTENT_AIR || m == CONTENT_TORCH)
+ if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
return 0;
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
return 1;
@@ -121,12 +121,30 @@ inline bool content_walkable(u8 m)
return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
}
-// A liquid resists fast movement
inline bool content_liquid(u8 m)
{
return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
}
+inline bool content_flowing_liquid(u8 m)
+{
+ return (m == CONTENT_WATER);
+}
+
+inline bool content_liquid_source(u8 m)
+{
+ return (m == CONTENT_WATERSOURCE);
+}
+
+// CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
+// CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
+inline u8 make_liquid_flowing(u8 m)
+{
+ if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
+ return CONTENT_WATER;
+ assert(0);
+}
+
// Pointable contents can be pointed to in the map
inline bool content_pointable(u8 m)
{
@@ -349,6 +367,8 @@ struct MapNode
union
{
+ u8 param2;
+
/*
Pressure for liquids
*/
diff --git a/src/server.cpp b/src/server.cpp
index 312e2b6d9..17004a803 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -971,7 +971,8 @@ Server::Server(
m_time_of_day_send_timer(0),
m_uptime(0)
{
- m_flowwater_timer = 0.0;
+ //m_flowwater_timer = 0.0;
+ m_liquid_transform_timer = 0.0;
m_print_info_timer = 0.0;
m_objectdata_timer = 0.0;
m_emergethread_trigger_timer = 0.0;
@@ -1140,9 +1141,54 @@ void Server::AsyncRunStep()
/*
Do background stuff
*/
-
+
+ /*
+ Transform liquids
+ */
+ m_liquid_transform_timer += dtime;
+ if(m_liquid_transform_timer >= 1.00)
{
- //m_env.getMap().
+ m_liquid_transform_timer -= 1.00;
+
+ JMutexAutoLock lock(m_env_mutex);
+
+ core::map<v3s16, MapBlock*> modified_blocks;
+ m_env.getMap().transformLiquids(modified_blocks);
+#if 0
+ /*
+ Update lighting
+ */
+ core::map<v3s16, MapBlock*> lighting_modified_blocks;
+ ServerMap &map = ((ServerMap&)m_env.getMap());
+ map.updateLighting(modified_blocks, lighting_modified_blocks);
+
+ // Add blocks modified by lighting to modified_blocks
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = lighting_modified_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ MapBlock *block = i.getNode()->getValue();
+ modified_blocks.insert(block->getPos(), block);
+ }
+#endif
+ /*
+ 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);
+ }
+ }
}
#if 0
diff --git a/src/server.h b/src/server.h
index a1c4a1cd7..4bdaa8455 100644
--- a/src/server.h
+++ b/src/server.h
@@ -457,7 +457,8 @@ private:
void handlePeerChange(PeerChange &c);
void handlePeerChanges();
- float m_flowwater_timer;
+ //float m_flowwater_timer;
+ float m_liquid_transform_timer;
float m_print_info_timer;
float m_objectdata_timer;
float m_emergethread_trigger_timer;
diff --git a/src/utility.h b/src/utility.h
index a38d15f30..897390dba 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1608,7 +1608,7 @@ public:
return true;
}
- void pop_front()
+ Value pop_front()
{
typename core::list<Value>::Iterator i = m_list.begin();
Value value = *i;
@@ -1617,6 +1617,12 @@ public:
return value;
}
+ u32 size()
+ {
+ assert(m_list.size() == m_map.size());
+ return m_list.size();
+ }
+
private:
core::map<Value, u8> m_map;
core::list<Value> m_list;