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 |
BIN
data/lump_of_coal.png
Normal file
After Width: | Height: | Size: 933 B |
BIN
data/lump_of_iron.png
Normal file
After Width: | Height: | Size: 936 B |
BIN
data/mineral_coal.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
data/mineral_iron.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
data/sand.png
Normal file
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_ceiling.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/crack.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_mesepick.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/
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
||||
<Tool
|
||||
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"
|
||||
IgnoreDefaultLibraryNames="libcmtd.lib"
|
||||
IgnoreDefaultLibraryNames="libcmtd.dll"
|
||||
GenerateDebugInformation="false"
|
||||
LinkTimeCodeGeneration="1"
|
||||
/>
|
||||
|
@ -1273,6 +1273,7 @@ void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
|
||||
0: start digging
|
||||
1: place block
|
||||
2: stop digging (all parameters ignored)
|
||||
3: digging completed
|
||||
*/
|
||||
u8 datasize = 2 + 1 + 6 + 6 + 2;
|
||||
SharedBuffer<u8> data(datasize);
|
||||
|
35
src/client.h
@ -197,6 +197,40 @@ public:
|
||||
|
||||
//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)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
@ -215,6 +249,7 @@ public:
|
||||
if(changed)
|
||||
m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
|
||||
}
|
||||
#endif
|
||||
|
||||
float getAvgRtt()
|
||||
{
|
||||
|
@ -122,12 +122,6 @@ public:
|
||||
#ifndef SERVER
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
@ -257,15 +251,18 @@ public:
|
||||
video::ITexture * getImage()
|
||||
{
|
||||
std::string basename;
|
||||
|
||||
if(m_subname == "Stick")
|
||||
basename = porting::getDataPath("stick.png").c_str();
|
||||
// Default to cloud texture
|
||||
basename = porting::getDataPath("stick.png");
|
||||
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
|
||||
basename = tile_texture_path_get(TILE_CLOUD);
|
||||
basename = porting::getDataPath("cloud.png[[mod:crack3");
|
||||
|
||||
// Get such a texture
|
||||
return g_irrlicht->getTexture(basename);
|
||||
//return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
|
||||
}
|
||||
#endif
|
||||
std::string getText()
|
||||
@ -340,7 +337,8 @@ public:
|
||||
basename = porting::getDataPath("tool_mesepick.png").c_str();
|
||||
// Default to cloud texture
|
||||
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
|
||||
@ -350,6 +348,12 @@ public:
|
||||
u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
|
||||
|
||||
// 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;
|
||||
os<<basename<<"-toolprogress-"<<toolprogress;
|
||||
std::string finalname = os.str();
|
||||
@ -358,7 +362,7 @@ public:
|
||||
|
||||
// Get such a texture
|
||||
TextureMod *mod = new ProgressBarTextureMod(value_f);
|
||||
return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
|
||||
return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));*/
|
||||
}
|
||||
#endif
|
||||
std::string getText()
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "irrlichtwrapper.h"
|
||||
#include "constants.h"
|
||||
#include "string.h"
|
||||
#include "strfnd.h"
|
||||
|
||||
IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
|
||||
{
|
||||
@ -15,13 +17,13 @@ void IrrlichtWrapper::Run()
|
||||
*/
|
||||
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();
|
||||
|
||||
dstream<<"got texture request with key.name="
|
||||
<<request.key.name<<std::endl;
|
||||
dstream<<"got texture request with key="
|
||||
<<request.key<<std::endl;
|
||||
|
||||
GetResult<TextureSpec, video::ITexture*, u8, u8>
|
||||
GetResult<std::string, video::ITexture*, u8, u8>
|
||||
result;
|
||||
result.key = request.key;
|
||||
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)
|
||||
return t;
|
||||
|
||||
if(get_current_thread_id() == m_main_thread)
|
||||
{
|
||||
dstream<<"Getting texture directly: name="
|
||||
<<spec.name<<std::endl;
|
||||
dstream<<"Getting texture directly: spec="
|
||||
<<spec<<std::endl;
|
||||
|
||||
t = getTextureDirect(spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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
|
||||
m_get_texture_queue.add(spec, 0, 0, &result_queue);
|
||||
|
||||
dstream<<"Waiting for texture from main thread: "
|
||||
<<spec.name<<std::endl;
|
||||
<<spec<<std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
// Wait result for a second
|
||||
GetResult<TextureSpec, video::ITexture*, u8, u8>
|
||||
GetResult<std::string, video::ITexture*, u8, u8>
|
||||
result = result_queue.pop_front(1000);
|
||||
|
||||
// Check that at least something worked OK
|
||||
assert(result.key.name == spec.name);
|
||||
assert(result.key == spec);
|
||||
|
||||
t = result.item;
|
||||
}
|
||||
@ -74,44 +79,63 @@ video::ITexture* IrrlichtWrapper::getTexture(TextureSpec spec)
|
||||
}
|
||||
|
||||
// Add to cache and return
|
||||
m_texturecache.set(spec.name, t);
|
||||
m_texturecache.set(spec, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
video::ITexture* IrrlichtWrapper::getTexture(const std::string &path)
|
||||
{
|
||||
return getTexture(TextureSpec(path, path, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
Non-thread-safe functions
|
||||
*/
|
||||
|
||||
video::ITexture* IrrlichtWrapper::getTextureDirect(TextureSpec spec)
|
||||
{
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
/*
|
||||
Texture modifier functions
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
video::ITexture * CrackTextureMod::make(video::ITexture *original,
|
||||
// blitted_name = eg. "mineral_coal.png"
|
||||
video::ITexture * make_blitname(const std::string &blitted_name,
|
||||
video::ITexture *original,
|
||||
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
|
||||
core::dimension2d<u32> dim(16, 16);
|
||||
// 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());
|
||||
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
|
||||
|
||||
crackimage->copyToWithAlpha(baseimage, v2s32(0,0),
|
||||
@ -175,9 +169,13 @@ video::ITexture * CrackTextureMod::make(video::ITexture *original,
|
||||
return newtexture;
|
||||
}
|
||||
|
||||
video::ITexture * SideGrassTextureMod::make(video::ITexture *original,
|
||||
#if 0
|
||||
video::ITexture * make_sidegrass(video::ITexture *original,
|
||||
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 grass to in the base image
|
||||
@ -208,10 +206,14 @@ video::ITexture * SideGrassTextureMod::make(video::ITexture *original,
|
||||
|
||||
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)
|
||||
{
|
||||
if(original == NULL)
|
||||
return NULL;
|
||||
|
||||
core::position2d<s32> pos_base(0, 0);
|
||||
core::dimension2d<u32> dim = original->getOriginalSize();
|
||||
|
||||
@ -251,3 +253,166 @@ video::ITexture * ProgressBarTextureMod::make(video::ITexture *original,
|
||||
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;
|
||||
}
|
||||
|
||||
video::ITexture* get(std::string name)
|
||||
video::ITexture* get(const std::string &name)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
@ -74,86 +74,6 @@ private:
|
||||
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
|
||||
background worker threads.
|
||||
@ -183,14 +103,17 @@ public:
|
||||
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:
|
||||
/*
|
||||
Non-thread-safe variants of stuff, for internal use
|
||||
*/
|
||||
video::ITexture* getTextureDirect(TextureSpec spec);
|
||||
video::ITexture* getTextureDirect(const std::string &spec);
|
||||
|
||||
/*
|
||||
Members
|
||||
@ -203,7 +126,7 @@ private:
|
||||
|
||||
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
|
||||
|
139
src/map.cpp
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "utility.h"
|
||||
#include "voxel.h"
|
||||
#include "porting.h"
|
||||
#include "mineral.h"
|
||||
|
||||
/*
|
||||
Map
|
||||
@ -627,9 +628,8 @@ void Map::updateLighting(enum LightBank bank,
|
||||
//TimeTaker timer("updateLighting");
|
||||
|
||||
// For debugging
|
||||
bool debug=true;
|
||||
|
||||
u32 count_was = modified_blocks.size();
|
||||
//bool debug=true;
|
||||
//u32 count_was = modified_blocks.size();
|
||||
|
||||
core::map<v3s16, bool> light_sources;
|
||||
|
||||
@ -1835,9 +1835,18 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
|
||||
randfactor = 0.5;
|
||||
}*/
|
||||
|
||||
if(myrand()%3 < 2)
|
||||
{
|
||||
baseheight = 10;
|
||||
randmax = 30;
|
||||
randfactor = 0.7;
|
||||
}
|
||||
else
|
||||
{
|
||||
baseheight = 0;
|
||||
randmax = 15;
|
||||
randfactor = 0.63;
|
||||
}
|
||||
|
||||
list_baseheight->addPoint(p, Attribute(baseheight));
|
||||
list_randmax->addPoint(p, Attribute(randmax));
|
||||
@ -2699,7 +2708,7 @@ continue_generating:
|
||||
+ued*(y0*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_dungeons = true;
|
||||
@ -2755,17 +2764,11 @@ continue_generating:
|
||||
MapNode n;
|
||||
n.d = CONTENT_MESE;
|
||||
|
||||
//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++)
|
||||
for(u16 i=0; i<27; i++)
|
||||
{
|
||||
//if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
|
||||
if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
|
||||
if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
|
||||
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;
|
||||
n.d = CONTENT_COALSTONE;
|
||||
n.d = CONTENT_STONE;
|
||||
n.param = MINERAL_COAL;
|
||||
|
||||
//dstream<<"Adding coalstone"<<std::endl;
|
||||
|
||||
//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++)
|
||||
for(u16 i=0; i<27; i++)
|
||||
{
|
||||
//if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
|
||||
if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
|
||||
if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
|
||||
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;*/
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z-2);
|
||||
if(is_ground_content(sector->getNode(p2).d)
|
||||
&& !is_mineral(sector->getNode(p2).d))
|
||||
//if(is_ground_content(sector->getNode(p2).d))
|
||||
if(content_features(sector->getNode(p2).d).walkable)
|
||||
sector->setNode(p2, n);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z-1);
|
||||
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, n2);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z+0);
|
||||
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, n2);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z+1);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -4027,8 +4053,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
<<", 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
|
||||
*/
|
||||
@ -4053,14 +4081,29 @@ v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod, bool *changed)
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
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(0,0,0), // this
|
||||
v3s16(0,0,1), // back
|
||||
@ -4082,11 +4125,23 @@ v3s16 ClientMap::clearTempMod(v3s16 p, bool *changed)
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
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)
|
||||
@ -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
|
||||
run on background.
|
||||
*/
|
||||
|
17
src/map.h
@ -204,10 +204,13 @@ public:
|
||||
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.
|
||||
*/
|
||||
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
||||
|
||||
// Update meshes that touch the node
|
||||
//void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -483,10 +486,16 @@ public:
|
||||
/*
|
||||
Methods for setting temporary modifications to nodes for
|
||||
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);
|
||||
v3s16 clearTempMod(v3s16 p, bool *changed=NULL);
|
||||
bool setTempMod(v3s16 p, NodeMod mod,
|
||||
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
|
||||
//void clearTempMods();
|
||||
|
||||
|
@ -264,12 +264,10 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
|
||||
//u8 li = decode_light(light);
|
||||
u8 li = light;
|
||||
|
||||
u8 alpha = 255;
|
||||
|
||||
u8 alpha = tile.alpha;
|
||||
/*u8 alpha = 255;
|
||||
if(tile.id == TILE_WATER)
|
||||
{
|
||||
alpha = WATER_ALPHA;
|
||||
}
|
||||
alpha = WATER_ALPHA;*/
|
||||
|
||||
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 spec;
|
||||
|
||||
/*//DEBUG
|
||||
{
|
||||
spec.id = TILE_STONE;
|
||||
return spec;
|
||||
}*/
|
||||
|
||||
spec.feature = TILEFEAT_NONE;
|
||||
//spec.id = TILE_STONE;
|
||||
spec.id = mn.getTile(face_dir);
|
||||
spec = mn.getTile(face_dir);
|
||||
|
||||
/*
|
||||
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();
|
||||
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)
|
||||
{
|
||||
spec.feature = TILEFEAT_CRACK;
|
||||
spec.param.crack.progression = mod.param;
|
||||
std::ostringstream os;
|
||||
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};
|
||||
|
||||
if(f.tile.feature == TILEFEAT_NONE)
|
||||
{
|
||||
collector.append(tile_material_get(f.tile.id), f.vertices, 4,
|
||||
indices, 6);
|
||||
}
|
||||
else if(f.tile.feature == TILEFEAT_CRACK)
|
||||
{
|
||||
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);
|
||||
video::ITexture *texture = g_irrlicht->getTexture(f.tile.name);
|
||||
video::SMaterial material;
|
||||
material.Lighting = false;
|
||||
material.BackfaceCulling = false;
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material.setTexture(0, texture);
|
||||
if(f.tile.alpha != 255)
|
||||
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
|
||||
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;
|
||||
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)
|
||||
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 "porting.h"
|
||||
#include <string>
|
||||
#include "mineral.h"
|
||||
|
||||
/*
|
||||
Face directions:
|
||||
0: up
|
||||
1: down
|
||||
2: right
|
||||
3: left
|
||||
4: back
|
||||
5: front
|
||||
*/
|
||||
u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] =
|
||||
ContentFeatures::~ContentFeatures()
|
||||
{
|
||||
{TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE},
|
||||
{TILE_GRASS,TILE_MUD,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS},
|
||||
//{TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
|
||||
{TILE_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},
|
||||
};
|
||||
if(translate_to)
|
||||
delete translate_to;
|
||||
}
|
||||
|
||||
std::string g_content_inventory_texture_strings[USEFUL_CONTENT_COUNT];
|
||||
// Pointers to c_str()s of the above
|
||||
struct ContentFeatures g_content_features[256];
|
||||
|
||||
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_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()
|
||||
{
|
||||
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_strings[i].c_str();
|
||||
g_content_inventory_texture_paths[i] =
|
||||
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 "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
|
||||
|
||||
/*
|
||||
@ -69,33 +79,143 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define CONTENT_MESE 7
|
||||
#define CONTENT_MUD 8
|
||||
#define CONTENT_WATERSOURCE 9
|
||||
// Pretty much useless, clouds won't be drawn this way
|
||||
#define CONTENT_CLOUD 10
|
||||
#define CONTENT_COALSTONE 11
|
||||
#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];
|
||||
// Initializes g_content_inventory_texture_paths
|
||||
void init_content_inventory_texture_paths();
|
||||
|
||||
/*
|
||||
If true, the material allows light propagation and brightness is stored
|
||||
in param.
|
||||
NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
*/
|
||||
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.
|
||||
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)
|
||||
{
|
||||
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
|
||||
1: Transparent
|
||||
2: Opaque
|
||||
NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
*/
|
||||
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)
|
||||
return 0;
|
||||
if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
|
||||
return 1;
|
||||
return 2;
|
||||
return 2;*/
|
||||
}
|
||||
|
||||
// Objects collide with walkable contents
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return (m == CONTENT_WATERSOURCE);
|
||||
return g_content_features[m].liquid_type == LIQUID_SOURCE;
|
||||
//return (m == CONTENT_WATERSOURCE);
|
||||
}
|
||||
|
||||
// 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
|
||||
// NOTE: Don't use, use "content_features(m).whatever" instead
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
follows the main heightmap
|
||||
*/
|
||||
inline bool is_ground_content(u8 m)
|
||||
/*inline bool is_ground_content(u8 m)
|
||||
{
|
||||
return (
|
||||
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);
|
||||
}
|
||||
return g_content_features[m].is_ground_content;
|
||||
}*/
|
||||
|
||||
/*
|
||||
Nodes make a face if contents differ and solidness differs.
|
||||
@ -275,87 +383,15 @@ inline v3s16 unpackDir(u8 b)
|
||||
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
|
||||
{
|
||||
LIGHTBANK_DAY,
|
||||
LIGHTBANK_NIGHT
|
||||
};
|
||||
|
||||
#if 0
|
||||
#define DIR_PX 1 //X+
|
||||
#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
|
||||
/*
|
||||
This is the stuff what the whole world consists of.
|
||||
*/
|
||||
|
||||
struct MapNode
|
||||
{
|
||||
@ -512,10 +548,10 @@ struct MapNode
|
||||
assert(0);
|
||||
}
|
||||
|
||||
u16 getTile(v3s16 dir)
|
||||
{
|
||||
return content_tile(d, dir);
|
||||
}
|
||||
// In mapnode.cpp
|
||||
TileSpec getTile(v3s16 dir);
|
||||
|
||||
u8 getMineral();
|
||||
|
||||
/*
|
||||
These serialization functions are used when informing client
|
||||
@ -584,6 +620,15 @@ struct MapNode
|
||||
param = source[1];
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
The same thing backwards
|
||||
*/
|
||||
inline v3f intToFloat(v3s16 p)
|
||||
{
|
||||
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 "voxel.h"
|
||||
#include "materials.h"
|
||||
#include "mineral.h"
|
||||
|
||||
#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;
|
||||
|
||||
u8 material;
|
||||
u8 mineral = MINERAL_NONE;
|
||||
|
||||
try
|
||||
{
|
||||
MapNode n = m_env.getMap().getNode(p_under);
|
||||
// Get material at position
|
||||
material = m_env.getMap().getNode(p_under).d;
|
||||
material = n.d;
|
||||
// If it's not diggable, do nothing
|
||||
if(content_diggable(material) == false)
|
||||
{
|
||||
@ -1963,6 +1966,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
// Get mineral
|
||||
mineral = n.getMineral();
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
@ -1974,8 +1979,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Send to only 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
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -2134,7 +2145,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
MapNode n;
|
||||
n.d = mitem->getMaterial();
|
||||
if(content_directional(n.d))
|
||||
if(content_features(n.d).wall_mounted)
|
||||
n.dir = packDir(p_under - p_over);
|
||||
|
||||
#if 1
|
||||
@ -2939,7 +2950,7 @@ void Server::SendInventory(u16 peer_id)
|
||||
if(!found)
|
||||
{
|
||||
ItemSpec specs[9];
|
||||
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COALSTONE);
|
||||
specs[0] = ItemSpec(ITEM_CRAFT, "Coal");
|
||||
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
|
||||
if(checkItemCombination(items, specs))
|
||||
{
|
||||
@ -3300,6 +3311,11 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
InventoryItem *item = new ToolItem("WPick", 32000);
|
||||
void* r = player->inventory.addItem("main", item);
|
||||
assert(r == NULL);
|
||||
}
|
||||
/*{
|
||||
InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
|
||||
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 "porting.h"
|
||||
//#include "porting.h"
|
||||
// For IrrlichtWrapper
|
||||
#include "main.h"
|
||||
#include <string>
|
||||
//#include "main.h"
|
||||
//#include <string>
|
||||
|
||||
/*
|
||||
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];
|
||||
}
|
||||
// Nothing here
|
||||
|
||||
|
92
src/tile.h
@ -21,88 +21,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define TILE_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "utility.h"
|
||||
|
||||
// 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;
|
||||
};
|
||||
//#include "utility.h"
|
||||
#include <string>
|
||||
|
||||
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)
|
||||
{
|
||||
if(id != other.id)
|
||||
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;
|
||||
return (name == other.name && alpha == other.alpha);
|
||||
}
|
||||
|
||||
u16 id; // Id in g_tile_materials, TILE_NONE=none
|
||||
enum TileSpecialFeature feature;
|
||||
union
|
||||
{
|
||||
TileCrackParam crack;
|
||||
} param;
|
||||
// path + mods
|
||||
std::string name;
|
||||
u8 alpha;
|
||||
};
|
||||
|
||||
/*
|
||||
Functions
|
||||
*/
|
||||
|
||||
void init_tile_textures();
|
||||
|
||||
const char * tile_texture_path_get(u32 i);
|
||||
|
||||
video::SMaterial & tile_material_get(u32 i);
|
||||
|
||||
#endif
|
||||
|
@ -88,6 +88,41 @@ const v3s16 g_26dirs[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;
|
||||
|
||||
/* 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];
|
||||
|
||||
// 26th is (0,0,0)
|
||||
extern const v3s16 g_27dirs[27];
|
||||
|
||||
inline void writeU32(u8 *data, u32 i)
|
||||
{
|
||||
data[0] = ((i>>24)&0xff);
|
||||
@ -666,6 +669,14 @@ inline s32 stoi(std::string s)
|
||||
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)
|
||||
{
|
||||
std::ostringstream o;
|
||||
|
635
src/voxel.cpp
@ -110,7 +110,7 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
|
||||
if(pr <= 9)
|
||||
c = pr + '0';
|
||||
}
|
||||
else if(liquid_replaces_content(m))
|
||||
else if(m == CONTENT_AIR)
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
@ -653,637 +653,4 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
|
||||
}
|
||||
#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
|
||||
|
56
src/voxel.h
@ -411,62 +411,6 @@ public:
|
||||
void spreadLight(enum LightBank bank,
|
||||
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
|
||||
*/
|
||||
|