forked from Mirrorlandia_minetest/minetest
starting to separate "material" to "content" and "tile"
This commit is contained in:
parent
db49f37692
commit
47a593b519
@ -53,3 +53,6 @@
|
||||
#max_simultaneous_block_sends_per_client = 1
|
||||
#max_simultaneous_block_sends_server_total = 4
|
||||
|
||||
#max_block_send_distance = 8
|
||||
#max_block_generate_distance = 5
|
||||
|
||||
|
215
src/main.cpp
215
src/main.cpp
@ -179,200 +179,19 @@ SUGG: MovingObject::move and Player::move are basically the same.
|
||||
TODO: Transfer sign texts as metadata of block and not as data of
|
||||
object
|
||||
|
||||
SUGG: Implement a "Fast check queue" (a queue with a map for checking
|
||||
if something is already in it)
|
||||
- TODO: Use it in active block queue in water flowing
|
||||
|
||||
TODO: Proper looking torches.
|
||||
- Signs could be done in the same way?
|
||||
|
||||
Doing now:
|
||||
======================================================================
|
||||
|
||||
Water dynamics pseudo-code (block = MapNode):
|
||||
SUGG: Create separate flag table in VoxelManipulator to allow fast
|
||||
clearing of "modified" flags
|
||||
|
||||
neighborCausedPressure(pos):
|
||||
pressure = 0
|
||||
dirs = {down, left, right, back, front, up}
|
||||
for d in dirs:
|
||||
pos2 = pos + d
|
||||
p = block_at(pos2).pressure
|
||||
if d.Y == 1 and p > min:
|
||||
p -= 1
|
||||
if d.Y == -1 and p < max:
|
||||
p += 1
|
||||
if p > pressure:
|
||||
pressure = p
|
||||
return pressure
|
||||
|
||||
# This should somehow update all changed pressure values
|
||||
# in an unknown body of water
|
||||
updateWaterPressure(pos):
|
||||
TODO
|
||||
|
||||
FIXME: This goes in an indefinite loop when there is an underwater
|
||||
chamber like this:
|
||||
|
||||
#111######
|
||||
#222##22##
|
||||
#33333333x<- block removed from here
|
||||
##########
|
||||
|
||||
#111######
|
||||
#222##22##
|
||||
#3333333x1
|
||||
##########
|
||||
|
||||
#111######
|
||||
#222##22##
|
||||
#333333x11
|
||||
##########
|
||||
|
||||
#111######
|
||||
#222##2x##
|
||||
#333333333
|
||||
##########
|
||||
|
||||
#111######
|
||||
#222##x2##
|
||||
#333333333
|
||||
##########
|
||||
|
||||
Now, consider moving to the last block not allowed.
|
||||
|
||||
Consider it a 3D case with a depth of 2. We're now at this situation.
|
||||
Note the additional blocking ## in the second depth plane.
|
||||
|
||||
z=1 z=2
|
||||
#111###### #111######
|
||||
#222##x2## #222##22##
|
||||
#333333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##x2##
|
||||
#333333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##2x##
|
||||
#333333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
Now there is nowhere to go, without going to an already visited block,
|
||||
but the pressure calculated in here from neighboring blocks is >= 2,
|
||||
so it is not the final ending.
|
||||
|
||||
We will back up to a state where there is somewhere to go to.
|
||||
It is this state:
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##22##
|
||||
#333333x33 #33333##33
|
||||
########## ##########
|
||||
|
||||
Then just go on, avoiding already visited blocks:
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##22##
|
||||
#33333x333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##22##
|
||||
#3333x3333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##22##
|
||||
#333x33333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#222##22## #222##22##
|
||||
#33x333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#111###### #111######
|
||||
#22x##22## #222##22##
|
||||
#333333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
#11x###### #111######
|
||||
#222##22## #222##22##
|
||||
#333333333 #33333##33
|
||||
########## ##########
|
||||
|
||||
"Blob". the air bubble finally got out of the water.
|
||||
Then return recursively to a state where there is air next to water,
|
||||
clear the visit flags and feed the neighbor of the water recursively
|
||||
to the algorithm.
|
||||
|
||||
#11 ###### #111######
|
||||
#222##22## #222##22##
|
||||
#333333333x #33333##33
|
||||
########## ##########
|
||||
|
||||
#11 ###### #111######
|
||||
#222##22## #222##22##
|
||||
#33333333x3 #33333##33
|
||||
########## ##########
|
||||
|
||||
...and so on.
|
||||
|
||||
|
||||
# removed_pos: a position that has been changed from something to air
|
||||
flowWater(removed_pos):
|
||||
dirs = {top, left, right, back, front, bottom}
|
||||
selected_dir = None
|
||||
for d in dirs:
|
||||
b2 = removed_pos + d
|
||||
|
||||
# Ignore positions that don't have water
|
||||
if block_at(b2) != water:
|
||||
continue
|
||||
|
||||
# Ignore positions that have already been checked
|
||||
if block_at(b2).checked:
|
||||
continue
|
||||
|
||||
# If block is at top, select it always.
|
||||
if d.Y == 1:
|
||||
selected_dir = d
|
||||
break
|
||||
|
||||
# If block is at bottom, select it if it has enough pressure.
|
||||
# >= 3 needed for stability (and sanity)
|
||||
if d.Y == -1:
|
||||
if block_at(b2).pressure >= 3:
|
||||
selected_dir = d
|
||||
break
|
||||
continue
|
||||
|
||||
# Else block is at some side. select it if it has enough pressure.
|
||||
if block_at(b2).pressure >= 2:
|
||||
selected_dir = d
|
||||
break
|
||||
|
||||
# If there is nothing to do anymore, return.
|
||||
if selected_dir == None
|
||||
return
|
||||
|
||||
b2 = removed_pos + selected_dir
|
||||
|
||||
# Move block
|
||||
set_block(removed_pos, block_at(b2))
|
||||
set_block(b2, air_block)
|
||||
|
||||
# Update pressure
|
||||
updateWaterPressure(removed_pos)
|
||||
|
||||
# Flow water to the newly created empty position
|
||||
flowWater(b2)
|
||||
|
||||
# Check empty positions around and try flowing water to them
|
||||
for d in dirs:
|
||||
b3 = removed_pos + d
|
||||
# Ignore positions that are not air
|
||||
if block_at(b3) is not air:
|
||||
continue
|
||||
flowWater(b3)
|
||||
|
||||
TODO: A system for showing some nodes in some other way than cubes
|
||||
- Needed for torches
|
||||
- Also for signs, stairs, etc
|
||||
|
||||
======================================================================
|
||||
|
||||
@ -448,7 +267,8 @@ const char *g_material_filenames[MATERIALS_COUNT] =
|
||||
"../data/leaves.png",
|
||||
"../data/grass_footsteps.png",
|
||||
"../data/mese.png",
|
||||
"../data/mud.png"
|
||||
"../data/mud.png",
|
||||
"../data/water.png", // ocean
|
||||
};
|
||||
|
||||
video::SMaterial g_materials[MATERIALS_COUNT];
|
||||
@ -499,6 +319,8 @@ void set_default_settings()
|
||||
g_settings.set("name", "");
|
||||
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");
|
||||
|
||||
// Server stuff
|
||||
g_settings.set("creative_mode", "false");
|
||||
@ -1489,13 +1311,12 @@ int main(int argc, char *argv[])
|
||||
g_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
//g_materials[i].setFlag(video::EMF_ANISOTROPIC_FILTER, false);
|
||||
//g_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
|
||||
if(i == MATERIAL_WATER)
|
||||
{
|
||||
g_materials[i].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
//g_materials[i].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
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_mesh_materials[0].setTexture(0, driver->getTexture("../data/water.png"));
|
||||
g_mesh_materials[1].setTexture(0, driver->getTexture("../data/grass.png"));
|
||||
g_mesh_materials[2].setTexture(0, driver->getTexture("../data/stone.png"));
|
||||
|
81
src/map.cpp
81
src/map.cpp
@ -1819,7 +1819,8 @@ MapBlock * ServerMap::emergeBlock(
|
||||
// If under water level, it's water
|
||||
if(real_y < WATER_LEVEL)
|
||||
{
|
||||
n.d = MATERIAL_WATER;
|
||||
//n.d = MATERIAL_WATER;
|
||||
n.d = MATERIAL_OCEAN;
|
||||
n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
|
||||
}
|
||||
// else air
|
||||
@ -2731,34 +2732,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver,
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
||||
#if 0
|
||||
/*
|
||||
Draw master heightmap mesh
|
||||
*/
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(mesh_mutex);
|
||||
if(mesh != NULL)
|
||||
{
|
||||
u32 c = mesh->getMeshBufferCount();
|
||||
|
||||
for(u32 i=0; i<c; i++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
const video::SMaterial& material = buf->getMaterial();
|
||||
video::IMaterialRenderer* rnd =
|
||||
driver->getMaterialRenderer(material.MaterialType);
|
||||
bool transparent = (rnd && rnd->isTransparent());
|
||||
// Render transparent on transparent pass and likewise.
|
||||
if(transparent == is_transparent_pass)
|
||||
{
|
||||
driver->setMaterial(buf->getMaterial());
|
||||
driver->drawMeshBuffer(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Get time for measuring timeout.
|
||||
@ -3162,7 +3135,8 @@ MapVoxelManipulator::~MapVoxelManipulator()
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
void MapVoxelManipulator::emerge(VoxelArea a)
|
||||
#if 1
|
||||
void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
|
||||
{
|
||||
TimeTaker timer1("emerge", g_device, &emerge_time);
|
||||
|
||||
@ -3190,8 +3164,11 @@ void MapVoxelManipulator::emerge(VoxelArea a)
|
||||
{
|
||||
TimeTaker timer1("emerge load", g_device, &emerge_load_time);
|
||||
|
||||
dstream<<"Loading block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<std::endl;
|
||||
/*dstream<<"Loading block (caller_id="<<caller_id<<")"
|
||||
<<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<" wanted area: ";
|
||||
a.print(dstream);
|
||||
dstream<<std::endl;*/
|
||||
|
||||
MapBlock *block = m_map->getBlockNoCreate(p);
|
||||
if(block->isDummy())
|
||||
@ -3221,6 +3198,43 @@ void MapVoxelManipulator::emerge(VoxelArea a)
|
||||
|
||||
//dstream<<"emerge done"<<std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void MapVoxelManipulator::emerge(VoxelArea a)
|
||||
{
|
||||
TimeTaker timer1("emerge", g_device, &emerge_time);
|
||||
|
||||
v3s16 size = a.getExtent();
|
||||
|
||||
VoxelArea padded = a;
|
||||
padded.pad(m_area.getExtent() / 4);
|
||||
addArea(padded);
|
||||
|
||||
for(s16 z=0; z<size.Z; z++)
|
||||
for(s16 y=0; y<size.Y; y++)
|
||||
for(s16 x=0; x<size.X; x++)
|
||||
{
|
||||
v3s16 p(x,y,z);
|
||||
s32 i = m_area.index(a.MinEdge + p);
|
||||
// Don't touch nodes that have already been loaded
|
||||
if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
|
||||
continue;
|
||||
try
|
||||
{
|
||||
TimeTaker timer1("emerge load", g_device, &emerge_load_time);
|
||||
MapNode n = m_map->getNode(a.MinEdge + p);
|
||||
m_data[i] = n;
|
||||
m_flags[i] = 0;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
m_flags[i] = VOXELFLAG_INEXISTENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
TODO: Add an option to only update eg. water and air nodes.
|
||||
@ -3230,6 +3244,9 @@ void MapVoxelManipulator::emerge(VoxelArea a)
|
||||
void MapVoxelManipulator::blitBack
|
||||
(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||
{
|
||||
if(m_area.getExtent() == v3s16(0,0,0))
|
||||
return;
|
||||
|
||||
TimeTaker timer1("blitBack", g_device);
|
||||
|
||||
/*
|
||||
|
11
src/map.h
11
src/map.h
@ -603,15 +603,18 @@ public:
|
||||
m_loaded_blocks.clear();
|
||||
}
|
||||
|
||||
virtual void emerge(VoxelArea a);
|
||||
virtual void emerge(VoxelArea a, s32 caller_id=-1);
|
||||
|
||||
void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
|
||||
|
||||
private:
|
||||
Map *m_map;
|
||||
// bool is dummy value
|
||||
// SUGG: How 'bout an another VoxelManipulator for storing the
|
||||
// information about which block is loaded?
|
||||
/*
|
||||
NOTE: This might be used or not
|
||||
bool is dummy value
|
||||
SUGG: How 'bout an another VoxelManipulator for storing the
|
||||
information about which block is loaded?
|
||||
*/
|
||||
core::map<v3s16, bool> m_loaded_blocks;
|
||||
};
|
||||
|
||||
|
@ -111,7 +111,7 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p,
|
||||
|
||||
u8 alpha = 255;
|
||||
|
||||
if(material == MATERIAL_WATER)
|
||||
if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
|
||||
{
|
||||
alpha = 128;
|
||||
}
|
||||
@ -173,13 +173,14 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
|
||||
|
||||
/*
|
||||
Gets node material from any place relative to block.
|
||||
Returns MATERIAL_AIR if doesn't exist.
|
||||
Returns MATERIAL_IGNORE if doesn't exist or should not be drawn.
|
||||
*/
|
||||
u8 MapBlock::getNodeMaterial(v3s16 p)
|
||||
{
|
||||
try{
|
||||
MapNode n = getNodeParent(p);
|
||||
return n.d;
|
||||
|
||||
return content_cube_material(n.d);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
@ -470,46 +471,6 @@ void MapBlock::updateMesh()
|
||||
|
||||
collector.fillMesh(mesh_new);
|
||||
|
||||
#if 0
|
||||
scene::IMeshBuffer *buf = NULL;
|
||||
|
||||
core::list<FastFace*>::Iterator i = fastfaces_new->begin();
|
||||
|
||||
// MATERIAL_AIR shouldn't be used by any face
|
||||
u8 material_in_use = MATERIAL_AIR;
|
||||
|
||||
for(; i != fastfaces_new->end(); i++)
|
||||
{
|
||||
FastFace *f = *i;
|
||||
|
||||
if(f->material != material_in_use || buf == NULL)
|
||||
{
|
||||
// Try to get a meshbuffer associated with the material
|
||||
buf = mesh_new->getMeshBuffer(g_materials[f->material]);
|
||||
// If not found, create one
|
||||
if(buf == NULL)
|
||||
{
|
||||
// This is a "Standard MeshBuffer",
|
||||
// it's a typedeffed CMeshBuffer<video::S3DVertex>
|
||||
buf = new scene::SMeshBuffer();
|
||||
// Set material
|
||||
((scene::SMeshBuffer*)buf)->Material = g_materials[f->material];
|
||||
// Use VBO
|
||||
//buf->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
// Add to mesh
|
||||
mesh_new->addMeshBuffer(buf);
|
||||
// Mesh grabbed it
|
||||
buf->drop();
|
||||
}
|
||||
material_in_use = f->material;
|
||||
}
|
||||
|
||||
u16 new_indices[] = {0,1,2,2,3,0};
|
||||
|
||||
//buf->append(f->vertices, 4, indices, 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Use VBO for mesh (this just would set this for ever buffer)
|
||||
//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
|
||||
@ -518,7 +479,10 @@ void MapBlock::updateMesh()
|
||||
<<" materials (meshbuffers)"<<std::endl;*/
|
||||
}
|
||||
|
||||
// TODO: Get rid of the FastFace stage
|
||||
/*
|
||||
Clear temporary FastFaces
|
||||
*/
|
||||
|
||||
core::list<FastFace*>::Iterator i;
|
||||
i = fastfaces_new->begin();
|
||||
for(; i != fastfaces_new->end(); i++)
|
||||
@ -528,6 +492,18 @@ void MapBlock::updateMesh()
|
||||
fastfaces_new->clear();
|
||||
delete fastfaces_new;
|
||||
|
||||
/*
|
||||
Add special graphics:
|
||||
- torches
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
Replace the mesh
|
||||
*/
|
||||
|
@ -56,6 +56,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
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
|
||||
*/
|
||||
|
||||
enum Material
|
||||
@ -78,6 +80,8 @@ enum Material
|
||||
|
||||
MATERIAL_MUD,
|
||||
|
||||
MATERIAL_OCEAN,
|
||||
|
||||
// This is set to the number of the actual values in this enum
|
||||
USEFUL_MATERIAL_COUNT
|
||||
};
|
||||
@ -88,7 +92,7 @@ enum Material
|
||||
*/
|
||||
inline bool light_propagates_material(u8 m)
|
||||
{
|
||||
return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER);
|
||||
return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -110,7 +114,7 @@ inline u8 material_solidness(u8 m)
|
||||
{
|
||||
if(m == MATERIAL_AIR)
|
||||
return 0;
|
||||
if(m == MATERIAL_WATER)
|
||||
if(m == MATERIAL_WATER || m == MATERIAL_OCEAN)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
@ -118,29 +122,54 @@ inline u8 material_solidness(u8 m)
|
||||
// Objects collide with walkable materials
|
||||
inline bool material_walkable(u8 m)
|
||||
{
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER);
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN && m != MATERIAL_LIGHT);
|
||||
}
|
||||
|
||||
// A liquid resists fast movement
|
||||
inline bool material_liquid(u8 m)
|
||||
{
|
||||
return (m == MATERIAL_WATER);
|
||||
return (m == MATERIAL_WATER || m == MATERIAL_OCEAN);
|
||||
}
|
||||
|
||||
// Pointable materials can be pointed to in the map
|
||||
inline bool material_pointable(u8 m)
|
||||
{
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER);
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
|
||||
}
|
||||
|
||||
inline bool material_diggable(u8 m)
|
||||
{
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER);
|
||||
return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
|
||||
}
|
||||
|
||||
inline bool material_buildable_to(u8 m)
|
||||
{
|
||||
return (m == MATERIAL_AIR || m == MATERIAL_WATER);
|
||||
return (m == MATERIAL_AIR || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
|
||||
}
|
||||
|
||||
/*
|
||||
As of now, input is a "material" and the output is a "material"
|
||||
*/
|
||||
inline u8 content_cube_material(u8 c)
|
||||
{
|
||||
if(c == MATERIAL_IGNORE || c == MATERIAL_LIGHT)
|
||||
return MATERIAL_AIR;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true for materials that form the base ground that
|
||||
follows the main heightmap
|
||||
*/
|
||||
inline bool is_ground_material(u8 m)
|
||||
{
|
||||
return(
|
||||
m == MATERIAL_STONE ||
|
||||
m == MATERIAL_GRASS ||
|
||||
m == MATERIAL_GRASS_FOOTSTEPS ||
|
||||
m == MATERIAL_MESE ||
|
||||
m == MATERIAL_MUD
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -168,21 +197,6 @@ inline u8 face_materials(u8 m1, u8 m2)
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true for materials that form the base ground that
|
||||
follows the main heightmap
|
||||
*/
|
||||
inline bool is_ground_material(u8 m)
|
||||
{
|
||||
return(
|
||||
m == MATERIAL_STONE ||
|
||||
m == MATERIAL_GRASS ||
|
||||
m == MATERIAL_GRASS_FOOTSTEPS ||
|
||||
m == MATERIAL_MESE ||
|
||||
m == MATERIAL_MUD
|
||||
);
|
||||
}
|
||||
|
||||
struct MapNode
|
||||
{
|
||||
//TODO: block type to differ from material
|
||||
@ -214,7 +228,9 @@ struct MapNode
|
||||
|
||||
bool operator==(const MapNode &other)
|
||||
{
|
||||
return (d == other.d && param == other.param);
|
||||
return (d == other.d
|
||||
&& param == other.param
|
||||
&& pressure == other.pressure);
|
||||
}
|
||||
|
||||
bool light_propagates()
|
||||
|
@ -196,6 +196,28 @@ void * EmergeThread::Thread()
|
||||
{
|
||||
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()
|
||||
@ -244,12 +266,6 @@ void * EmergeThread::Thread()
|
||||
// Remove block from sent history
|
||||
client->SetBlocksNotSent(modified_blocks);
|
||||
}
|
||||
|
||||
/*if(q->peer_ids.find(client->peer_id) != NULL)
|
||||
{
|
||||
// Decrement emerge queue count of client
|
||||
client->BlockEmerged();
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
@ -348,14 +364,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
|
||||
//bool has_incomplete_blocks = false;
|
||||
|
||||
/*
|
||||
TODO: Get this from somewhere
|
||||
*/
|
||||
//s16 d_max = 7;
|
||||
s16 d_max = 8;
|
||||
|
||||
//TODO: Get this from somewhere (probably a bigger value)
|
||||
s16 d_max_gen = 5;
|
||||
s16 d_max = g_settings.getS16("max_block_send_distance");
|
||||
s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
|
||||
|
||||
//dstream<<"Starting from "<<d_start<<std::endl;
|
||||
|
||||
@ -998,7 +1008,7 @@ void Server::AsyncRunStep()
|
||||
{
|
||||
static float counter = 0.0;
|
||||
counter += dtime;
|
||||
if(counter >= 1.0)
|
||||
if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
|
||||
{
|
||||
|
||||
counter = 0.0;
|
||||
@ -1011,16 +1021,7 @@ void Server::AsyncRunStep()
|
||||
|
||||
MapVoxelManipulator v(&m_env.getMap());
|
||||
|
||||
/*try{
|
||||
v.flowWater(m_flow_active_nodes, 0, false, 20);
|
||||
//v.flowWater(p_under, 0, true, 100);
|
||||
}
|
||||
catch(ProcessingLimitException &e)
|
||||
{
|
||||
dstream<<"Processing limit reached"<<std::endl;
|
||||
}*/
|
||||
|
||||
v.flowWater(m_flow_active_nodes, 0, false, 20);
|
||||
v.flowWater(m_flow_active_nodes, 0, false, 50);
|
||||
|
||||
v.blitBack(modified_blocks);
|
||||
|
||||
@ -1059,7 +1060,7 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // interval counter
|
||||
}
|
||||
|
||||
// Periodically print some info
|
||||
@ -1547,7 +1548,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
catch(ProcessingLimitException &e)
|
||||
{
|
||||
dstream<<"Processing limit reached"<<std::endl;
|
||||
dstream<<"Processing limit reached (1)"<<std::endl;
|
||||
}
|
||||
|
||||
v.blitBack(modified_blocks);
|
||||
@ -1624,6 +1625,28 @@ 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);
|
||||
|
||||
/*
|
||||
Update water
|
||||
*/
|
||||
|
||||
// Update water pressure around modification
|
||||
// This also adds it to m_flow_active_nodes if appropriate
|
||||
|
||||
MapVoxelManipulator v(&m_env.getMap());
|
||||
|
||||
VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1));
|
||||
|
||||
try
|
||||
{
|
||||
v.updateAreaWaterPressure(area, m_flow_active_nodes);
|
||||
}
|
||||
catch(ProcessingLimitException &e)
|
||||
{
|
||||
dstream<<"Processing limit reached (1)"<<std::endl;
|
||||
}
|
||||
|
||||
v.blitBack(modified_blocks);
|
||||
}
|
||||
/*
|
||||
Handle block object items
|
||||
@ -2019,6 +2042,10 @@ void Server::peerAdded(con::Peer *peer)
|
||||
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
|
||||
for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++)
|
||||
{
|
||||
// Skip some materials
|
||||
if(i == MATERIAL_OCEAN)
|
||||
continue;
|
||||
|
||||
InventoryItem *item = new MaterialItem(i, 1);
|
||||
player->inventory.addItem(item);
|
||||
}
|
||||
|
@ -264,11 +264,13 @@ struct TestVoxelManipulator
|
||||
s16 highest_y = -32768;
|
||||
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);*/
|
||||
|
||||
active_nodes.clear();
|
||||
active_nodes[v3s16(9,1,0)] = 1;
|
||||
//v.flowWater(active_nodes, 0, false);
|
||||
v.flowWater(active_nodes, 0, true);
|
||||
v.flowWater(active_nodes, 0, true, 1000);
|
||||
|
||||
dstream<<"Final result of flowWater:"<<std::endl;
|
||||
v.print(dstream, VOXELPRINT_WATERPRESSURE);
|
||||
|
185
src/voxel.cpp
185
src/voxel.cpp
@ -335,23 +335,26 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
|
||||
if(p.Y > highest_y)
|
||||
highest_y = p.Y;
|
||||
|
||||
recur_count++;
|
||||
if(recur_count > 30)
|
||||
/*if(recur_count > 1000)
|
||||
throw ProcessingLimitException
|
||||
("getWaterPressure recur_count limit reached");
|
||||
("getWaterPressure recur_count limit reached");*/
|
||||
|
||||
if(recur_count > 10000)
|
||||
return -1;
|
||||
|
||||
recur_count++;
|
||||
|
||||
v3s16 dirs[6] = {
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(-1,0,0), // left
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(-1,0,0), // left
|
||||
v3s16(0,-1,0), // bottom
|
||||
};
|
||||
|
||||
// Load neighboring nodes
|
||||
// TODO: A bigger area would be better
|
||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
|
||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
|
||||
|
||||
s32 i;
|
||||
for(i=0; i<6; i++)
|
||||
@ -368,13 +371,13 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
|
||||
|
||||
int pr;
|
||||
|
||||
// If at surface
|
||||
/*if(n.pressure == 1)
|
||||
// If at ocean surface
|
||||
if(n.pressure == 1 && n.d == MATERIAL_OCEAN)
|
||||
{
|
||||
pr = 1;
|
||||
}
|
||||
// Otherwise recurse more
|
||||
else*/
|
||||
else
|
||||
{
|
||||
pr = getWaterPressure(p2, highest_y, recur_count);
|
||||
if(pr == -1)
|
||||
@ -410,10 +413,21 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
core::map<v3s16, u8> &active_nodes,
|
||||
int recur_count)
|
||||
{
|
||||
//if(recur_count > 10000)
|
||||
/*throw ProcessingLimitException
|
||||
("spreadWaterPressure recur_count limit reached");*/
|
||||
if(recur_count > 10)
|
||||
return;
|
||||
recur_count++;
|
||||
if(recur_count > 10000)
|
||||
throw ProcessingLimitException
|
||||
("spreadWaterPressure recur_count limit reached");
|
||||
|
||||
/*dstream<<"spreadWaterPressure: p=("
|
||||
<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<", oldpr="<<(int)m_data[m_area.index(p)].pressure
|
||||
<<", pr="<<pr
|
||||
<<", recur_count="<<recur_count
|
||||
<<", request_area=";
|
||||
request_area.print(dstream);
|
||||
dstream<<std::endl;*/
|
||||
|
||||
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
|
||||
m_data[m_area.index(p)].pressure = pr;
|
||||
@ -428,7 +442,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
};
|
||||
|
||||
// Load neighboring nodes
|
||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
|
||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
|
||||
|
||||
s32 i;
|
||||
for(i=0; i<6; i++)
|
||||
@ -455,6 +469,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
// If block is at top
|
||||
if(i == 0)
|
||||
{
|
||||
//if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
|
||||
if(pr >= 3)
|
||||
pressure_causes_flow = true;
|
||||
}
|
||||
@ -466,6 +481,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
// If block is at side
|
||||
else
|
||||
{
|
||||
//if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
|
||||
if(pr >= 2)
|
||||
pressure_causes_flow = true;
|
||||
}
|
||||
@ -497,7 +513,10 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
||||
}
|
||||
|
||||
// Ignore if correct pressure is already set and is not on
|
||||
// request_area
|
||||
// request_area.
|
||||
// Thus, request_area can be used for updating as much
|
||||
// pressure info in some area as possible to possibly
|
||||
// make some calls to getWaterPressure unnecessary.
|
||||
if(n.pressure == pr2 && request_area.contains(p2) == false)
|
||||
continue;
|
||||
|
||||
@ -512,7 +531,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
|
||||
TimeTaker timer("updateAreaWaterPressure", g_device,
|
||||
&updateareawaterpressure_time);
|
||||
|
||||
emerge(a);
|
||||
emerge(a, 3);
|
||||
|
||||
bool checked2_clear = false;
|
||||
|
||||
@ -596,20 +615,21 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
|
||||
bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
core::map<v3s16, u8> &active_nodes,
|
||||
int recursion_depth, bool debugprint,
|
||||
int *counter, int counterlimit)
|
||||
u32 stoptime)
|
||||
{
|
||||
v3s16 dirs[6] = {
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(-1,0,0), // left
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(-1,0,0), // left
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,-1,0), // bottom
|
||||
};
|
||||
|
||||
recursion_depth++;
|
||||
|
||||
v3s16 p;
|
||||
bool from_ocean = false;
|
||||
|
||||
// Randomize horizontal order
|
||||
static s32 cs = 0;
|
||||
@ -625,7 +645,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
|
||||
|
||||
// Load neighboring nodes
|
||||
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
|
||||
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
|
||||
|
||||
// Ignore incorrect removed_pos
|
||||
{
|
||||
@ -660,11 +680,13 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
// If block is at bottom, select it if it has enough pressure
|
||||
if(i == 5)
|
||||
{
|
||||
//if(n.pressure >= PRESERVE_WATER_VOLUME ? 3 : 2)
|
||||
if(n.pressure >= 3)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
// Else block is at some side. Select it if it has enough pressure
|
||||
//if(n.pressure >= PRESERVE_WATER_VOLUME ? 2 : 1)
|
||||
if(n.pressure >= 2)
|
||||
{
|
||||
break;
|
||||
@ -675,22 +697,47 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
if(i==6)
|
||||
return false;
|
||||
|
||||
// Switch nodes at p and removed_pos
|
||||
/*
|
||||
Move water and bubble
|
||||
*/
|
||||
|
||||
u8 m = m_data[m_area.index(p)].d;
|
||||
u8 f = m_flags[m_area.index(p)];
|
||||
|
||||
if(m == MATERIAL_OCEAN)
|
||||
from_ocean = true;
|
||||
|
||||
// Move air bubble if not taking water from ocean
|
||||
if(from_ocean == false)
|
||||
{
|
||||
m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
|
||||
m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
|
||||
}
|
||||
|
||||
m_data[m_area.index(removed_pos)].d = m;
|
||||
m_flags[m_area.index(removed_pos)] = f;
|
||||
|
||||
// Mark removed_pos checked
|
||||
m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
|
||||
|
||||
// If block was dropped from surface, increase pressure
|
||||
if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
|
||||
{
|
||||
m_data[m_area.index(removed_pos)].pressure = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE: This does not work as-is
|
||||
if(m == MATERIAL_OCEAN)
|
||||
{
|
||||
// If block was raised to surface, increase pressure of
|
||||
// source node
|
||||
if(i == 5 && m_data[m_area.index(p)].pressure == 1)
|
||||
{
|
||||
m_data[m_area.index(p)].pressure = 2;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*if(debugprint)
|
||||
{
|
||||
dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
|
||||
@ -721,11 +768,29 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
||||
|
||||
}//timer1
|
||||
|
||||
//if(PRESERVE_WATER_VOLUME)
|
||||
if(from_ocean == false)
|
||||
{
|
||||
// Flow water to the newly created empty position
|
||||
/*flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);*/
|
||||
flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);
|
||||
debugprint, stoptime);
|
||||
}
|
||||
|
||||
if(stoptime != 0 && g_device != NULL)
|
||||
{
|
||||
u32 timenow = g_device->getTimer()->getRealTime();
|
||||
if(timenow >= stoptime ||
|
||||
(stoptime < 0x80000000 && timenow > 0x80000000))
|
||||
{
|
||||
dstream<<"flowWater: stoptime reached"<<std::endl;
|
||||
throw ProcessingLimitException("flowWater stoptime reached");
|
||||
}
|
||||
}
|
||||
|
||||
find_again:
|
||||
|
||||
// Try flowing water to empty positions around removed_pos.
|
||||
// They are checked in reverse order compared to the previous loop.
|
||||
for(s32 i=5; i>=0; i--)
|
||||
@ -745,7 +810,9 @@ find_again:
|
||||
// Flow water to node
|
||||
bool moved =
|
||||
flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);
|
||||
debugprint, stoptime);
|
||||
/*flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, counter, counterlimit);*/
|
||||
|
||||
if(moved)
|
||||
{
|
||||
@ -754,27 +821,13 @@ find_again:
|
||||
}
|
||||
}
|
||||
|
||||
if(counter != NULL)
|
||||
{
|
||||
(*counter)++;
|
||||
if((*counter) % 10 == 0)
|
||||
dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
|
||||
<<std::endl;
|
||||
|
||||
if(counterlimit != -1 && (*counter) > counterlimit)
|
||||
{
|
||||
dstream<<"Counter limit reached; returning"<<std::endl;
|
||||
throw ProcessingLimitException("flowWater counterlimit reached");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VoxelManipulator::flowWater(
|
||||
core::map<v3s16, u8> &active_nodes,
|
||||
int recursion_depth, bool debugprint,
|
||||
int counterlimit)
|
||||
u32 timelimit)
|
||||
{
|
||||
addarea_time = 0;
|
||||
emerge_time = 0;
|
||||
@ -783,25 +836,53 @@ void VoxelManipulator::flowWater(
|
||||
updateareawaterpressure_time = 0;
|
||||
flowwater_pre_time = 0;
|
||||
|
||||
if(active_nodes.size() == 0)
|
||||
{
|
||||
dstream<<"flowWater: no active nodes"<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
TimeTaker timer1("flowWater (active_nodes)", g_device);
|
||||
|
||||
dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
|
||||
|
||||
int counter = 0;
|
||||
//int counter = 0;
|
||||
|
||||
u32 stoptime = 0;
|
||||
if(g_device != NULL)
|
||||
{
|
||||
stoptime = g_device->getTimer()->getRealTime() + timelimit;
|
||||
}
|
||||
|
||||
// Count of handled active nodes
|
||||
u32 handled_count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
/*
|
||||
Take random one at first
|
||||
|
||||
This is randomized only at the first time so that all
|
||||
subsequent nodes will be taken at roughly the same position
|
||||
*/
|
||||
s32 k = 0;
|
||||
if(active_nodes.size() != 0)
|
||||
k = (s32)rand() % (s32)active_nodes.size();
|
||||
|
||||
// Flow water to active nodes
|
||||
for(;;)
|
||||
//for(s32 h=0; h<1; h++)
|
||||
{
|
||||
// Clear check flags
|
||||
clearFlag(VOXELFLAG_CHECKED);
|
||||
|
||||
if(active_nodes.size() == 0)
|
||||
break;
|
||||
|
||||
dstream<<"Selecting a new active_node"<<std::endl;
|
||||
handled_count++;
|
||||
|
||||
// Clear check flags
|
||||
clearFlag(VOXELFLAG_CHECKED);
|
||||
|
||||
//dstream<<"Selecting a new active_node"<<std::endl;
|
||||
|
||||
#if 0
|
||||
// Take first one
|
||||
@ -810,9 +891,7 @@ void VoxelManipulator::flowWater(
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// Take random one
|
||||
s32 k = (s32)rand() % (s32)active_nodes.size();
|
||||
//s32 k = 0;
|
||||
|
||||
core::map<v3s16, u8>::Iterator
|
||||
i = active_nodes.getIterator().getNode();
|
||||
for(s32 j=0; j<k; j++)
|
||||
@ -820,12 +899,17 @@ void VoxelManipulator::flowWater(
|
||||
i++;
|
||||
}
|
||||
core::map<v3s16, u8>::Node *n = i.getNode();
|
||||
|
||||
// Decrement index if less than 0.
|
||||
// This keeps us in existing indices always.
|
||||
if(k > 0)
|
||||
k--;
|
||||
#endif
|
||||
|
||||
v3s16 p = n->getKey();
|
||||
active_nodes.remove(p);
|
||||
flowWater(p, active_nodes, recursion_depth,
|
||||
debugprint, &counter, counterlimit);
|
||||
debugprint, stoptime);
|
||||
}
|
||||
|
||||
}
|
||||
@ -836,9 +920,12 @@ void VoxelManipulator::flowWater(
|
||||
|
||||
v3s16 e = m_area.getExtent();
|
||||
s32 v = m_area.getVolume();
|
||||
dstream<<"flowWater (active): moved "<<counter<<" nodes, "
|
||||
//dstream<<"flowWater (active): moved "<<counter<<" nodes, "
|
||||
dstream<<"flowWater (active): "
|
||||
<<"area ended up as "
|
||||
<<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
|
||||
<<", handled a_node count: "<<handled_count
|
||||
<<", active_nodes.size() = "<<active_nodes.size()
|
||||
<<std::endl;
|
||||
|
||||
dstream<<"addarea_time: "<<addarea_time
|
||||
|
@ -428,8 +428,8 @@ public:
|
||||
bool flowWater(v3s16 removed_pos,
|
||||
core::map<v3s16, u8> &active_nodes,
|
||||
int recursion_depth=0,
|
||||
bool debugprint=false, int *counter=NULL,
|
||||
int counterlimit=-1
|
||||
bool debugprint=false,
|
||||
u32 stoptime=0
|
||||
);
|
||||
|
||||
/*
|
||||
@ -446,7 +446,7 @@ public:
|
||||
void flowWater(core::map<v3s16, u8> &active_nodes,
|
||||
int recursion_depth=0,
|
||||
bool debugprint=false,
|
||||
int counterlimit=-1
|
||||
u32 timelimit=50
|
||||
);
|
||||
|
||||
/*
|
||||
@ -460,7 +460,7 @@ public:
|
||||
|
||||
If not found from source, add with VOXELFLAG_INEXISTENT
|
||||
*/
|
||||
virtual void emerge(VoxelArea a)
|
||||
virtual void emerge(VoxelArea a, s32 caller_id=-1)
|
||||
{
|
||||
//dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
|
||||
addArea(a);
|
||||
|
Loading…
Reference in New Issue
Block a user