Reworked texture, material, mineral and whatever handling

This commit is contained in:
Perttu Ahola 2011-01-26 00:41:06 +02:00
parent 035345f13d
commit 9f882bf74d
27 changed files with 952 additions and 1324 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
data/lump_of_coal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

BIN
data/lump_of_iron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

BIN
data/mineral_coal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
data/mineral_iron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
data/sand.png Normal file

Binary file not shown.

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="&quot;C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib&quot;;&quot;..\irrlicht\irrlicht-1.7.1\lib\Win32-visualstudio&quot;;..\zlib125dll\dll32" AdditionalLibraryDirectories="&quot;C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib&quot;;&quot;..\irrlicht\irrlicht-1.7.1\lib\Win32-visualstudio&quot;;..\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);

@ -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

@ -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;
}*/ }*/
if(myrand()%3 < 2)
{
baseheight = 10;
randmax = 30;
randfactor = 0.7;
}
else
{
baseheight = 0; baseheight = 0;
randmax = 15; randmax = 15;
randfactor = 0.63; 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)
}
v3s16 ClientMap::clearTempMod(v3s16 p, bool *changed)
{ {
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;
}
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.
*/ */

@ -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,36 +668,19 @@ 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);
u16 progression = f.tile.param.crack.progression;
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); material.setTexture(0, texture);
if(f.tile.alpha != 255)
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
collector.append(material, f.vertices, 4, indices, 6); 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;

@ -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();
} }
} }

@ -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(

60
src/mineral.h Normal file

@ -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);

@ -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];
}

@ -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;

@ -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

@ -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
*/ */