Reworked texture, material, mineral and whatever handling
Before Width: | Height: | Size: 1.5 KiB |
BIN
data/grass.png
Before Width: | Height: | Size: 855 B After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 933 B |
After Width: | Height: | Size: 936 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 659 B |
|
@ -39,7 +39,6 @@ cp -r data/torch.png $PACKAGEPATH/data/
|
||||||
cp -r data/torch_on_floor.png $PACKAGEPATH/data/
|
cp -r data/torch_on_floor.png $PACKAGEPATH/data/
|
||||||
cp -r data/torch_on_ceiling.png $PACKAGEPATH/data/
|
cp -r data/torch_on_ceiling.png $PACKAGEPATH/data/
|
||||||
cp -r data/tree_top.png $PACKAGEPATH/data/
|
cp -r data/tree_top.png $PACKAGEPATH/data/
|
||||||
#cp -r data/mud_with_grass.png $PACKAGEPATH/data/
|
|
||||||
cp -r data/coalstone.png $PACKAGEPATH/data/
|
cp -r data/coalstone.png $PACKAGEPATH/data/
|
||||||
cp -r data/crack.png $PACKAGEPATH/data/
|
cp -r data/crack.png $PACKAGEPATH/data/
|
||||||
cp -r data/wood.png $PACKAGEPATH/data/
|
cp -r data/wood.png $PACKAGEPATH/data/
|
||||||
|
@ -48,6 +47,11 @@ cp -r data/tool_wpick.png $PACKAGEPATH/data/
|
||||||
cp -r data/tool_stpick.png $PACKAGEPATH/data/
|
cp -r data/tool_stpick.png $PACKAGEPATH/data/
|
||||||
cp -r data/tool_mesepick.png $PACKAGEPATH/data/
|
cp -r data/tool_mesepick.png $PACKAGEPATH/data/
|
||||||
cp -r data/grass_side.png $PACKAGEPATH/data/
|
cp -r data/grass_side.png $PACKAGEPATH/data/
|
||||||
|
cp -r data/lump_of_coal.png $PACKAGEPATH/data/
|
||||||
|
cp -r data/lump_of_iron.png $PACKAGEPATH/data/
|
||||||
|
cp -r data/mineral_coal.png $PACKAGEPATH/data/
|
||||||
|
cp -r data/mineral_iron.png $PACKAGEPATH/data/
|
||||||
|
cp -r data/sand.png $PACKAGEPATH/data/
|
||||||
|
|
||||||
#cp -r data/pauseMenu.gui $PACKAGEPATH/data/
|
#cp -r data/pauseMenu.gui $PACKAGEPATH/data/
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalLibraryDirectories=""C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib";"..\irrlicht\irrlicht-1.7.1\lib\Win32-visualstudio";..\zlib125dll\dll32"
|
AdditionalLibraryDirectories=""C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib";"..\irrlicht\irrlicht-1.7.1\lib\Win32-visualstudio";..\zlib125dll\dll32"
|
||||||
IgnoreDefaultLibraryNames="libcmtd.lib"
|
IgnoreDefaultLibraryNames="libcmtd.dll"
|
||||||
GenerateDebugInformation="false"
|
GenerateDebugInformation="false"
|
||||||
LinkTimeCodeGeneration="1"
|
LinkTimeCodeGeneration="1"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1273,6 +1273,7 @@ void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
|
||||||
0: start digging
|
0: start digging
|
||||||
1: place block
|
1: place block
|
||||||
2: stop digging (all parameters ignored)
|
2: stop digging (all parameters ignored)
|
||||||
|
3: digging completed
|
||||||
*/
|
*/
|
||||||
u8 datasize = 2 + 1 + 6 + 6 + 2;
|
u8 datasize = 2 + 1 + 6 + 6 + 2;
|
||||||
SharedBuffer<u8> data(datasize);
|
SharedBuffer<u8> data(datasize);
|
||||||
|
|
35
src/client.h
|
@ -197,6 +197,40 @@ public:
|
||||||
|
|
||||||
//void updateSomeExpiredMeshes();
|
//void updateSomeExpiredMeshes();
|
||||||
|
|
||||||
|
void setTempMod(v3s16 p, NodeMod mod)
|
||||||
|
{
|
||||||
|
JMutexAutoLock envlock(m_env_mutex);
|
||||||
|
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||||
|
|
||||||
|
core::map<v3s16, MapBlock*> affected_blocks;
|
||||||
|
((ClientMap&)m_env.getMap()).setTempMod(p, mod,
|
||||||
|
&affected_blocks);
|
||||||
|
|
||||||
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
|
i = affected_blocks.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void clearTempMod(v3s16 p)
|
||||||
|
{
|
||||||
|
JMutexAutoLock envlock(m_env_mutex);
|
||||||
|
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||||
|
|
||||||
|
core::map<v3s16, MapBlock*> affected_blocks;
|
||||||
|
((ClientMap&)m_env.getMap()).clearTempMod(p,
|
||||||
|
&affected_blocks);
|
||||||
|
|
||||||
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
|
i = affected_blocks.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void setTempMod(v3s16 p, NodeMod mod)
|
void setTempMod(v3s16 p, NodeMod mod)
|
||||||
{
|
{
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
JMutexAutoLock envlock(m_env_mutex);
|
||||||
|
@ -215,6 +249,7 @@ public:
|
||||||
if(changed)
|
if(changed)
|
||||||
m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
|
m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
float getAvgRtt()
|
float getAvgRtt()
|
||||||
{
|
{
|
||||||
|
|
|
@ -122,12 +122,6 @@ public:
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
video::ITexture * getImage()
|
video::ITexture * getImage()
|
||||||
{
|
{
|
||||||
/*if(m_content == CONTENT_TORCH)
|
|
||||||
return g_texturecache.get("torch_on_floor");
|
|
||||||
|
|
||||||
u16 tile = content_tile(m_content, v3s16(1,0,0));
|
|
||||||
return g_tile_contents[tile].getTexture(0);*/
|
|
||||||
|
|
||||||
if(m_content >= USEFUL_CONTENT_COUNT)
|
if(m_content >= USEFUL_CONTENT_COUNT)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -257,15 +251,18 @@ public:
|
||||||
video::ITexture * getImage()
|
video::ITexture * getImage()
|
||||||
{
|
{
|
||||||
std::string basename;
|
std::string basename;
|
||||||
|
|
||||||
if(m_subname == "Stick")
|
if(m_subname == "Stick")
|
||||||
basename = porting::getDataPath("stick.png").c_str();
|
basename = porting::getDataPath("stick.png");
|
||||||
// Default to cloud texture
|
else if(m_subname == "lump_of_coal")
|
||||||
|
basename = porting::getDataPath("lump_of_coal.png");
|
||||||
|
else if(m_subname == "lump_of_iron")
|
||||||
|
basename = porting::getDataPath("lump_of_iron.png");
|
||||||
else
|
else
|
||||||
basename = tile_texture_path_get(TILE_CLOUD);
|
basename = porting::getDataPath("cloud.png[[mod:crack3");
|
||||||
|
|
||||||
// Get such a texture
|
// Get such a texture
|
||||||
return g_irrlicht->getTexture(basename);
|
return g_irrlicht->getTexture(basename);
|
||||||
//return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::string getText()
|
std::string getText()
|
||||||
|
@ -340,7 +337,8 @@ public:
|
||||||
basename = porting::getDataPath("tool_mesepick.png").c_str();
|
basename = porting::getDataPath("tool_mesepick.png").c_str();
|
||||||
// Default to cloud texture
|
// Default to cloud texture
|
||||||
else
|
else
|
||||||
basename = tile_texture_path_get(TILE_CLOUD);
|
basename = porting::getDataPath("cloud.png").c_str();
|
||||||
|
//basename = tile_texture_path_get(TILE_CLOUD);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate some progress value with sane amount of
|
Calculate some progress value with sane amount of
|
||||||
|
@ -350,6 +348,12 @@ public:
|
||||||
u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
|
u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
|
||||||
|
|
||||||
// Make texture name for the new texture with a progress bar
|
// Make texture name for the new texture with a progress bar
|
||||||
|
float value_f = (float)toolprogress / (float)maxprogress;
|
||||||
|
std::ostringstream os;
|
||||||
|
os<<basename<<"[[mod:progressbar"<<value_f;
|
||||||
|
return g_irrlicht->getTexture(os.str());
|
||||||
|
|
||||||
|
/*// Make texture name for the new texture with a progress bar
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os<<basename<<"-toolprogress-"<<toolprogress;
|
os<<basename<<"-toolprogress-"<<toolprogress;
|
||||||
std::string finalname = os.str();
|
std::string finalname = os.str();
|
||||||
|
@ -358,7 +362,7 @@ public:
|
||||||
|
|
||||||
// Get such a texture
|
// Get such a texture
|
||||||
TextureMod *mod = new ProgressBarTextureMod(value_f);
|
TextureMod *mod = new ProgressBarTextureMod(value_f);
|
||||||
return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
|
return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));*/
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::string getText()
|
std::string getText()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "irrlichtwrapper.h"
|
#include "irrlichtwrapper.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "strfnd.h"
|
||||||
|
|
||||||
IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
|
IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
|
||||||
{
|
{
|
||||||
|
@ -15,13 +17,13 @@ void IrrlichtWrapper::Run()
|
||||||
*/
|
*/
|
||||||
if(m_get_texture_queue.size() > 0)
|
if(m_get_texture_queue.size() > 0)
|
||||||
{
|
{
|
||||||
GetRequest<TextureSpec, video::ITexture*, u8, u8>
|
GetRequest<std::string, video::ITexture*, u8, u8>
|
||||||
request = m_get_texture_queue.pop();
|
request = m_get_texture_queue.pop();
|
||||||
|
|
||||||
dstream<<"got texture request with key.name="
|
dstream<<"got texture request with key="
|
||||||
<<request.key.name<<std::endl;
|
<<request.key<<std::endl;
|
||||||
|
|
||||||
GetResult<TextureSpec, video::ITexture*, u8, u8>
|
GetResult<std::string, video::ITexture*, u8, u8>
|
||||||
result;
|
result;
|
||||||
result.key = request.key;
|
result.key = request.key;
|
||||||
result.callers = request.callers;
|
result.callers = request.callers;
|
||||||
|
@ -31,38 +33,41 @@ void IrrlichtWrapper::Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture* IrrlichtWrapper::getTexture(TextureSpec spec)
|
video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
|
||||||
{
|
{
|
||||||
video::ITexture *t = m_texturecache.get(spec.name);
|
if(spec == "")
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
video::ITexture *t = m_texturecache.get(spec);
|
||||||
if(t != NULL)
|
if(t != NULL)
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
if(get_current_thread_id() == m_main_thread)
|
if(get_current_thread_id() == m_main_thread)
|
||||||
{
|
{
|
||||||
dstream<<"Getting texture directly: name="
|
dstream<<"Getting texture directly: spec="
|
||||||
<<spec.name<<std::endl;
|
<<spec<<std::endl;
|
||||||
|
|
||||||
t = getTextureDirect(spec);
|
t = getTextureDirect(spec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We're gonna ask the result to be put into here
|
// We're gonna ask the result to be put into here
|
||||||
ResultQueue<TextureSpec, video::ITexture*, u8, u8> result_queue;
|
ResultQueue<std::string, video::ITexture*, u8, u8> result_queue;
|
||||||
|
|
||||||
// Throw a request in
|
// Throw a request in
|
||||||
m_get_texture_queue.add(spec, 0, 0, &result_queue);
|
m_get_texture_queue.add(spec, 0, 0, &result_queue);
|
||||||
|
|
||||||
dstream<<"Waiting for texture from main thread: "
|
dstream<<"Waiting for texture from main thread: "
|
||||||
<<spec.name<<std::endl;
|
<<spec<<std::endl;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Wait result for a second
|
// Wait result for a second
|
||||||
GetResult<TextureSpec, video::ITexture*, u8, u8>
|
GetResult<std::string, video::ITexture*, u8, u8>
|
||||||
result = result_queue.pop_front(1000);
|
result = result_queue.pop_front(1000);
|
||||||
|
|
||||||
// Check that at least something worked OK
|
// Check that at least something worked OK
|
||||||
assert(result.key.name == spec.name);
|
assert(result.key == spec);
|
||||||
|
|
||||||
t = result.item;
|
t = result.item;
|
||||||
}
|
}
|
||||||
|
@ -74,44 +79,63 @@ video::ITexture* IrrlichtWrapper::getTexture(TextureSpec spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to cache and return
|
// Add to cache and return
|
||||||
m_texturecache.set(spec.name, t);
|
m_texturecache.set(spec, t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture* IrrlichtWrapper::getTexture(const std::string &path)
|
|
||||||
{
|
|
||||||
return getTexture(TextureSpec(path, path, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Non-thread-safe functions
|
Non-thread-safe functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
video::ITexture* IrrlichtWrapper::getTextureDirect(TextureSpec spec)
|
/*
|
||||||
{
|
Texture modifier functions
|
||||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
*/
|
||||||
|
|
||||||
if(spec.mod == NULL)
|
// blitted_name = eg. "mineral_coal.png"
|
||||||
{
|
video::ITexture * make_blitname(const std::string &blitted_name,
|
||||||
dstream<<"IrrlichtWrapper::getTextureDirect: Loading texture "
|
video::ITexture *original,
|
||||||
<<spec.path<<std::endl;
|
|
||||||
return driver->getTexture(spec.path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
dstream<<"IrrlichtWrapper::getTextureDirect: Loading and modifying "
|
|
||||||
"texture "<<spec.path<<" to make "<<spec.name<<std::endl;
|
|
||||||
|
|
||||||
video::ITexture *base = driver->getTexture(spec.path.c_str());
|
|
||||||
video::ITexture *result = spec.mod->make(base, spec.name.c_str(), driver);
|
|
||||||
|
|
||||||
delete spec.mod;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::ITexture * CrackTextureMod::make(video::ITexture *original,
|
|
||||||
const char *newname, video::IVideoDriver* driver)
|
const char *newname, video::IVideoDriver* driver)
|
||||||
{
|
{
|
||||||
|
if(original == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Size of the base image
|
||||||
|
core::dimension2d<u32> dim(16, 16);
|
||||||
|
// Position to copy the blitted to in the base image
|
||||||
|
core::position2d<s32> pos_base(0, 0);
|
||||||
|
// Position to copy the blitted from in the blitted image
|
||||||
|
core::position2d<s32> pos_other(0, 0);
|
||||||
|
|
||||||
|
video::IImage *baseimage = driver->createImage(original, pos_base, dim);
|
||||||
|
assert(baseimage);
|
||||||
|
|
||||||
|
video::IImage *blittedimage = driver->createImageFromFile(porting::getDataPath(blitted_name.c_str()).c_str());
|
||||||
|
assert(blittedimage);
|
||||||
|
|
||||||
|
// Then copy the right part of blittedimage to baseimage
|
||||||
|
|
||||||
|
blittedimage->copyToWithAlpha(baseimage, v2s32(0,0),
|
||||||
|
core::rect<s32>(pos_other, dim),
|
||||||
|
video::SColor(255,255,255,255),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
blittedimage->drop();
|
||||||
|
|
||||||
|
// Create texture from resulting image
|
||||||
|
|
||||||
|
video::ITexture *newtexture = driver->addTexture(newname, baseimage);
|
||||||
|
|
||||||
|
baseimage->drop();
|
||||||
|
|
||||||
|
return newtexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::ITexture * make_crack(u16 progression, video::ITexture *original,
|
||||||
|
const char *newname, video::IVideoDriver* driver)
|
||||||
|
{
|
||||||
|
if(original == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// Size of the base image
|
// Size of the base image
|
||||||
core::dimension2d<u32> dim(16, 16);
|
core::dimension2d<u32> dim(16, 16);
|
||||||
// Size of the crack image
|
// Size of the crack image
|
||||||
|
@ -127,36 +151,6 @@ video::ITexture * CrackTextureMod::make(video::ITexture *original,
|
||||||
video::IImage *crackimage = driver->createImageFromFile(porting::getDataPath("crack.png").c_str());
|
video::IImage *crackimage = driver->createImageFromFile(porting::getDataPath("crack.png").c_str());
|
||||||
assert(crackimage);
|
assert(crackimage);
|
||||||
|
|
||||||
#if 0
|
|
||||||
video::ITexture *other = driver->getTexture(porting::getDataPath("crack.png").c_str());
|
|
||||||
|
|
||||||
dstream<<__FUNCTION_NAME<<": crack texture size is "
|
|
||||||
<<other->getSize().Width<<"x"
|
|
||||||
<<other->getSize().Height<<std::endl;
|
|
||||||
|
|
||||||
// We have to get the whole texture because getting a smaller area
|
|
||||||
// messes the whole thing. It is probably a bug in Irrlicht.
|
|
||||||
// NOTE: This doesn't work probably because some systems scale
|
|
||||||
// the image to fit a texture or something...
|
|
||||||
video::IImage *otherimage = driver->createImage(
|
|
||||||
other, core::position2d<s32>(0,0), other->getSize());
|
|
||||||
|
|
||||||
assert(otherimage);
|
|
||||||
|
|
||||||
// Now, the image might be 80 or 128 high depending on the computer
|
|
||||||
// Let's make an image of the right size and copy the possibly
|
|
||||||
// wrong sized one with scaling
|
|
||||||
// NOTE: This is an ugly hack.
|
|
||||||
|
|
||||||
video::IImage *crackimage = driver->createImage(
|
|
||||||
baseimage->getColorFormat(), dim_crack);
|
|
||||||
|
|
||||||
assert(crackimage);
|
|
||||||
|
|
||||||
otherimage->copyToScaling(crackimage);
|
|
||||||
otherimage->drop();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Then copy the right part of crackimage to baseimage
|
// Then copy the right part of crackimage to baseimage
|
||||||
|
|
||||||
crackimage->copyToWithAlpha(baseimage, v2s32(0,0),
|
crackimage->copyToWithAlpha(baseimage, v2s32(0,0),
|
||||||
|
@ -175,9 +169,13 @@ video::ITexture * CrackTextureMod::make(video::ITexture *original,
|
||||||
return newtexture;
|
return newtexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture * SideGrassTextureMod::make(video::ITexture *original,
|
#if 0
|
||||||
|
video::ITexture * make_sidegrass(video::ITexture *original,
|
||||||
const char *newname, video::IVideoDriver* driver)
|
const char *newname, video::IVideoDriver* driver)
|
||||||
{
|
{
|
||||||
|
if(original == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// Size of the base image
|
// Size of the base image
|
||||||
core::dimension2d<u32> dim(16, 16);
|
core::dimension2d<u32> dim(16, 16);
|
||||||
// Position to copy the grass to in the base image
|
// Position to copy the grass to in the base image
|
||||||
|
@ -208,10 +206,14 @@ video::ITexture * SideGrassTextureMod::make(video::ITexture *original,
|
||||||
|
|
||||||
return newtexture;
|
return newtexture;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
video::ITexture * ProgressBarTextureMod::make(video::ITexture *original,
|
video::ITexture * make_progressbar(float value, video::ITexture *original,
|
||||||
const char *newname, video::IVideoDriver* driver)
|
const char *newname, video::IVideoDriver* driver)
|
||||||
{
|
{
|
||||||
|
if(original == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
core::position2d<s32> pos_base(0, 0);
|
core::position2d<s32> pos_base(0, 0);
|
||||||
core::dimension2d<u32> dim = original->getOriginalSize();
|
core::dimension2d<u32> dim = original->getOriginalSize();
|
||||||
|
|
||||||
|
@ -251,3 +253,166 @@ video::ITexture * ProgressBarTextureMod::make(video::ITexture *original,
|
||||||
return newtexture;
|
return newtexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Texture fetcher/maker function, called always from the main thread
|
||||||
|
*/
|
||||||
|
|
||||||
|
video::ITexture* IrrlichtWrapper::getTextureDirect(const std::string &spec)
|
||||||
|
{
|
||||||
|
if(spec == "")
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input (spec) is something like this:
|
||||||
|
"/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3"
|
||||||
|
*/
|
||||||
|
|
||||||
|
video::ITexture* t = NULL;
|
||||||
|
std::string modmagic = "[[mod:";
|
||||||
|
Strfnd f(spec);
|
||||||
|
std::string path = f.next(modmagic);
|
||||||
|
t = driver->getTexture(path.c_str());
|
||||||
|
std::string texture_name = path;
|
||||||
|
while(f.atend() == false)
|
||||||
|
{
|
||||||
|
std::string mod = f.next(modmagic);
|
||||||
|
texture_name += modmagic + mod;
|
||||||
|
dstream<<"Making texture \""<<texture_name<<"\""<<std::endl;
|
||||||
|
/*if(mod == "sidegrass")
|
||||||
|
{
|
||||||
|
t = make_sidegrass(t, texture_name.c_str(), driver);
|
||||||
|
}
|
||||||
|
else*/
|
||||||
|
if(mod.substr(0, 9) == "blitname:")
|
||||||
|
{
|
||||||
|
//t = make_sidegrass(t, texture_name.c_str(), driver);
|
||||||
|
t = make_blitname(mod.substr(9), t, texture_name.c_str(), driver);
|
||||||
|
}
|
||||||
|
else if(mod.substr(0,5) == "crack")
|
||||||
|
{
|
||||||
|
u16 prog = stoi(mod.substr(5));
|
||||||
|
t = make_crack(prog, t, texture_name.c_str(), driver);
|
||||||
|
}
|
||||||
|
else if(mod.substr(0,11) == "progressbar")
|
||||||
|
{
|
||||||
|
float value = stof(mod.substr(11));
|
||||||
|
t = make_progressbar(value, t, texture_name.c_str(), driver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstream<<"Invalid texture mod: \""<<mod<<"\""<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
video::ITexture* t = NULL;
|
||||||
|
const char *modmagic = "[[mod:";
|
||||||
|
const s32 modmagic_len = 6;
|
||||||
|
enum{
|
||||||
|
READMODE_PATH,
|
||||||
|
READMODE_MOD
|
||||||
|
} readmode = READMODE_PATH;
|
||||||
|
s32 specsize = spec.size()+1;
|
||||||
|
char *strcache = (char*)malloc(specsize);
|
||||||
|
assert(strcache);
|
||||||
|
char *path = NULL;
|
||||||
|
s32 length = 0;
|
||||||
|
// Next index of modmagic to be found
|
||||||
|
s32 modmagic_i = 0;
|
||||||
|
u32 i=0;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
strcache[length++] = spec[i];
|
||||||
|
|
||||||
|
bool got_modmagic = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check modmagic
|
||||||
|
*/
|
||||||
|
if(spec[i] == modmagic[modmagic_i])
|
||||||
|
{
|
||||||
|
modmagic_i++;
|
||||||
|
if(modmagic_i == modmagic_len)
|
||||||
|
{
|
||||||
|
got_modmagic = true;
|
||||||
|
modmagic_i = 0;
|
||||||
|
length -= modmagic_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
modmagic_i = 0;
|
||||||
|
|
||||||
|
// Set i to be the length of read string
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(got_modmagic || i >= spec.size())
|
||||||
|
{
|
||||||
|
strcache[length] = '\0';
|
||||||
|
// Now our string is in strcache, ending in \0
|
||||||
|
|
||||||
|
if(readmode == READMODE_PATH)
|
||||||
|
{
|
||||||
|
// Get initial texture (strcache is path)
|
||||||
|
assert(t == NULL);
|
||||||
|
t = driver->getTexture(strcache);
|
||||||
|
readmode = READMODE_MOD;
|
||||||
|
path = strcache;
|
||||||
|
strcache = (char*)malloc(specsize);
|
||||||
|
assert(strcache);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstream<<"Parsing mod \""<<strcache<<"\""<<std::endl;
|
||||||
|
// The name of the result of adding this mod.
|
||||||
|
// This doesn't have to be fast so std::string is used.
|
||||||
|
std::string name(path);
|
||||||
|
name += "[[mod:";
|
||||||
|
name += strcache;
|
||||||
|
dstream<<"Name of modded texture is \""<<name<<"\""
|
||||||
|
<<std::endl;
|
||||||
|
// Sidegrass
|
||||||
|
if(strcmp(strcache, "sidegrass") == 0)
|
||||||
|
{
|
||||||
|
t = make_sidegrass(t, name.c_str(), driver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstream<<"Invalid texture mod"<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i >= spec.size())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(spec.mod == NULL)
|
||||||
|
{
|
||||||
|
dstream<<"IrrlichtWrapper::getTextureDirect: Loading texture "
|
||||||
|
<<spec.path<<std::endl;
|
||||||
|
return driver->getTexture(spec.path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
dstream<<"IrrlichtWrapper::getTextureDirect: Loading and modifying "
|
||||||
|
"texture "<<spec.path<<" to make "<<spec.name<<std::endl;
|
||||||
|
|
||||||
|
video::ITexture *base = driver->getTexture(spec.path.c_str());
|
||||||
|
video::ITexture *result = spec.mod->make(base, spec.name.c_str(), driver);
|
||||||
|
|
||||||
|
delete spec.mod;*/
|
||||||
|
|
||||||
|
if(strcache)
|
||||||
|
free(strcache);
|
||||||
|
if(path)
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
m_textures[name] = texture;
|
m_textures[name] = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture* get(std::string name)
|
video::ITexture* get(const std::string &name)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_mutex);
|
JMutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
|
@ -74,86 +74,6 @@ private:
|
||||||
JMutex m_mutex;
|
JMutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureMod
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Returns a new texture which can be based on the original.
|
|
||||||
Shall not modify or delete the original texture.
|
|
||||||
*/
|
|
||||||
virtual video::ITexture * make(video::ITexture *original,
|
|
||||||
const char *newname, video::IVideoDriver* driver) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CrackTextureMod: public TextureMod
|
|
||||||
{
|
|
||||||
CrackTextureMod(u16 a_progression)
|
|
||||||
{
|
|
||||||
progression = a_progression;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual video::ITexture * make(video::ITexture *original,
|
|
||||||
const char *newname, video::IVideoDriver* driver);
|
|
||||||
|
|
||||||
u16 progression;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SideGrassTextureMod: public TextureMod
|
|
||||||
{
|
|
||||||
SideGrassTextureMod()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual video::ITexture * make(video::ITexture *original,
|
|
||||||
const char *newname, video::IVideoDriver* driver);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProgressBarTextureMod: public TextureMod
|
|
||||||
{
|
|
||||||
// value is from 0.0 to 1.0
|
|
||||||
ProgressBarTextureMod(float a_value)
|
|
||||||
{
|
|
||||||
value = a_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual video::ITexture * make(video::ITexture *original,
|
|
||||||
const char *newname, video::IVideoDriver* driver);
|
|
||||||
|
|
||||||
float value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
A class for specifying a requested texture
|
|
||||||
*/
|
|
||||||
struct TextureSpec
|
|
||||||
{
|
|
||||||
TextureSpec()
|
|
||||||
{
|
|
||||||
mod = NULL;
|
|
||||||
}
|
|
||||||
TextureSpec(const std::string &a_name, const std::string &a_path,
|
|
||||||
TextureMod *a_mod)
|
|
||||||
{
|
|
||||||
name = a_name;
|
|
||||||
path = a_path;
|
|
||||||
mod = a_mod;;
|
|
||||||
}
|
|
||||||
~TextureSpec()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool operator==(const TextureSpec &other)
|
|
||||||
{
|
|
||||||
return name == other.name;
|
|
||||||
}
|
|
||||||
// An unique name for the texture. Usually the same as the path.
|
|
||||||
// Note that names and paths reside the same namespace.
|
|
||||||
std::string name;
|
|
||||||
// This is the path of the base texture
|
|
||||||
std::string path;
|
|
||||||
// Modification to do to the base texture
|
|
||||||
// NOTE: This is deleted by the one who processes the request
|
|
||||||
TextureMod *mod;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A thread-safe wrapper for irrlicht, to be accessed from
|
A thread-safe wrapper for irrlicht, to be accessed from
|
||||||
background worker threads.
|
background worker threads.
|
||||||
|
@ -183,14 +103,17 @@ public:
|
||||||
return m_device->getTimer()->getRealTime();
|
return m_device->getTimer()->getRealTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture* getTexture(TextureSpec spec);
|
/*
|
||||||
video::ITexture* getTexture(const std::string &path);
|
Path can contain stuff like
|
||||||
|
"/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3"
|
||||||
|
*/
|
||||||
|
video::ITexture* getTexture(const std::string &spec);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
Non-thread-safe variants of stuff, for internal use
|
Non-thread-safe variants of stuff, for internal use
|
||||||
*/
|
*/
|
||||||
video::ITexture* getTextureDirect(TextureSpec spec);
|
video::ITexture* getTextureDirect(const std::string &spec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Members
|
Members
|
||||||
|
@ -203,7 +126,7 @@ private:
|
||||||
|
|
||||||
TextureCache m_texturecache;
|
TextureCache m_texturecache;
|
||||||
|
|
||||||
RequestQueue<TextureSpec, video::ITexture*, u8, u8> m_get_texture_queue;
|
RequestQueue<std::string, video::ITexture*, u8, u8> m_get_texture_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
145
src/map.cpp
|
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
|
#include "mineral.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Map
|
Map
|
||||||
|
@ -627,9 +628,8 @@ void Map::updateLighting(enum LightBank bank,
|
||||||
//TimeTaker timer("updateLighting");
|
//TimeTaker timer("updateLighting");
|
||||||
|
|
||||||
// For debugging
|
// For debugging
|
||||||
bool debug=true;
|
//bool debug=true;
|
||||||
|
//u32 count_was = modified_blocks.size();
|
||||||
u32 count_was = modified_blocks.size();
|
|
||||||
|
|
||||||
core::map<v3s16, bool> light_sources;
|
core::map<v3s16, bool> light_sources;
|
||||||
|
|
||||||
|
@ -1835,9 +1835,18 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
|
||||||
randfactor = 0.5;
|
randfactor = 0.5;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
baseheight = 0;
|
if(myrand()%3 < 2)
|
||||||
randmax = 15;
|
{
|
||||||
randfactor = 0.63;
|
baseheight = 10;
|
||||||
|
randmax = 30;
|
||||||
|
randfactor = 0.7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseheight = 0;
|
||||||
|
randmax = 15;
|
||||||
|
randfactor = 0.63;
|
||||||
|
}
|
||||||
|
|
||||||
list_baseheight->addPoint(p, Attribute(baseheight));
|
list_baseheight->addPoint(p, Attribute(baseheight));
|
||||||
list_randmax->addPoint(p, Attribute(randmax));
|
list_randmax->addPoint(p, Attribute(randmax));
|
||||||
|
@ -2699,7 +2708,7 @@ continue_generating:
|
||||||
+ued*(y0*ued/MAP_BLOCKSIZE)
|
+ued*(y0*ued/MAP_BLOCKSIZE)
|
||||||
+(x0*ued/MAP_BLOCKSIZE)])
|
+(x0*ued/MAP_BLOCKSIZE)])
|
||||||
{
|
{
|
||||||
if(is_ground_content(n.d))
|
if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
|
||||||
{
|
{
|
||||||
// Has now caves
|
// Has now caves
|
||||||
has_dungeons = true;
|
has_dungeons = true;
|
||||||
|
@ -2755,17 +2764,11 @@ continue_generating:
|
||||||
MapNode n;
|
MapNode n;
|
||||||
n.d = CONTENT_MESE;
|
n.d = CONTENT_MESE;
|
||||||
|
|
||||||
//if(is_ground_content(block->getNode(cp).d))
|
for(u16 i=0; i<27; i++)
|
||||||
if(block->getNode(cp).d == CONTENT_STONE)
|
|
||||||
if(myrand()%8 == 0)
|
|
||||||
block->setNode(cp, n);
|
|
||||||
|
|
||||||
for(u16 i=0; i<26; i++)
|
|
||||||
{
|
{
|
||||||
//if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
|
if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
|
||||||
if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
|
|
||||||
if(myrand()%8 == 0)
|
if(myrand()%8 == 0)
|
||||||
block->setNode(cp+g_26dirs[i], n);
|
block->setNode(cp+g_27dirs[i], n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2790,21 +2793,47 @@ continue_generating:
|
||||||
);
|
);
|
||||||
|
|
||||||
MapNode n;
|
MapNode n;
|
||||||
n.d = CONTENT_COALSTONE;
|
n.d = CONTENT_STONE;
|
||||||
|
n.param = MINERAL_COAL;
|
||||||
|
|
||||||
//dstream<<"Adding coalstone"<<std::endl;
|
for(u16 i=0; i<27; i++)
|
||||||
|
|
||||||
//if(is_ground_content(block->getNode(cp).d))
|
|
||||||
if(block->getNode(cp).d == CONTENT_STONE)
|
|
||||||
if(myrand()%8 == 0)
|
|
||||||
block->setNode(cp, n);
|
|
||||||
|
|
||||||
for(u16 i=0; i<26; i++)
|
|
||||||
{
|
{
|
||||||
//if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
|
if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
|
||||||
if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
|
|
||||||
if(myrand()%8 == 0)
|
if(myrand()%8 == 0)
|
||||||
block->setNode(cp+g_26dirs[i], n);
|
block->setNode(cp+g_27dirs[i], n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add iron
|
||||||
|
*/
|
||||||
|
//TODO: change to iron_amount or whatever
|
||||||
|
u16 iron_amount = 30.0 * g_settings.getFloat("coal_amount");
|
||||||
|
u16 iron_rareness = 60 / iron_amount;
|
||||||
|
if(iron_rareness == 0)
|
||||||
|
iron_rareness = 1;
|
||||||
|
if(myrand()%iron_rareness == 0)
|
||||||
|
{
|
||||||
|
u16 a = myrand() % 16;
|
||||||
|
u16 amount = iron_amount * a*a*a / 1000;
|
||||||
|
for(s16 i=0; i<amount; i++)
|
||||||
|
{
|
||||||
|
v3s16 cp(
|
||||||
|
(myrand()%(MAP_BLOCKSIZE-2))+1,
|
||||||
|
(myrand()%(MAP_BLOCKSIZE-2))+1,
|
||||||
|
(myrand()%(MAP_BLOCKSIZE-2))+1
|
||||||
|
);
|
||||||
|
|
||||||
|
MapNode n;
|
||||||
|
n.d = CONTENT_STONE;
|
||||||
|
n.param = MINERAL_IRON;
|
||||||
|
|
||||||
|
for(u16 i=0; i<27; i++)
|
||||||
|
{
|
||||||
|
if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
|
||||||
|
if(myrand()%8 == 0)
|
||||||
|
block->setNode(cp+g_27dirs[i], n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3012,26 +3041,23 @@ continue_generating:
|
||||||
<<std::endl;*/
|
<<std::endl;*/
|
||||||
{
|
{
|
||||||
v3s16 p2 = p + v3s16(x,y,z-2);
|
v3s16 p2 = p + v3s16(x,y,z-2);
|
||||||
if(is_ground_content(sector->getNode(p2).d)
|
//if(is_ground_content(sector->getNode(p2).d))
|
||||||
&& !is_mineral(sector->getNode(p2).d))
|
if(content_features(sector->getNode(p2).d).walkable)
|
||||||
sector->setNode(p2, n);
|
sector->setNode(p2, n);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
v3s16 p2 = p + v3s16(x,y,z-1);
|
v3s16 p2 = p + v3s16(x,y,z-1);
|
||||||
if(is_ground_content(sector->getNode(p2).d)
|
if(content_features(sector->getNode(p2).d).walkable)
|
||||||
&& !is_mineral(sector->getNode(p2).d))
|
|
||||||
sector->setNode(p2, n2);
|
sector->setNode(p2, n2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
v3s16 p2 = p + v3s16(x,y,z+0);
|
v3s16 p2 = p + v3s16(x,y,z+0);
|
||||||
if(is_ground_content(sector->getNode(p2).d)
|
if(content_features(sector->getNode(p2).d).walkable)
|
||||||
&& !is_mineral(sector->getNode(p2).d))
|
|
||||||
sector->setNode(p2, n2);
|
sector->setNode(p2, n2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
v3s16 p2 = p + v3s16(x,y,z+1);
|
v3s16 p2 = p + v3s16(x,y,z+1);
|
||||||
if(is_ground_content(sector->getNode(p2).d)
|
if(content_features(sector->getNode(p2).d).walkable)
|
||||||
&& !is_mineral(sector->getNode(p2).d))
|
|
||||||
sector->setNode(p2, n);
|
sector->setNode(p2, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4027,8 +4053,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
|
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod, bool *changed)
|
bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
|
||||||
|
core::map<v3s16, MapBlock*> *affected_blocks)
|
||||||
{
|
{
|
||||||
|
bool changed = false;
|
||||||
/*
|
/*
|
||||||
Add it to all blocks touching it
|
Add it to all blocks touching it
|
||||||
*/
|
*/
|
||||||
|
@ -4053,14 +4081,29 @@ v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod, bool *changed)
|
||||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||||
if(blockref->setTempMod(relpos, mod))
|
if(blockref->setTempMod(relpos, mod))
|
||||||
{
|
{
|
||||||
if(changed != NULL)
|
changed = true;
|
||||||
*changed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getNodeBlockPos(p);
|
if(changed && affected_blocks!=NULL)
|
||||||
|
{
|
||||||
|
for(u16 i=0; i<7; i++)
|
||||||
|
{
|
||||||
|
v3s16 p2 = p + dirs[i];
|
||||||
|
// Block position of neighbor (or requested) node
|
||||||
|
v3s16 blockpos = getNodeBlockPos(p2);
|
||||||
|
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||||
|
if(blockref == NULL)
|
||||||
|
continue;
|
||||||
|
affected_blocks->insert(blockpos, blockref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
v3s16 ClientMap::clearTempMod(v3s16 p, bool *changed)
|
|
||||||
|
bool ClientMap::clearTempMod(v3s16 p,
|
||||||
|
core::map<v3s16, MapBlock*> *affected_blocks)
|
||||||
{
|
{
|
||||||
|
bool changed = false;
|
||||||
v3s16 dirs[7] = {
|
v3s16 dirs[7] = {
|
||||||
v3s16(0,0,0), // this
|
v3s16(0,0,0), // this
|
||||||
v3s16(0,0,1), // back
|
v3s16(0,0,1), // back
|
||||||
|
@ -4082,11 +4125,23 @@ v3s16 ClientMap::clearTempMod(v3s16 p, bool *changed)
|
||||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||||
if(blockref->clearTempMod(relpos))
|
if(blockref->clearTempMod(relpos))
|
||||||
{
|
{
|
||||||
if(changed != NULL)
|
changed = true;
|
||||||
*changed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getNodeBlockPos(p);
|
if(changed && affected_blocks!=NULL)
|
||||||
|
{
|
||||||
|
for(u16 i=0; i<7; i++)
|
||||||
|
{
|
||||||
|
v3s16 p2 = p + dirs[i];
|
||||||
|
// Block position of neighbor (or requested) node
|
||||||
|
v3s16 blockpos = getNodeBlockPos(p2);
|
||||||
|
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||||
|
if(blockref == NULL)
|
||||||
|
continue;
|
||||||
|
affected_blocks->insert(blockpos, blockref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientMap::PrintInfo(std::ostream &out)
|
void ClientMap::PrintInfo(std::ostream &out)
|
||||||
|
@ -4216,7 +4271,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: Add an option to only update eg. water and air nodes.
|
SUGG: Add an option to only update eg. water and air nodes.
|
||||||
This will make it interfere less with important stuff if
|
This will make it interfere less with important stuff if
|
||||||
run on background.
|
run on background.
|
||||||
*/
|
*/
|
||||||
|
|
17
src/map.h
|
@ -204,10 +204,13 @@ public:
|
||||||
void expireMeshes(bool only_daynight_diffed);
|
void expireMeshes(bool only_daynight_diffed);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Updates the faces of the given block and blocks on the
|
Update the faces of the given block and blocks on the
|
||||||
leading edge.
|
leading edge.
|
||||||
*/
|
*/
|
||||||
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
||||||
|
|
||||||
|
// Update meshes that touch the node
|
||||||
|
//void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -483,10 +486,16 @@ public:
|
||||||
/*
|
/*
|
||||||
Methods for setting temporary modifications to nodes for
|
Methods for setting temporary modifications to nodes for
|
||||||
drawing.
|
drawing.
|
||||||
Return value is position of changed block.
|
|
||||||
|
Returns true if something changed.
|
||||||
|
|
||||||
|
All blocks whose mesh could have been changed are inserted
|
||||||
|
to affected_blocks.
|
||||||
*/
|
*/
|
||||||
v3s16 setTempMod(v3s16 p, NodeMod mod, bool *changed=NULL);
|
bool setTempMod(v3s16 p, NodeMod mod,
|
||||||
v3s16 clearTempMod(v3s16 p, bool *changed=NULL);
|
core::map<v3s16, MapBlock*> *affected_blocks=NULL);
|
||||||
|
bool clearTempMod(v3s16 p,
|
||||||
|
core::map<v3s16, MapBlock*> *affected_blocks=NULL);
|
||||||
// Efficient implementation needs a cache of TempMods
|
// Efficient implementation needs a cache of TempMods
|
||||||
//void clearTempMods();
|
//void clearTempMods();
|
||||||
|
|
||||||
|
|
|
@ -264,12 +264,10 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
|
||||||
//u8 li = decode_light(light);
|
//u8 li = decode_light(light);
|
||||||
u8 li = light;
|
u8 li = light;
|
||||||
|
|
||||||
u8 alpha = 255;
|
u8 alpha = tile.alpha;
|
||||||
|
/*u8 alpha = 255;
|
||||||
if(tile.id == TILE_WATER)
|
if(tile.id == TILE_WATER)
|
||||||
{
|
alpha = WATER_ALPHA;*/
|
||||||
alpha = WATER_ALPHA;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor c = video::SColor(alpha,li,li,li);
|
video::SColor c = video::SColor(alpha,li,li,li);
|
||||||
|
|
||||||
|
@ -297,16 +295,7 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
|
||||||
TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
|
TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
|
||||||
{
|
{
|
||||||
TileSpec spec;
|
TileSpec spec;
|
||||||
|
spec = mn.getTile(face_dir);
|
||||||
/*//DEBUG
|
|
||||||
{
|
|
||||||
spec.id = TILE_STONE;
|
|
||||||
return spec;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
spec.feature = TILEFEAT_NONE;
|
|
||||||
//spec.id = TILE_STONE;
|
|
||||||
spec.id = mn.getTile(face_dir);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check temporary modifications on this node
|
Check temporary modifications on this node
|
||||||
|
@ -320,12 +309,15 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
|
||||||
struct NodeMod mod = n->getValue();
|
struct NodeMod mod = n->getValue();
|
||||||
if(mod.type == NODEMOD_CHANGECONTENT)
|
if(mod.type == NODEMOD_CHANGECONTENT)
|
||||||
{
|
{
|
||||||
spec.id = content_tile(mod.param, face_dir);
|
//spec = content_tile(mod.param, face_dir);
|
||||||
|
MapNode mn2(mod.param);
|
||||||
|
spec = mn2.getTile(face_dir);
|
||||||
}
|
}
|
||||||
if(mod.type == NODEMOD_CRACK)
|
if(mod.type == NODEMOD_CRACK)
|
||||||
{
|
{
|
||||||
spec.feature = TILEFEAT_CRACK;
|
std::ostringstream os;
|
||||||
spec.param.crack.progression = mod.param;
|
os<<"[[mod:crack"<<mod.param;
|
||||||
|
spec.name += os.str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,35 +668,18 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||||
|
|
||||||
const u16 indices[] = {0,1,2,2,3,0};
|
const u16 indices[] = {0,1,2,2,3,0};
|
||||||
|
|
||||||
if(f.tile.feature == TILEFEAT_NONE)
|
video::ITexture *texture = g_irrlicht->getTexture(f.tile.name);
|
||||||
{
|
video::SMaterial material;
|
||||||
collector.append(tile_material_get(f.tile.id), f.vertices, 4,
|
material.Lighting = false;
|
||||||
indices, 6);
|
material.BackfaceCulling = false;
|
||||||
}
|
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||||
else if(f.tile.feature == TILEFEAT_CRACK)
|
material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
|
||||||
{
|
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||||
const char *path = tile_texture_path_get(f.tile.id);
|
material.setTexture(0, texture);
|
||||||
|
if(f.tile.alpha != 255)
|
||||||
|
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||||
|
|
||||||
u16 progression = f.tile.param.crack.progression;
|
collector.append(material, f.vertices, 4, indices, 6);
|
||||||
|
|
||||||
std::string name = (std::string)path + "_cracked_"
|
|
||||||
+ (char)('0' + progression);
|
|
||||||
|
|
||||||
TextureMod *mod = new CrackTextureMod(progression);
|
|
||||||
|
|
||||||
video::ITexture *texture = g_irrlicht->getTexture(
|
|
||||||
TextureSpec(name, path, mod));
|
|
||||||
|
|
||||||
video::SMaterial material = tile_material_get(f.tile.id);
|
|
||||||
material.setTexture(0, texture);
|
|
||||||
|
|
||||||
collector.append(material, f.vertices, 4, indices, 6);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No such feature
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1427,7 +1402,8 @@ s16 MapBlock::getGroundLevel(v2s16 p2d)
|
||||||
s16 y = MAP_BLOCKSIZE-1;
|
s16 y = MAP_BLOCKSIZE-1;
|
||||||
for(; y>=0; y--)
|
for(; y>=0; y--)
|
||||||
{
|
{
|
||||||
if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
|
//if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
|
||||||
|
if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
|
||||||
{
|
{
|
||||||
if(y == MAP_BLOCKSIZE-1)
|
if(y == MAP_BLOCKSIZE-1)
|
||||||
return -2;
|
return -2;
|
||||||
|
|
228
src/mapnode.cpp
|
@ -21,61 +21,197 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "mineral.h"
|
||||||
|
|
||||||
/*
|
ContentFeatures::~ContentFeatures()
|
||||||
Face directions:
|
|
||||||
0: up
|
|
||||||
1: down
|
|
||||||
2: right
|
|
||||||
3: left
|
|
||||||
4: back
|
|
||||||
5: front
|
|
||||||
*/
|
|
||||||
u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] =
|
|
||||||
{
|
{
|
||||||
{TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE},
|
if(translate_to)
|
||||||
{TILE_GRASS,TILE_MUD,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS},
|
delete translate_to;
|
||||||
//{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},
|
|
||||||
{TILE_GRASS_FOOTSTEPS,TILE_MUD,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS},
|
|
||||||
{TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE},
|
|
||||||
{TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD},
|
|
||||||
{TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER}, // ocean
|
|
||||||
{TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD},
|
|
||||||
{TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE},
|
|
||||||
{TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD},
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string g_content_inventory_texture_strings[USEFUL_CONTENT_COUNT];
|
struct ContentFeatures g_content_features[256];
|
||||||
// Pointers to c_str()s of the above
|
|
||||||
|
void init_mapnode()
|
||||||
|
{
|
||||||
|
u8 i;
|
||||||
|
ContentFeatures *f = NULL;
|
||||||
|
|
||||||
|
i = CONTENT_STONE;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("stone.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_GRASS;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
//f->setAllTextures("mud.png[[mod:sidegrass");
|
||||||
|
f->setAllTextures("mud.png[[mod:blitname:grass_side.png");
|
||||||
|
f->setTexture(0, "grass.png");
|
||||||
|
f->setTexture(1, "mud.png");
|
||||||
|
f->setInventoryImage("grass.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_GRASS_FOOTSTEPS;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
//f->setAllTextures("mud.png[[mod:sidegrass");
|
||||||
|
f->setAllTextures("mud.png[[mod:blitname:grass_side.png");
|
||||||
|
f->setTexture(0, "grass_footsteps.png");
|
||||||
|
f->setTexture(1, "mud.png");
|
||||||
|
f->setInventoryImage("grass_footsteps.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_MUD;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("mud.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_SAND;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("mud.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_TREE;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("tree.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_LEAVES;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("leaves.png");
|
||||||
|
f->param_type = CPT_MINERAL;
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_COALSTONE;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
|
||||||
|
/*f->setAllTextures("coalstone.png");
|
||||||
|
f->is_ground_content = true;*/
|
||||||
|
|
||||||
|
i = CONTENT_WOOD;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("wood.png");
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_MESE;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("mese.png");
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_CLOUD;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setAllTextures("cloud.png");
|
||||||
|
f->is_ground_content = true;
|
||||||
|
|
||||||
|
i = CONTENT_AIR;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->param_type = CPT_LIGHT;
|
||||||
|
f->light_propagates = true;
|
||||||
|
f->sunlight_propagates = true;
|
||||||
|
f->solidness = 0;
|
||||||
|
f->walkable = false;
|
||||||
|
f->pointable = false;
|
||||||
|
f->diggable = false;
|
||||||
|
f->buildable_to = true;
|
||||||
|
|
||||||
|
i = CONTENT_WATER;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setInventoryImage("water.png");
|
||||||
|
f->param_type = CPT_LIGHT;
|
||||||
|
f->light_propagates = true;
|
||||||
|
f->solidness = 0; // Drawn separately, makes no faces
|
||||||
|
f->walkable = false;
|
||||||
|
f->pointable = false;
|
||||||
|
f->diggable = false;
|
||||||
|
f->buildable_to = true;
|
||||||
|
f->liquid_type = LIQUID_FLOWING;
|
||||||
|
|
||||||
|
i = CONTENT_WATERSOURCE;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setTexture(0, "water.png", WATER_ALPHA);
|
||||||
|
f->setInventoryImage("water.png");
|
||||||
|
f->param_type = CPT_LIGHT;
|
||||||
|
f->light_propagates = true;
|
||||||
|
f->solidness = 1;
|
||||||
|
f->walkable = false;
|
||||||
|
f->pointable = false;
|
||||||
|
f->diggable = false;
|
||||||
|
f->buildable_to = true;
|
||||||
|
f->liquid_type = LIQUID_SOURCE;
|
||||||
|
|
||||||
|
i = CONTENT_TORCH;
|
||||||
|
f = &g_content_features[i];
|
||||||
|
f->setInventoryImage("torch_on_floor.png");
|
||||||
|
f->param_type = CPT_LIGHT;
|
||||||
|
f->light_propagates = true;
|
||||||
|
f->solidness = 0; // drawn separately, makes no faces
|
||||||
|
f->walkable = false;
|
||||||
|
f->wall_mounted = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TileSpec MapNode::getTile(v3s16 dir)
|
||||||
|
{
|
||||||
|
TileSpec spec;
|
||||||
|
|
||||||
|
s32 dir_i = -1;
|
||||||
|
|
||||||
|
if(dir == v3s16(0,1,0))
|
||||||
|
dir_i = 0;
|
||||||
|
else if(dir == v3s16(0,-1,0))
|
||||||
|
dir_i = 1;
|
||||||
|
else if(dir == v3s16(1,0,0))
|
||||||
|
dir_i = 2;
|
||||||
|
else if(dir == v3s16(-1,0,0))
|
||||||
|
dir_i = 3;
|
||||||
|
else if(dir == v3s16(0,0,1))
|
||||||
|
dir_i = 4;
|
||||||
|
else if(dir == v3s16(0,0,-1))
|
||||||
|
dir_i = 5;
|
||||||
|
|
||||||
|
if(dir_i == -1)
|
||||||
|
// Non-directional
|
||||||
|
spec = content_features(d).tiles[0];
|
||||||
|
else
|
||||||
|
spec = content_features(d).tiles[dir_i];
|
||||||
|
|
||||||
|
if(content_features(d).param_type == CPT_MINERAL)
|
||||||
|
{
|
||||||
|
u8 mineral = param & 0x1f;
|
||||||
|
const char *ts = mineral_block_texture(mineral);
|
||||||
|
if(ts[0] != 0)
|
||||||
|
{
|
||||||
|
spec.name += "[[mod:blitname:";
|
||||||
|
spec.name += ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 MapNode::getMineral()
|
||||||
|
{
|
||||||
|
if(content_features(d).param_type == CPT_MINERAL)
|
||||||
|
{
|
||||||
|
return param & 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MINERAL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointers to c_str()s g_content_features[i].inventory_image_path
|
||||||
const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT] = {0};
|
const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT] = {0};
|
||||||
|
|
||||||
const char * g_content_inventory_texture_paths_base[USEFUL_CONTENT_COUNT] =
|
|
||||||
{
|
|
||||||
"stone.png",
|
|
||||||
"grass.png",
|
|
||||||
"water.png",
|
|
||||||
"torch_on_floor.png",
|
|
||||||
"tree_top.png",
|
|
||||||
"leaves.png",
|
|
||||||
"grass_footsteps.png",
|
|
||||||
"mese.png",
|
|
||||||
"mud.png",
|
|
||||||
"water.png", //ocean
|
|
||||||
"cloud.png",
|
|
||||||
"coalstone.png",
|
|
||||||
"wood.png",
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_content_inventory_texture_paths()
|
void init_content_inventory_texture_paths()
|
||||||
{
|
{
|
||||||
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
|
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
|
||||||
{
|
{
|
||||||
g_content_inventory_texture_strings[i] = porting::getDataPath(g_content_inventory_texture_paths_base[i]);
|
g_content_inventory_texture_paths[i] =
|
||||||
g_content_inventory_texture_paths[i] = g_content_inventory_texture_strings[i].c_str();
|
g_content_features[i].inventory_image_path.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
298
src/mapnode.h
|
@ -28,6 +28,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
|
// Initializes all kind of stuff in here.
|
||||||
|
// Doesn't depend on anything else.
|
||||||
|
// Many things depend on this.
|
||||||
|
void init_mapnode();
|
||||||
|
|
||||||
|
// Initializes g_content_inventory_texture_paths
|
||||||
|
void init_content_inventory_texture_paths();
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: This is not used appropriately everywhere.
|
||||||
#define MATERIALS_COUNT 256
|
#define MATERIALS_COUNT 256
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -69,33 +79,143 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define CONTENT_MESE 7
|
#define CONTENT_MESE 7
|
||||||
#define CONTENT_MUD 8
|
#define CONTENT_MUD 8
|
||||||
#define CONTENT_WATERSOURCE 9
|
#define CONTENT_WATERSOURCE 9
|
||||||
|
// Pretty much useless, clouds won't be drawn this way
|
||||||
#define CONTENT_CLOUD 10
|
#define CONTENT_CLOUD 10
|
||||||
#define CONTENT_COALSTONE 11
|
#define CONTENT_COALSTONE 11
|
||||||
#define CONTENT_WOOD 12
|
#define CONTENT_WOOD 12
|
||||||
|
#define CONTENT_SAND 13
|
||||||
|
|
||||||
#define USEFUL_CONTENT_COUNT 13
|
/*
|
||||||
|
This is used by all kinds of things to allocate memory for all
|
||||||
|
contents except CONTENT_AIR and CONTENT_IGNORE
|
||||||
|
*/
|
||||||
|
#define USEFUL_CONTENT_COUNT 14
|
||||||
|
|
||||||
|
/*
|
||||||
|
Content feature list
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ContentParamType
|
||||||
|
{
|
||||||
|
CPT_NONE,
|
||||||
|
CPT_LIGHT,
|
||||||
|
CPT_MINERAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LiquidType
|
||||||
|
{
|
||||||
|
LIQUID_NONE,
|
||||||
|
LIQUID_FLOWING,
|
||||||
|
LIQUID_SOURCE
|
||||||
|
};
|
||||||
|
|
||||||
|
class MapNode;
|
||||||
|
|
||||||
|
struct ContentFeatures
|
||||||
|
{
|
||||||
|
// If non-NULL, content is translated to this when deserialized
|
||||||
|
MapNode *translate_to;
|
||||||
|
|
||||||
|
// Type of MapNode::param
|
||||||
|
ContentParamType param_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
0: up
|
||||||
|
1: down
|
||||||
|
2: right
|
||||||
|
3: left
|
||||||
|
4: back
|
||||||
|
5: front
|
||||||
|
*/
|
||||||
|
TileSpec tiles[6];
|
||||||
|
|
||||||
|
std::string inventory_image_path;
|
||||||
|
|
||||||
|
bool is_ground_content; //TODO: Remove, use walkable instead
|
||||||
|
bool light_propagates;
|
||||||
|
bool sunlight_propagates;
|
||||||
|
u8 solidness; // Used when choosing which face is drawn
|
||||||
|
bool walkable;
|
||||||
|
bool pointable;
|
||||||
|
bool diggable;
|
||||||
|
bool buildable_to;
|
||||||
|
enum LiquidType liquid_type;
|
||||||
|
bool wall_mounted; // If true, param2 is set to direction when placed
|
||||||
|
|
||||||
|
//TODO: Move more properties here
|
||||||
|
|
||||||
|
ContentFeatures()
|
||||||
|
{
|
||||||
|
translate_to = NULL;
|
||||||
|
param_type = CPT_NONE;
|
||||||
|
is_ground_content = false;
|
||||||
|
light_propagates = false;
|
||||||
|
sunlight_propagates = false;
|
||||||
|
solidness = 2;
|
||||||
|
walkable = true;
|
||||||
|
pointable = true;
|
||||||
|
diggable = true;
|
||||||
|
buildable_to = false;
|
||||||
|
liquid_type = LIQUID_NONE;
|
||||||
|
wall_mounted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ContentFeatures();
|
||||||
|
|
||||||
|
void setAllTextures(std::string imgname, u8 alpha=255)
|
||||||
|
{
|
||||||
|
for(u16 i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
tiles[i].name = porting::getDataPath(imgname.c_str());
|
||||||
|
tiles[i].alpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this too so it can be left as is most times
|
||||||
|
if(inventory_image_path == "")
|
||||||
|
inventory_image_path = porting::getDataPath(imgname.c_str());
|
||||||
|
}
|
||||||
|
void setTexture(u16 i, std::string imgname, u8 alpha=255)
|
||||||
|
{
|
||||||
|
tiles[i].name = porting::getDataPath(imgname.c_str());
|
||||||
|
tiles[i].alpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInventoryImage(std::string imgname)
|
||||||
|
{
|
||||||
|
inventory_image_path = porting::getDataPath(imgname.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialized by init_mapnode()
|
||||||
|
extern struct ContentFeatures g_content_features[256];
|
||||||
|
|
||||||
|
inline ContentFeatures & content_features(u8 i)
|
||||||
|
{
|
||||||
|
return g_content_features[i];
|
||||||
|
}
|
||||||
|
|
||||||
extern u16 g_content_tiles[USEFUL_CONTENT_COUNT][6];
|
|
||||||
extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
|
extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
|
||||||
// Initializes g_content_inventory_texture_paths
|
|
||||||
void init_content_inventory_texture_paths();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If true, the material allows light propagation and brightness is stored
|
If true, the material allows light propagation and brightness is stored
|
||||||
in param.
|
in param.
|
||||||
|
NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
*/
|
*/
|
||||||
inline bool light_propagates_content(u8 m)
|
inline bool light_propagates_content(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
return g_content_features[m].light_propagates;
|
||||||
|
//return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If true, the material allows lossless sunlight propagation.
|
If true, the material allows lossless sunlight propagation.
|
||||||
NOTE: It doesn't seem to go through torches regardlessly of this
|
NOTE: It doesn't seem to go through torches regardlessly of this
|
||||||
|
NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
*/
|
*/
|
||||||
inline bool sunlight_propagates_content(u8 m)
|
inline bool sunlight_propagates_content(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_AIR || m == CONTENT_TORCH);
|
return g_content_features[m].sunlight_propagates;
|
||||||
|
//return (m == CONTENT_AIR || m == CONTENT_TORCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -104,36 +224,46 @@ inline bool sunlight_propagates_content(u8 m)
|
||||||
0: Invisible
|
0: Invisible
|
||||||
1: Transparent
|
1: Transparent
|
||||||
2: Opaque
|
2: Opaque
|
||||||
|
NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
*/
|
*/
|
||||||
inline u8 content_solidness(u8 m)
|
inline u8 content_solidness(u8 m)
|
||||||
{
|
{
|
||||||
// As of now, every pseudo node like torches are added to this
|
return g_content_features[m].solidness;
|
||||||
|
/*// As of now, every pseudo node like torches are added to this
|
||||||
if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
|
if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
|
||||||
return 0;
|
return 0;
|
||||||
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
|
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
|
||||||
return 1;
|
return 1;
|
||||||
return 2;
|
return 2;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Objects collide with walkable contents
|
// Objects collide with walkable contents
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_walkable(u8 m)
|
inline bool content_walkable(u8 m)
|
||||||
{
|
{
|
||||||
return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
|
return g_content_features[m].walkable;
|
||||||
|
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_liquid(u8 m)
|
inline bool content_liquid(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
return g_content_features[m].liquid_type != LIQUID_NONE;
|
||||||
|
//return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_flowing_liquid(u8 m)
|
inline bool content_flowing_liquid(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_WATER);
|
return g_content_features[m].liquid_type == LIQUID_FLOWING;
|
||||||
|
//return (m == CONTENT_WATER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_liquid_source(u8 m)
|
inline bool content_liquid_source(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_WATERSOURCE);
|
return g_content_features[m].liquid_type == LIQUID_SOURCE;
|
||||||
|
//return (m == CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
|
// CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
|
||||||
|
@ -146,57 +276,35 @@ inline u8 make_liquid_flowing(u8 m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointable contents can be pointed to in the map
|
// Pointable contents can be pointed to in the map
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_pointable(u8 m)
|
inline bool content_pointable(u8 m)
|
||||||
{
|
{
|
||||||
return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
return g_content_features[m].pointable;
|
||||||
|
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_diggable(u8 m)
|
inline bool content_diggable(u8 m)
|
||||||
{
|
{
|
||||||
return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
return g_content_features[m].diggable;
|
||||||
|
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||||
inline bool content_buildable_to(u8 m)
|
inline bool content_buildable_to(u8 m)
|
||||||
{
|
{
|
||||||
return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
return g_content_features[m].buildable_to;
|
||||||
|
//return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns true for contents that form the base ground that
|
Returns true for contents that form the base ground that
|
||||||
follows the main heightmap
|
follows the main heightmap
|
||||||
*/
|
*/
|
||||||
inline bool is_ground_content(u8 m)
|
/*inline bool is_ground_content(u8 m)
|
||||||
{
|
{
|
||||||
return (
|
return g_content_features[m].is_ground_content;
|
||||||
m != CONTENT_IGNORE
|
}*/
|
||||||
&& m != CONTENT_AIR
|
|
||||||
&& m != CONTENT_WATER
|
|
||||||
&& m != CONTENT_TORCH
|
|
||||||
&& m != CONTENT_TREE
|
|
||||||
&& m != CONTENT_LEAVES
|
|
||||||
&& m != CONTENT_WATERSOURCE
|
|
||||||
&& m != CONTENT_CLOUD
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_mineral(u8 c)
|
|
||||||
{
|
|
||||||
return(c == CONTENT_MESE
|
|
||||||
|| c == CONTENT_COALSTONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool liquid_replaces_content(u8 c)
|
|
||||||
{
|
|
||||||
return (c == CONTENT_AIR || c == CONTENT_TORCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
When placing a node, drection info is added to it if this is true
|
|
||||||
*/
|
|
||||||
inline bool content_directional(u8 c)
|
|
||||||
{
|
|
||||||
return (c == CONTENT_TORCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Nodes make a face if contents differ and solidness differs.
|
Nodes make a face if contents differ and solidness differs.
|
||||||
|
@ -275,87 +383,15 @@ inline v3s16 unpackDir(u8 b)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u16 content_tile(u8 c, v3s16 dir)
|
|
||||||
{
|
|
||||||
if(c == CONTENT_IGNORE || c == CONTENT_AIR
|
|
||||||
|| c >= USEFUL_CONTENT_COUNT)
|
|
||||||
return TILE_NONE;
|
|
||||||
|
|
||||||
s32 dir_i = -1;
|
|
||||||
|
|
||||||
if(dir == v3s16(0,1,0))
|
|
||||||
dir_i = 0;
|
|
||||||
else if(dir == v3s16(0,-1,0))
|
|
||||||
dir_i = 1;
|
|
||||||
else if(dir == v3s16(1,0,0))
|
|
||||||
dir_i = 2;
|
|
||||||
else if(dir == v3s16(-1,0,0))
|
|
||||||
dir_i = 3;
|
|
||||||
else if(dir == v3s16(0,0,1))
|
|
||||||
dir_i = 4;
|
|
||||||
else if(dir == v3s16(0,0,-1))
|
|
||||||
dir_i = 5;
|
|
||||||
|
|
||||||
/*if(dir_i == -1)
|
|
||||||
return TILE_NONE;*/
|
|
||||||
assert(dir_i != -1);
|
|
||||||
|
|
||||||
return g_content_tiles[c][dir_i];
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LightBank
|
enum LightBank
|
||||||
{
|
{
|
||||||
LIGHTBANK_DAY,
|
LIGHTBANK_DAY,
|
||||||
LIGHTBANK_NIGHT
|
LIGHTBANK_NIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
/*
|
||||||
#define DIR_PX 1 //X+
|
This is the stuff what the whole world consists of.
|
||||||
#define DIR_NX 2 //X-
|
*/
|
||||||
#define DIR_PZ 4 //Z+
|
|
||||||
#define DIR_NZ 8 //Z-
|
|
||||||
#define DIR_PY 16 //Y+
|
|
||||||
#define DIR_NY 32 //Y-
|
|
||||||
|
|
||||||
inline void decode_dirs(u8 b, core::list<v3s16> &dirs)
|
|
||||||
{
|
|
||||||
if(b & DIR_PX)
|
|
||||||
dirs.push_back(v3s16(1,0,0));
|
|
||||||
if(b & DIR_NX)
|
|
||||||
dirs.push_back(v3s16(-1,0,0));
|
|
||||||
if(b & DIR_PZ)
|
|
||||||
dirs.push_back(v3s16(0,0,1));
|
|
||||||
if(b & DIR_NZ)
|
|
||||||
dirs.push_back(v3s16(0,0,-1));
|
|
||||||
if(b & DIR_PY)
|
|
||||||
dirs.push_back(v3s16(0,1,0));
|
|
||||||
if(b & DIR_NY)
|
|
||||||
dirs.push_back(v3s16(0,-1,0));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u8 encode_dirs(core::list<v3s16> &dirs)
|
|
||||||
{
|
|
||||||
u8 b = 0;
|
|
||||||
for(core::list<v3s16>::Iterator
|
|
||||||
i = dirs.begin();
|
|
||||||
i != dirs.end(); i++)
|
|
||||||
{
|
|
||||||
if(*i == v3s16(1,0,0))
|
|
||||||
b += DIR_PX;
|
|
||||||
else if(*i == v3s16(-1,0,0))
|
|
||||||
b += DIR_NX;
|
|
||||||
else if(*i == v3s16(0,0,1))
|
|
||||||
b += DIR_PZ;
|
|
||||||
else if(*i == v3s16(0,0,-1))
|
|
||||||
b += DIR_NZ;
|
|
||||||
else if(*i == v3s16(0,1,0))
|
|
||||||
b += DIR_PY;
|
|
||||||
else if(*i == v3s16(0,-1,0))
|
|
||||||
b += DIR_NY;
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct MapNode
|
struct MapNode
|
||||||
{
|
{
|
||||||
|
@ -512,10 +548,10 @@ struct MapNode
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 getTile(v3s16 dir)
|
// In mapnode.cpp
|
||||||
{
|
TileSpec getTile(v3s16 dir);
|
||||||
return content_tile(d, dir);
|
|
||||||
}
|
u8 getMineral();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
These serialization functions are used when informing client
|
These serialization functions are used when informing client
|
||||||
|
@ -584,6 +620,15 @@ struct MapNode
|
||||||
param = source[1];
|
param = source[1];
|
||||||
param2 = source[2];
|
param2 = source[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate deprecated stuff
|
||||||
|
MapNode *translate_to = g_content_features[d].translate_to;
|
||||||
|
if(translate_to)
|
||||||
|
{
|
||||||
|
dstream<<"MapNode: WARNING: Translating "<<d<<" to "
|
||||||
|
<<translate_to->d<<std::endl;
|
||||||
|
*this = *translate_to;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -600,6 +645,9 @@ inline v3s16 floatToInt(v3f p)
|
||||||
return p2;
|
return p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The same thing backwards
|
||||||
|
*/
|
||||||
inline v3f intToFloat(v3s16 p)
|
inline v3f intToFloat(v3s16 p)
|
||||||
{
|
{
|
||||||
v3f p2(
|
v3f p2(
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Minetest-c55
|
||||||
|
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINERAL_HEADER
|
||||||
|
#define MINERAL_HEADER
|
||||||
|
|
||||||
|
#include "inventory.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Minerals
|
||||||
|
|
||||||
|
Value is stored in the lowest 5 bits of a MapNode's CPT_MINERAL
|
||||||
|
type param.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MINERAL_NONE 0
|
||||||
|
#define MINERAL_COAL 1
|
||||||
|
#define MINERAL_IRON 2
|
||||||
|
|
||||||
|
inline const char * mineral_block_texture(u8 mineral)
|
||||||
|
{
|
||||||
|
switch(mineral)
|
||||||
|
{
|
||||||
|
case MINERAL_COAL:
|
||||||
|
return "mineral_coal.png";
|
||||||
|
case MINERAL_IRON:
|
||||||
|
return "mineral_iron.png";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CraftItem * getDiggedMineralItem(u8 mineral)
|
||||||
|
{
|
||||||
|
if(mineral == MINERAL_COAL)
|
||||||
|
return new CraftItem("lump_of_coal", 1);
|
||||||
|
else if(mineral == MINERAL_IRON)
|
||||||
|
return new CraftItem("lump_of_iron", 1);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "materials.h"
|
#include "materials.h"
|
||||||
|
#include "mineral.h"
|
||||||
|
|
||||||
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
||||||
|
|
||||||
|
@ -1951,11 +1952,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
core::map<v3s16, MapBlock*> modified_blocks;
|
core::map<v3s16, MapBlock*> modified_blocks;
|
||||||
|
|
||||||
u8 material;
|
u8 material;
|
||||||
|
u8 mineral = MINERAL_NONE;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
MapNode n = m_env.getMap().getNode(p_under);
|
||||||
// Get material at position
|
// Get material at position
|
||||||
material = m_env.getMap().getNode(p_under).d;
|
material = n.d;
|
||||||
// If it's not diggable, do nothing
|
// If it's not diggable, do nothing
|
||||||
if(content_diggable(material) == false)
|
if(content_diggable(material) == false)
|
||||||
{
|
{
|
||||||
|
@ -1963,6 +1966,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Get mineral
|
||||||
|
mineral = n.getMineral();
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
{
|
{
|
||||||
|
@ -1974,8 +1979,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Send to only other clients
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send the removal to all other clients
|
Send the removal to all other clients
|
||||||
*/
|
*/
|
||||||
|
@ -2047,7 +2050,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
/*
|
/*
|
||||||
Add digged item to inventory
|
Add digged item to inventory
|
||||||
*/
|
*/
|
||||||
InventoryItem *item = new MaterialItem(material, 1);
|
|
||||||
|
InventoryItem *item = NULL;
|
||||||
|
|
||||||
|
if(mineral != MINERAL_NONE)
|
||||||
|
item = getDiggedMineralItem(mineral);
|
||||||
|
|
||||||
|
if(item == NULL)
|
||||||
|
item = new MaterialItem(material, 1);
|
||||||
|
|
||||||
player->inventory.addItem("main", item);
|
player->inventory.addItem("main", item);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2134,7 +2145,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
MaterialItem *mitem = (MaterialItem*)item;
|
MaterialItem *mitem = (MaterialItem*)item;
|
||||||
MapNode n;
|
MapNode n;
|
||||||
n.d = mitem->getMaterial();
|
n.d = mitem->getMaterial();
|
||||||
if(content_directional(n.d))
|
if(content_features(n.d).wall_mounted)
|
||||||
n.dir = packDir(p_under - p_over);
|
n.dir = packDir(p_under - p_over);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
@ -2939,7 +2950,7 @@ void Server::SendInventory(u16 peer_id)
|
||||||
if(!found)
|
if(!found)
|
||||||
{
|
{
|
||||||
ItemSpec specs[9];
|
ItemSpec specs[9];
|
||||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COALSTONE);
|
specs[0] = ItemSpec(ITEM_CRAFT, "Coal");
|
||||||
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
|
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||||
if(checkItemCombination(items, specs))
|
if(checkItemCombination(items, specs))
|
||||||
{
|
{
|
||||||
|
@ -3300,6 +3311,11 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
InventoryItem *item = new ToolItem("WPick", 32000);
|
||||||
|
void* r = player->inventory.addItem("main", item);
|
||||||
|
assert(r == NULL);
|
||||||
|
}
|
||||||
/*{
|
/*{
|
||||||
InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
|
InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
|
||||||
void* r = player->inventory.addItem("main", item);
|
void* r = player->inventory.addItem("main", item);
|
||||||
|
|
117
src/tile.cpp
|
@ -18,119 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "porting.h"
|
//#include "porting.h"
|
||||||
// For IrrlichtWrapper
|
// For IrrlichtWrapper
|
||||||
#include "main.h"
|
//#include "main.h"
|
||||||
#include <string>
|
//#include <string>
|
||||||
|
|
||||||
/*
|
// Nothing here
|
||||||
These can either be real paths or generated names of preloaded
|
|
||||||
textures (like "mud.png_sidegrass")
|
|
||||||
*/
|
|
||||||
std::string g_tile_texture_paths[TILES_COUNT];
|
|
||||||
|
|
||||||
const char * tile_texture_path_get(u32 i)
|
|
||||||
{
|
|
||||||
assert(i < TILES_COUNT);
|
|
||||||
|
|
||||||
//return g_tile_texture_paths[i];
|
|
||||||
return g_tile_texture_paths[i].c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A mapping from tiles to materials
|
|
||||||
// Initialized at run-time.
|
|
||||||
video::SMaterial g_tile_materials[TILES_COUNT];
|
|
||||||
|
|
||||||
enum TileTextureModID
|
|
||||||
{
|
|
||||||
TTMID_NONE,
|
|
||||||
TTMID_SIDEGRASS,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileTextureSpec
|
|
||||||
{
|
|
||||||
const char *filename;
|
|
||||||
enum TileTextureModID mod;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Initializes g_tile_texture_paths with paths of textures,
|
|
||||||
generates generated textures and creates the tile material array.
|
|
||||||
*/
|
|
||||||
void init_tile_textures()
|
|
||||||
{
|
|
||||||
TileTextureSpec tile_texture_specs[TILES_COUNT] =
|
|
||||||
{
|
|
||||||
{NULL, TTMID_NONE},
|
|
||||||
{"stone.png", TTMID_NONE},
|
|
||||||
{"water.png", TTMID_NONE},
|
|
||||||
{"grass.png", TTMID_NONE},
|
|
||||||
{"tree.png", TTMID_NONE},
|
|
||||||
{"leaves.png", TTMID_NONE},
|
|
||||||
{"grass_footsteps.png", TTMID_NONE},
|
|
||||||
{"mese.png", TTMID_NONE},
|
|
||||||
{"mud.png", TTMID_NONE},
|
|
||||||
{"tree_top.png", TTMID_NONE},
|
|
||||||
{"mud.png", TTMID_SIDEGRASS},
|
|
||||||
{"cloud.png", TTMID_NONE},
|
|
||||||
{"coalstone.png", TTMID_NONE},
|
|
||||||
{"wood.png", TTMID_NONE},
|
|
||||||
};
|
|
||||||
|
|
||||||
for(s32 i=0; i<TILES_COUNT; i++)
|
|
||||||
{
|
|
||||||
const char *filename = tile_texture_specs[i].filename;
|
|
||||||
enum TileTextureModID mod_id = tile_texture_specs[i].mod;
|
|
||||||
|
|
||||||
if(filename != NULL && std::string("") != filename)
|
|
||||||
{
|
|
||||||
std::string path = porting::getDataPath(filename);
|
|
||||||
std::string mod_postfix = "";
|
|
||||||
if(mod_id == TTMID_SIDEGRASS)
|
|
||||||
{
|
|
||||||
mod_postfix = "_sidegrass";
|
|
||||||
// Generate texture
|
|
||||||
TextureMod *mod = new SideGrassTextureMod();
|
|
||||||
g_irrlicht->getTexture(TextureSpec(path + mod_postfix,
|
|
||||||
path, mod));
|
|
||||||
}
|
|
||||||
g_tile_texture_paths[i] = path + mod_postfix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(s32 i=0; i<TILES_COUNT; i++)
|
|
||||||
{
|
|
||||||
const char *path = tile_texture_path_get(i);
|
|
||||||
|
|
||||||
video::ITexture *t = NULL;
|
|
||||||
|
|
||||||
if(path != NULL && std::string("") != path)
|
|
||||||
{
|
|
||||||
t = g_irrlicht->getTexture(path);
|
|
||||||
assert(t != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_tile_materials[i].Lighting = false;
|
|
||||||
g_tile_materials[i].BackfaceCulling = false;
|
|
||||||
g_tile_materials[i].setFlag(video::EMF_BILINEAR_FILTER, false);
|
|
||||||
g_tile_materials[i].setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
|
|
||||||
//if(i != TILE_WATER)
|
|
||||||
g_tile_materials[i].setFlag(video::EMF_FOG_ENABLE, true);
|
|
||||||
|
|
||||||
//g_tile_materials[i].setFlag(video::EMF_TEXTURE_WRAP, video::ETC_REPEAT);
|
|
||||||
//g_tile_materials[i].setFlag(video::EMF_ANISOTROPIC_FILTER, false);
|
|
||||||
|
|
||||||
g_tile_materials[i].setTexture(0, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_tile_materials[TILE_WATER].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
|
||||||
//g_tile_materials[TILE_WATER].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SMaterial & tile_material_get(u32 i)
|
|
||||||
{
|
|
||||||
assert(i < TILES_COUNT);
|
|
||||||
|
|
||||||
return g_tile_materials[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
92
src/tile.h
|
@ -21,88 +21,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define TILE_HEADER
|
#define TILE_HEADER
|
||||||
|
|
||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
#include "utility.h"
|
//#include "utility.h"
|
||||||
|
#include <string>
|
||||||
// TileID is supposed to be stored in a u16
|
|
||||||
|
|
||||||
enum TileID
|
|
||||||
{
|
|
||||||
TILE_NONE, // Nothing shown
|
|
||||||
TILE_STONE,
|
|
||||||
TILE_WATER,
|
|
||||||
TILE_GRASS,
|
|
||||||
TILE_TREE,
|
|
||||||
TILE_LEAVES,
|
|
||||||
TILE_GRASS_FOOTSTEPS,
|
|
||||||
TILE_MESE,
|
|
||||||
TILE_MUD,
|
|
||||||
TILE_TREE_TOP,
|
|
||||||
TILE_MUD_WITH_GRASS,
|
|
||||||
TILE_CLOUD,
|
|
||||||
TILE_COALSTONE,
|
|
||||||
TILE_WOOD,
|
|
||||||
|
|
||||||
// Count of tile ids
|
|
||||||
TILES_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TileSpecialFeature
|
|
||||||
{
|
|
||||||
TILEFEAT_NONE,
|
|
||||||
TILEFEAT_CRACK,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileCrackParam
|
|
||||||
{
|
|
||||||
bool operator==(TileCrackParam &other)
|
|
||||||
{
|
|
||||||
return progression == other.progression;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 progression;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileSpec
|
struct TileSpec
|
||||||
{
|
{
|
||||||
TileSpec()
|
TileSpec():
|
||||||
|
alpha(255)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TileSpec(const std::string &a_name):
|
||||||
|
name(a_name),
|
||||||
|
alpha(255)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TileSpec(const char *a_name):
|
||||||
|
name(a_name),
|
||||||
|
alpha(255)
|
||||||
{
|
{
|
||||||
id = TILE_NONE;
|
|
||||||
feature = TILEFEAT_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(TileSpec &other)
|
bool operator==(TileSpec &other)
|
||||||
{
|
{
|
||||||
if(id != other.id)
|
return (name == other.name && alpha == other.alpha);
|
||||||
return false;
|
|
||||||
if(feature != other.feature)
|
|
||||||
return false;
|
|
||||||
if(feature == TILEFEAT_NONE)
|
|
||||||
return true;
|
|
||||||
if(feature == TILEFEAT_CRACK)
|
|
||||||
{
|
|
||||||
return param.crack == other.param.crack;
|
|
||||||
}
|
|
||||||
// Invalid feature
|
|
||||||
assert(0);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 id; // Id in g_tile_materials, TILE_NONE=none
|
// path + mods
|
||||||
enum TileSpecialFeature feature;
|
std::string name;
|
||||||
union
|
u8 alpha;
|
||||||
{
|
|
||||||
TileCrackParam crack;
|
|
||||||
} param;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
Functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
void init_tile_textures();
|
|
||||||
|
|
||||||
const char * tile_texture_path_get(u32 i);
|
|
||||||
|
|
||||||
video::SMaterial & tile_material_get(u32 i);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -88,6 +88,41 @@ const v3s16 g_26dirs[26] =
|
||||||
// 26
|
// 26
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const v3s16 g_27dirs[27] =
|
||||||
|
{
|
||||||
|
// +right, +top, +back
|
||||||
|
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
|
||||||
|
// 6
|
||||||
|
v3s16(-1, 1, 0), // top left
|
||||||
|
v3s16( 1, 1, 0), // top right
|
||||||
|
v3s16( 0, 1, 1), // top back
|
||||||
|
v3s16( 0, 1,-1), // top front
|
||||||
|
v3s16(-1, 0, 1), // back left
|
||||||
|
v3s16( 1, 0, 1), // back right
|
||||||
|
v3s16(-1, 0,-1), // front left
|
||||||
|
v3s16( 1, 0,-1), // front right
|
||||||
|
v3s16(-1,-1, 0), // bottom left
|
||||||
|
v3s16( 1,-1, 0), // bottom right
|
||||||
|
v3s16( 0,-1, 1), // bottom back
|
||||||
|
v3s16( 0,-1,-1), // bottom front
|
||||||
|
// 18
|
||||||
|
v3s16(-1, 1, 1), // top back-left
|
||||||
|
v3s16( 1, 1, 1), // top back-right
|
||||||
|
v3s16(-1, 1,-1), // top front-left
|
||||||
|
v3s16( 1, 1,-1), // top front-right
|
||||||
|
v3s16(-1,-1, 1), // bottom back-left
|
||||||
|
v3s16( 1,-1, 1), // bottom back-right
|
||||||
|
v3s16(-1,-1,-1), // bottom front-left
|
||||||
|
v3s16( 1,-1,-1), // bottom front-right
|
||||||
|
// 26
|
||||||
|
v3s16(0,0,0),
|
||||||
|
};
|
||||||
|
|
||||||
static unsigned long next = 1;
|
static unsigned long next = 1;
|
||||||
|
|
||||||
/* RAND_MAX assumed to be 32767 */
|
/* RAND_MAX assumed to be 32767 */
|
||||||
|
|
|
@ -36,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
extern const v3s16 g_26dirs[26];
|
extern const v3s16 g_26dirs[26];
|
||||||
|
|
||||||
|
// 26th is (0,0,0)
|
||||||
|
extern const v3s16 g_27dirs[27];
|
||||||
|
|
||||||
inline void writeU32(u8 *data, u32 i)
|
inline void writeU32(u8 *data, u32 i)
|
||||||
{
|
{
|
||||||
data[0] = ((i>>24)&0xff);
|
data[0] = ((i>>24)&0xff);
|
||||||
|
@ -666,6 +669,14 @@ inline s32 stoi(std::string s)
|
||||||
return atoi(s.c_str());
|
return atoi(s.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float stof(std::string s)
|
||||||
|
{
|
||||||
|
float f;
|
||||||
|
std::istringstream ss(s);
|
||||||
|
ss>>f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string itos(s32 i)
|
inline std::string itos(s32 i)
|
||||||
{
|
{
|
||||||
std::ostringstream o;
|
std::ostringstream o;
|
||||||
|
|
635
src/voxel.cpp
|
@ -110,7 +110,7 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
|
||||||
if(pr <= 9)
|
if(pr <= 9)
|
||||||
c = pr + '0';
|
c = pr + '0';
|
||||||
}
|
}
|
||||||
else if(liquid_replaces_content(m))
|
else if(m == CONTENT_AIR)
|
||||||
{
|
{
|
||||||
c = ' ';
|
c = ' ';
|
||||||
}
|
}
|
||||||
|
@ -653,637 +653,4 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
|
|
||||||
{
|
|
||||||
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED2;
|
|
||||||
|
|
||||||
if(p.Y > highest_y)
|
|
||||||
highest_y = p.Y;
|
|
||||||
|
|
||||||
/*if(recur_count > 1000)
|
|
||||||
throw ProcessingLimitException
|
|
||||||
("getWaterPressure recur_count limit reached");*/
|
|
||||||
|
|
||||||
if(recur_count > 10000)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
recur_count++;
|
|
||||||
|
|
||||||
v3s16 dirs[6] = {
|
|
||||||
v3s16(0,1,0), // top
|
|
||||||
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
|
|
||||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
|
|
||||||
|
|
||||||
s32 i;
|
|
||||||
for(i=0; i<6; i++)
|
|
||||||
{
|
|
||||||
v3s16 p2 = p + dirs[i];
|
|
||||||
u8 f = m_flags[m_area.index(p2)];
|
|
||||||
// Ignore inexistent or checked nodes
|
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED2))
|
|
||||||
continue;
|
|
||||||
MapNode &n = m_data[m_area.index(p2)];
|
|
||||||
// Ignore non-liquid nodes
|
|
||||||
if(content_liquid(n.d) == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int pr;
|
|
||||||
|
|
||||||
// If at ocean surface
|
|
||||||
if(n.pressure == 1 && n.d == CONTENT_WATERSOURCE)
|
|
||||||
//if(n.pressure == 1) // Causes glitches but is fast
|
|
||||||
{
|
|
||||||
pr = 1;
|
|
||||||
}
|
|
||||||
// Otherwise recurse more
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pr = getWaterPressure(p2, highest_y, recur_count);
|
|
||||||
if(pr == -1)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If block is at top, pressure here is one higher
|
|
||||||
if(i == 0)
|
|
||||||
{
|
|
||||||
if(pr < 255)
|
|
||||||
pr++;
|
|
||||||
}
|
|
||||||
// If block is at bottom, pressure here is one lower
|
|
||||||
else if(i == 5)
|
|
||||||
{
|
|
||||||
if(pr > 1)
|
|
||||||
pr--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Node is on the pressure route
|
|
||||||
m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED4;
|
|
||||||
|
|
||||||
// Got pressure
|
|
||||||
return pr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing useful found
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
|
|
||||||
VoxelArea request_area,
|
|
||||||
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++;
|
|
||||||
|
|
||||||
/*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;
|
|
||||||
|
|
||||||
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,-1,0), // bottom
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load neighboring nodes
|
|
||||||
emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
|
|
||||||
|
|
||||||
s32 i;
|
|
||||||
for(i=0; i<6; i++)
|
|
||||||
{
|
|
||||||
v3s16 p2 = p + dirs[i];
|
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p2)];
|
|
||||||
|
|
||||||
// Ignore inexistent and checked nodes
|
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MapNode &n = m_data[m_area.index(p2)];
|
|
||||||
|
|
||||||
/*
|
|
||||||
If material is air:
|
|
||||||
add to active_nodes if there is flow-causing pressure.
|
|
||||||
NOTE: Do not remove anything from there. We cannot know
|
|
||||||
here if some other neighbor of it causes flow.
|
|
||||||
*/
|
|
||||||
if(liquid_replaces_content(n.d))
|
|
||||||
{
|
|
||||||
bool pressure_causes_flow = false;
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
// If block is at bottom
|
|
||||||
else if(i == 5)
|
|
||||||
{
|
|
||||||
pressure_causes_flow = true;
|
|
||||||
}
|
|
||||||
// If block is at side
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
|
|
||||||
if(pr >= 2)
|
|
||||||
pressure_causes_flow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pressure_causes_flow)
|
|
||||||
{
|
|
||||||
active_nodes[p2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore non-liquid nodes
|
|
||||||
if(content_liquid(n.d) == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int pr2 = pr;
|
|
||||||
// If block is at top, pressure there is lower
|
|
||||||
if(i == 0)
|
|
||||||
{
|
|
||||||
if(pr2 > 0)
|
|
||||||
pr2--;
|
|
||||||
}
|
|
||||||
// If block is at bottom, pressure there is higher
|
|
||||||
else if(i == 5)
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
spreadWaterPressure(p2, pr2, request_area, active_nodes, recur_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
bool checked3_is_clear)
|
|
||||||
{
|
|
||||||
TimeTaker timer("updateAreaWaterPressure", &updateareawaterpressure_time);
|
|
||||||
|
|
||||||
emerge(a, 3);
|
|
||||||
|
|
||||||
bool checked2_clear = false;
|
|
||||||
|
|
||||||
if(checked3_is_clear == false)
|
|
||||||
{
|
|
||||||
//clearFlag(VOXELFLAG_CHECKED3);
|
|
||||||
|
|
||||||
clearFlag(VOXELFLAG_CHECKED3 | VOXELFLAG_CHECKED2);
|
|
||||||
checked2_clear = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
|
|
||||||
for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
|
|
||||||
for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
|
|
||||||
{
|
|
||||||
v3s16 p(x,y,z);
|
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
|
||||||
// Ignore inexistent or checked nodes
|
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
|
|
||||||
continue;
|
|
||||||
MapNode &n = m_data[m_area.index(p)];
|
|
||||||
// Ignore non-liquid nodes
|
|
||||||
if(content_liquid(n.d) == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(checked2_clear == false)
|
|
||||||
{
|
|
||||||
clearFlag(VOXELFLAG_CHECKED2);
|
|
||||||
checked2_clear = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
checked2_clear = false;
|
|
||||||
|
|
||||||
s16 highest_y = -32768;
|
|
||||||
int recur_count = 0;
|
|
||||||
int pr = -1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 0-1ms @ recur_count <= 100
|
|
||||||
//TimeTaker timer("getWaterPressure", g_irrlicht);
|
|
||||||
pr = getWaterPressure(p, highest_y, recur_count);
|
|
||||||
}
|
|
||||||
catch(ProcessingLimitException &e)
|
|
||||||
{
|
|
||||||
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pr == -1)
|
|
||||||
{
|
|
||||||
assert(highest_y != -32768);
|
|
||||||
|
|
||||||
pr = highest_y - p.Y + 1;
|
|
||||||
if(pr > 255)
|
|
||||||
pr = 255;
|
|
||||||
|
|
||||||
/*dstream<<"WARNING: Pressure at ("
|
|
||||||
<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
|
||||||
<<" = "<<pr
|
|
||||||
//<<" and highest_y == -32768"
|
|
||||||
<<std::endl;
|
|
||||||
assert(highest_y != -32768);
|
|
||||||
continue;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 0ms
|
|
||||||
//TimeTaker timer("spreadWaterPressure", g_irrlicht);
|
|
||||||
spreadWaterPressure(p, pr, a, active_nodes, 0);
|
|
||||||
}
|
|
||||||
catch(ProcessingLimitException &e)
|
|
||||||
{
|
|
||||||
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VoxelManipulator::flowWater(v3s16 removed_pos,
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
int recursion_depth, bool debugprint,
|
|
||||||
u32 stoptime)
|
|
||||||
{
|
|
||||||
v3s16 dirs[6] = {
|
|
||||||
v3s16(0,1,0), // top
|
|
||||||
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;
|
|
||||||
if(cs < 3)
|
|
||||||
cs++;
|
|
||||||
else
|
|
||||||
cs = 0;
|
|
||||||
s16 s1 = (cs & 1) ? 1 : -1;
|
|
||||||
s16 s2 = (cs & 2) ? 1 : -1;
|
|
||||||
//dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
|
|
||||||
|
|
||||||
{
|
|
||||||
TimeTaker timer1("flowWater pre", &flowwater_pre_time);
|
|
||||||
|
|
||||||
// Load neighboring nodes
|
|
||||||
emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
|
|
||||||
|
|
||||||
// Ignore incorrect removed_pos
|
|
||||||
{
|
|
||||||
u8 f = m_flags[m_area.index(removed_pos)];
|
|
||||||
// Ignore inexistent or checked node
|
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
|
||||||
return false;
|
|
||||||
MapNode &n = m_data[m_area.index(removed_pos)];
|
|
||||||
// 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)];
|
|
||||||
// Inexistent or checked nodes can't move
|
|
||||||
if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
|
|
||||||
continue;
|
|
||||||
MapNode &n = m_data[m_area.index(p)];
|
|
||||||
// Only liquid nodes can move
|
|
||||||
if(content_liquid(n.d) == false)
|
|
||||||
continue;
|
|
||||||
// If block is at top, select it always
|
|
||||||
if(i == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is nothing to move, return
|
|
||||||
if(i==6)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Move water and bubble
|
|
||||||
*/
|
|
||||||
|
|
||||||
u8 m = m_data[m_area.index(p)].d;
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
|
||||||
|
|
||||||
if(m == CONTENT_WATERSOURCE)
|
|
||||||
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)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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)].getLightBanksWithSource();
|
|
||||||
|
|
||||||
m_data[m_area.index(removed_pos)].d = m;
|
|
||||||
m_flags[m_area.index(removed_pos)] = f;
|
|
||||||
|
|
||||||
m_data[m_area.index(removed_pos)].setLightBanks(light);
|
|
||||||
|
|
||||||
// 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 == CONTENT_WATERSOURCE)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
print(dstream, VOXELPRINT_WATERPRESSURE);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Update pressure
|
|
||||||
VoxelArea a;
|
|
||||||
a.addPoint(p - v3s16(1,1,1));
|
|
||||||
a.addPoint(p + v3s16(1,1,1));
|
|
||||||
a.addPoint(removed_pos - v3s16(1,1,1));
|
|
||||||
a.addPoint(removed_pos + v3s16(1,1,1));
|
|
||||||
updateAreaWaterPressure(a, active_nodes);
|
|
||||||
|
|
||||||
/*if(debugprint)
|
|
||||||
{
|
|
||||||
dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
|
|
||||||
print(dstream, VOXELPRINT_WATERPRESSURE);
|
|
||||||
//std::cin.get();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(debugprint)
|
|
||||||
{
|
|
||||||
dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
|
|
||||||
print(dstream, VOXELPRINT_WATERPRESSURE);
|
|
||||||
//std::cin.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}//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, stoptime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stoptime != 0)
|
|
||||||
{
|
|
||||||
u32 timenow = getTimeMs();
|
|
||||||
// Well, it is a bit hard to guess because we don't know the
|
|
||||||
// start time...
|
|
||||||
bool overflow = timenow < stoptime - 100000;
|
|
||||||
if(timenow >= stoptime || overflow)
|
|
||||||
{
|
|
||||||
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--)
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
u8 f = m_flags[m_area.index(p)];
|
|
||||||
// Water can't move to inexistent nodes
|
|
||||||
if(f & VOXELFLAG_INEXISTENT)
|
|
||||||
continue;
|
|
||||||
MapNode &n = m_data[m_area.index(p)];
|
|
||||||
// Water can only move to air
|
|
||||||
if(liquid_replaces_content(n.d) == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Flow water to node
|
|
||||||
bool moved =
|
|
||||||
flowWater(p, active_nodes, recursion_depth,
|
|
||||||
debugprint, stoptime);
|
|
||||||
/*flowWater(p, active_nodes, recursion_depth,
|
|
||||||
debugprint, counter, counterlimit);*/
|
|
||||||
|
|
||||||
if(moved)
|
|
||||||
{
|
|
||||||
// Search again from all neighbors
|
|
||||||
goto find_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VoxelManipulator::flowWater(
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
int recursion_depth, bool debugprint,
|
|
||||||
u32 timelimit)
|
|
||||||
{
|
|
||||||
addarea_time = 0;
|
|
||||||
emerge_time = 0;
|
|
||||||
emerge_load_time = 0;
|
|
||||||
clearflag_time = 0;
|
|
||||||
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_irrlicht);
|
|
||||||
|
|
||||||
//dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
u32 stoptime = 0;
|
|
||||||
stoptime = getTimeMs() + 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)myrand() % (s32)active_nodes.size();
|
|
||||||
|
|
||||||
// Flow water to active nodes
|
|
||||||
for(;;)
|
|
||||||
//for(s32 h=0; h<1; h++)
|
|
||||||
{
|
|
||||||
if(active_nodes.size() == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
handled_count++;
|
|
||||||
|
|
||||||
// Clear check flags
|
|
||||||
clearFlag(VOXELFLAG_CHECKED);
|
|
||||||
|
|
||||||
//dstream<<"Selecting a new active_node"<<std::endl;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Take first one
|
|
||||||
core::map<v3s16, u8>::Node
|
|
||||||
*n = active_nodes.getIterator().getNode();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
|
|
||||||
core::map<v3s16, u8>::Iterator
|
|
||||||
i = active_nodes.getIterator().getNode();
|
|
||||||
for(s32 j=0; j<k; j++)
|
|
||||||
{
|
|
||||||
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, stoptime);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(ProcessingLimitException &e)
|
|
||||||
{
|
|
||||||
//dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*v3s16 e = m_area.getExtent();
|
|
||||||
s32 v = m_area.getVolume();
|
|
||||||
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
|
|
||||||
<<", emerge_time: "<<emerge_time
|
|
||||||
<<", emerge_load_time: "<<emerge_load_time
|
|
||||||
<<", clearflag_time: "<<clearflag_time
|
|
||||||
<<", flowwater_pre_time: "<<flowwater_pre_time
|
|
||||||
<<", updateareawaterpressure_time: "<<updateareawaterpressure_time
|
|
||||||
<<std::endl;*/
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//END
|
//END
|
||||||
|
|
56
src/voxel.h
|
@ -411,62 +411,6 @@ public:
|
||||||
void spreadLight(enum LightBank bank,
|
void spreadLight(enum LightBank bank,
|
||||||
core::map<v3s16, bool> & from_nodes);
|
core::map<v3s16, bool> & from_nodes);
|
||||||
|
|
||||||
#if 0
|
|
||||||
// VOXELFLAG_CHECKED2s must usually be cleared before calling
|
|
||||||
// -1: dead end, 0-255: pressure
|
|
||||||
// highest_y: Highest found water y is stored here.
|
|
||||||
// Must be initialized to -32768
|
|
||||||
int getWaterPressure(v3s16 p, s16 &highest_y, int recur_count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
VOXELFLAG_CHECKED3s must usually be cleared before calling.
|
|
||||||
|
|
||||||
active_nodes: surface-touching air nodes with flow-causing
|
|
||||||
pressure. set-like dummy map container.
|
|
||||||
|
|
||||||
Spreads pressure pr at node p to request_area or as far as
|
|
||||||
there is invalid pressure.
|
|
||||||
*/
|
|
||||||
void spreadWaterPressure(v3s16 p, int pr,
|
|
||||||
VoxelArea request_area,
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
int recur_count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
VOXELFLAG_CHECKED3s must usually be cleared before calling.
|
|
||||||
*/
|
|
||||||
void updateAreaWaterPressure(VoxelArea a,
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
bool checked3_is_clear=false);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns true if moved something
|
|
||||||
*/
|
|
||||||
bool flowWater(v3s16 removed_pos,
|
|
||||||
core::map<v3s16, u8> &active_nodes,
|
|
||||||
int recursion_depth=0,
|
|
||||||
bool debugprint=false,
|
|
||||||
u32 stoptime=0
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
To flow some water, call this with the target node in
|
|
||||||
active_nodes
|
|
||||||
TODO: Make the active_nodes map to contain some vectors
|
|
||||||
that are properly sorted according to water flow order.
|
|
||||||
The current order makes water flow strangely if the
|
|
||||||
first one is always taken.
|
|
||||||
No, active_nodes should preserve the order stuff is
|
|
||||||
added to it, in addition to adhering the water flow
|
|
||||||
order.
|
|
||||||
*/
|
|
||||||
void flowWater(core::map<v3s16, u8> &active_nodes,
|
|
||||||
int recursion_depth=0,
|
|
||||||
bool debugprint=false,
|
|
||||||
u32 timelimit=50
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Virtual functions
|
Virtual functions
|
||||||
*/
|
*/
|
||||||
|
|