Now texture handling is fast. Also now players are saved on disk.

This commit is contained in:
Perttu Ahola 2011-01-28 01:38:16 +02:00
parent bd100c5483
commit 64b5975732
23 changed files with 1167 additions and 656 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -271,6 +271,10 @@
RelativePath=".\src\materials.cpp" RelativePath=".\src\materials.cpp"
> >
</File> </File>
<File
RelativePath=".\src\mineral.cpp"
>
</File>
<File <File
RelativePath=".\src\player.cpp" RelativePath=".\src\player.cpp"
> >

@ -38,18 +38,12 @@ configure_file(
"${PROJECT_BINARY_DIR}/cmake_config.h" "${PROJECT_BINARY_DIR}/cmake_config.h"
) )
set(minetest_SRCS set(common_SRCS
guiMainMenu.cpp mineral.cpp
porting.cpp porting.cpp
guiMessageMenu.cpp
materials.cpp materials.cpp
guiTextInputMenu.cpp
guiInventoryMenu.cpp
irrlichtwrapper.cpp
guiPauseMenu.cpp
defaultsettings.cpp defaultsettings.cpp
mapnode.cpp mapnode.cpp
tile.cpp
voxel.cpp voxel.cpp
mapblockobject.cpp mapblockobject.cpp
inventory.cpp inventory.cpp
@ -59,7 +53,6 @@ set(minetest_SRCS
filesys.cpp filesys.cpp
connection.cpp connection.cpp
environment.cpp environment.cpp
client.cpp
server.cpp server.cpp
socket.cpp socket.cpp
mapblock.cpp mapblock.cpp
@ -68,34 +61,24 @@ set(minetest_SRCS
map.cpp map.cpp
player.cpp player.cpp
utility.cpp utility.cpp
main.cpp
test.cpp test.cpp
) )
set(minetest_SRCS
${common_SRCS}
guiMainMenu.cpp
guiMessageMenu.cpp
guiTextInputMenu.cpp
guiInventoryMenu.cpp
guiPauseMenu.cpp
irrlichtwrapper.cpp
client.cpp
main.cpp
)
set(minetestserver_SRCS set(minetestserver_SRCS
porting.cpp ${common_SRCS}
materials.cpp
defaultsettings.cpp
mapnode.cpp
voxel.cpp
mapblockobject.cpp
inventory.cpp
debug.cpp
serialization.cpp
light.cpp
filesys.cpp
connection.cpp
environment.cpp
server.cpp
socket.cpp
mapblock.cpp
mapsector.cpp
heightmap.cpp
map.cpp
player.cpp
utility.cpp
servermain.cpp servermain.cpp
test.cpp
) )
include_directories( include_directories(

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "environment.h" #include "environment.h"
#include "filesys.h"
Environment::Environment(Map *map, std::ostream &dout): Environment::Environment(Map *map, std::ostream &dout):
m_dout(dout) m_dout(dout)
@ -192,6 +193,7 @@ void Environment::addPlayer(Player *player)
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
/* /*
Check that only one local player exists and peer_ids are unique. Check that only one local player exists and peer_ids are unique.
Also check that names are unique.
Exception: there can be multiple players with peer_id=0 Exception: there can be multiple players with peer_id=0
*/ */
#ifndef SERVER #ifndef SERVER
@ -201,8 +203,12 @@ void Environment::addPlayer(Player *player)
*/ */
assert(!(player->isLocal() == true && getLocalPlayer() != NULL)); assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
#endif #endif
// If peer id is non-zero, it has to be unique.
if(player->peer_id != 0) if(player->peer_id != 0)
assert(getPlayer(player->peer_id) == NULL); assert(getPlayer(player->peer_id) == NULL);
// Name has to be unique.
assert(getPlayer(player->getName()) == NULL);
// Add.
m_players.push_back(player); m_players.push_back(player);
} }
@ -300,6 +306,181 @@ void Environment::printPlayers(std::ostream &o)
} }
} }
void Environment::serializePlayers(const std::string &savedir)
{
std::string players_path = savedir + "/players";
fs::CreateDir(players_path);
core::map<Player*, bool> saved_players;
std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++)
{
if(player_files[i].dir)
continue;
// Full path to this file
std::string path = players_path + "/" + player_files[i].name;
dstream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
ServerRemotePlayer testplayer;
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
if(is.good() == false)
{
dstream<<"Failed to read "<<path<<std::endl;
continue;
}
testplayer.deSerialize(is);
}
dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
// Search for the player
std::string playername = testplayer.getName();
Player *player = getPlayer(playername.c_str());
if(player == NULL)
{
dstream<<"Didn't find matching player, ignoring file."<<std::endl;
continue;
}
dstream<<"Found matching player, overwriting."<<std::endl;
// OK, found. Save player there.
{
// Open file and serialize
std::ofstream os(path.c_str(), std::ios_base::binary);
if(os.good() == false)
{
dstream<<"Failed to overwrite "<<path<<std::endl;
continue;
}
player->serialize(os);
saved_players.insert(player, true);
}
}
for(core::list<Player*>::Iterator i = m_players.begin();
i != m_players.end(); i++)
{
Player *player = *i;
if(saved_players.find(player) != NULL)
{
dstream<<"Player "<<player->getName()
<<" was already saved."<<std::endl;
continue;
}
std::string playername = player->getName();
// Don't save unnamed player
if(playername == "")
{
dstream<<"Not saving unnamed player."<<std::endl;
continue;
}
/*
Find a sane filename
*/
if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
playername = "player";
std::string path = players_path + "/" + playername;
bool found = false;
for(u32 i=0; i<1000; i++)
{
if(fs::PathExists(path) == false)
{
found = true;
break;
}
path = players_path + "/" + playername + itos(i);
}
if(found == false)
{
dstream<<"Didn't find free file for player"<<std::endl;
continue;
}
{
dstream<<"Saving player "<<player->getName()<<" to "
<<path<<std::endl;
// Open file and serialize
std::ofstream os(path.c_str(), std::ios_base::binary);
if(os.good() == false)
{
dstream<<"Failed to overwrite "<<path<<std::endl;
continue;
}
player->serialize(os);
saved_players.insert(player, true);
}
}
}
void Environment::deSerializePlayers(const std::string &savedir)
{
std::string players_path = savedir + "/players";
core::map<Player*, bool> saved_players;
std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++)
{
if(player_files[i].dir)
continue;
// Full path to this file
std::string path = players_path + "/" + player_files[i].name;
dstream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
ServerRemotePlayer testplayer;
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
if(is.good() == false)
{
dstream<<"Failed to read "<<path<<std::endl;
continue;
}
testplayer.deSerialize(is);
}
dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
// Search for the player
std::string playername = testplayer.getName();
Player *player = getPlayer(playername.c_str());
bool newplayer = false;
if(player == NULL)
{
dstream<<"Is a new player"<<std::endl;
player = new ServerRemotePlayer();
newplayer = true;
}
// Load player
{
dstream<<"Reading player "<<testplayer.getName()<<" from "
<<path<<std::endl;
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
if(is.good() == false)
{
dstream<<"Failed to read "<<path<<std::endl;
continue;
}
player->deSerialize(is);
}
if(newplayer)
addPlayer(player);
}
}
#ifndef SERVER #ifndef SERVER
void Environment::updateMeshes(v3s16 blockpos) void Environment::updateMeshes(v3s16 blockpos)
{ {

@ -63,6 +63,10 @@ public:
core::list<Player*> getPlayers(); core::list<Player*> getPlayers();
core::list<Player*> getPlayers(bool ignore_disconnected); core::list<Player*> getPlayers(bool ignore_disconnected);
void printPlayers(std::ostream &o); void printPlayers(std::ostream &o);
void serializePlayers(const std::string &savedir);
// This loads players as ServerRemotePlayers
void deSerializePlayers(const std::string &savedir);
#ifndef SERVER #ifndef SERVER
void updateMeshes(v3s16 blockpos); void updateMeshes(v3s16 blockpos);

@ -217,7 +217,7 @@ void InventoryList::serialize(std::ostream &os)
os<<"\n"; os<<"\n";
} }
os<<"end\n"; os<<"EndInventoryList\n";
} }
void InventoryList::deSerialize(std::istream &is) void InventoryList::deSerialize(std::istream &is)
@ -238,7 +238,7 @@ void InventoryList::deSerialize(std::istream &is)
std::string name; std::string name;
std::getline(iss, name, ' '); std::getline(iss, name, ' ');
if(name == "end") if(name == "EndInventoryList")
{ {
break; break;
} }
@ -497,7 +497,7 @@ void Inventory::serialize(std::ostream &os)
list->serialize(os); list->serialize(os);
} }
os<<"end\n"; os<<"EndInventory\n";
} }
void Inventory::deSerialize(std::istream &is) void Inventory::deSerialize(std::istream &is)
@ -514,7 +514,7 @@ void Inventory::deSerialize(std::istream &is)
std::string name; std::string name;
std::getline(iss, name, ' '); std::getline(iss, name, ' ');
if(name == "end") if(name == "EndInventory")
{ {
break; break;
} }

@ -122,10 +122,12 @@ public:
#ifndef SERVER #ifndef SERVER
video::ITexture * getImage() video::ITexture * getImage()
{ {
if(m_content >= USEFUL_CONTENT_COUNT) /*if(m_content >= USEFUL_CONTENT_COUNT)
return NULL; return NULL;
return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]); return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]);*/
return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
} }
#endif #endif
std::string getText() std::string getText()
@ -250,19 +252,19 @@ public:
#ifndef SERVER #ifndef SERVER
video::ITexture * getImage() video::ITexture * getImage()
{ {
std::string basename; std::string name;
if(m_subname == "Stick") if(m_subname == "Stick")
basename = porting::getDataPath("stick.png"); name = "stick.png";
else if(m_subname == "lump_of_coal") else if(m_subname == "lump_of_coal")
basename = porting::getDataPath("lump_of_coal.png"); name = "lump_of_coal.png";
else if(m_subname == "lump_of_iron") else if(m_subname == "lump_of_iron")
basename = porting::getDataPath("lump_of_iron.png"); name = "lump_of_iron.png";
else else
basename = porting::getDataPath("cloud.png[[mod:crack3"); name = "cloud.png";
// Get such a texture // Get such a texture
return g_irrlicht->getTexture(basename); return g_irrlicht->getTexture(name);
} }
#endif #endif
std::string getText() std::string getText()
@ -330,28 +332,35 @@ public:
{ {
std::string basename; std::string basename;
if(m_toolname == "WPick") if(m_toolname == "WPick")
basename = porting::getDataPath("tool_wpick.png").c_str(); basename = "tool_wpick.png";
else if(m_toolname == "STPick") else if(m_toolname == "STPick")
basename = porting::getDataPath("tool_stpick.png").c_str(); basename = "tool_stpick.png";
else if(m_toolname == "MesePick") else if(m_toolname == "MesePick")
basename = porting::getDataPath("tool_mesepick.png").c_str(); basename = "tool_mesepick.png";
// Default to cloud texture
else else
basename = porting::getDataPath("cloud.png").c_str(); basename = "cloud.png";
//basename = tile_texture_path_get(TILE_CLOUD);
/* /*
Calculate some progress value with sane amount of Calculate a progress value with sane amount of
maximum states maximum states
*/ */
u32 maxprogress = 30; u32 maxprogress = 30;
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 float value_f = (float)toolprogress / (float)maxprogress;
std::ostringstream os;
os<<"[progressbar"<<value_f;
TextureSpec spec;
spec.addTid(g_irrlicht->getTextureId(basename));
spec.addTid(g_irrlicht->getTextureId(os.str()));
return g_irrlicht->getTexture(spec);
/*// Make texture name for the new texture with a progress bar
float value_f = (float)toolprogress / (float)maxprogress; float value_f = (float)toolprogress / (float)maxprogress;
std::ostringstream os; std::ostringstream os;
os<<basename<<"[[mod:progressbar"<<value_f; os<<basename<<"[[mod:progressbar"<<value_f;
return g_irrlicht->getTexture(os.str()); return g_irrlicht->getTexture(os.str());*/
/*// Make texture name for the new texture with a progress bar /*// Make texture name for the new texture with a progress bar
std::ostringstream os; std::ostringstream os;

@ -17,13 +17,15 @@ void IrrlichtWrapper::Run()
*/ */
if(m_get_texture_queue.size() > 0) if(m_get_texture_queue.size() > 0)
{ {
GetRequest<std::string, video::ITexture*, u8, u8> GetRequest<TextureSpec, video::ITexture*, u8, u8>
request = m_get_texture_queue.pop(); request = m_get_texture_queue.pop();
dstream<<"got texture request with key=" dstream<<"got texture request with"
<<request.key<<std::endl; <<" key.tids[0]="<<request.key.tids[0]
<<" [1]="<<request.key.tids[1]
<<std::endl;
GetResult<std::string, video::ITexture*, u8, u8> GetResult<TextureSpec, video::ITexture*, u8, u8>
result; result;
result.key = request.key; result.key = request.key;
result.callers = request.callers; result.callers = request.callers;
@ -33,9 +35,29 @@ void IrrlichtWrapper::Run()
} }
} }
video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec) textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
{ {
if(spec == "") u32 id = m_namecache.getId(name);
return id;
}
std::string IrrlichtWrapper::getTextureName(textureid_t id)
{
std::string name("");
m_namecache.getValue(id, name);
// In case it was found, return the name; otherwise return an empty name.
return name;
}
video::ITexture* IrrlichtWrapper::getTexture(const std::string &name)
{
TextureSpec spec(getTextureId(name));
return getTexture(spec);
}
video::ITexture* IrrlichtWrapper::getTexture(const TextureSpec &spec)
{
if(spec.empty())
return NULL; return NULL;
video::ITexture *t = m_texturecache.get(spec); video::ITexture *t = m_texturecache.get(spec);
@ -44,26 +66,26 @@ video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
if(get_current_thread_id() == m_main_thread) if(get_current_thread_id() == m_main_thread)
{ {
dstream<<"Getting texture directly: spec=" dstream<<"Getting texture directly: spec.tids[0]="
<<spec<<std::endl; <<spec.tids[0]<<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<std::string, video::ITexture*, u8, u8> result_queue; ResultQueue<TextureSpec, 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.tids[0]="
<<spec<<std::endl; <<spec.tids[0]<<std::endl;
try try
{ {
// Wait result for a second // Wait result for a second
GetResult<std::string, video::ITexture*, u8, u8> GetResult<TextureSpec, 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
@ -83,144 +105,177 @@ video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
return t; return t;
} }
/* // Draw a progress bar on the image
Non-thread-safe functions void make_progressbar(float value, video::IImage *image);
*/
/* /*
Texture modifier functions Texture fetcher/maker function, called always from the main thread
*/ */
// blitted_name = eg. "mineral_coal.png" video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
video::ITexture * make_blitname(const std::string &blitted_name,
video::ITexture *original,
const char *newname, video::IVideoDriver* driver)
{ {
if(original == NULL) // This would result in NULL image
if(spec.empty())
return NULL; return NULL;
// Size of the base image // Don't generate existing stuff
core::dimension2d<u32> dim(16, 16); video::ITexture *t = m_texturecache.get(spec);
// Position to copy the blitted to in the base image if(t != NULL)
core::position2d<s32> pos_base(0, 0); {
// Position to copy the blitted from in the blitted image dstream<<"WARNING: Existing stuff requested from "
core::position2d<s32> pos_other(0, 0); "getTextureDirect()"<<std::endl;
return t;
}
video::IVideoDriver* driver = m_device->getVideoDriver();
video::IImage *baseimage = driver->createImage(original, pos_base, dim); /*
assert(baseimage); An image will be built from files and then converted into a texture.
*/
video::IImage *baseimg = NULL;
video::IImage *blittedimage = driver->createImageFromFile(porting::getDataPath(blitted_name.c_str()).c_str()); /*
assert(blittedimage); Irrlicht requires a name for every texture, with which it
will be stored internally in irrlicht.
*/
std::string texture_name;
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
textureid_t tid = spec.tids[i];
if(tid == 0)
continue;
std::string name = getTextureName(tid);
// Add something to the name so that it is a unique identifier.
texture_name += "[";
texture_name += name;
texture_name += "]";
if(name[0] != '[')
{
// A normal texture; load it from a file
std::string path = porting::getDataPath(name.c_str());
dstream<<"getTextureDirect(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
dstream<<"WARNING: Could not load image \""<<name
<<"\" from path \""<<path<<"\""
<<" while building texture"<<std::endl;
continue;
}
// If base image is NULL, load as base.
if(baseimg == NULL)
{
dstream<<"Setting "<<name<<" as base"<<std::endl;
/*
Copy it this way to get an alpha channel.
Otherwise images with alpha cannot be blitted on
images that don't have alpha in the original file.
*/
// This is a deprecated method
//baseimg = driver->createImage(video::ECF_A8R8G8B8, image);
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
image->copyTo(baseimg);
image->drop();
//baseimg = image;
}
// Else blit on base.
else
{
dstream<<"Blitting "<<name<<" on base"<<std::endl;
// Size of the copied area
core::dimension2d<u32> dim = image->getDimension();
//core::dimension2d<u32> dim(16,16);
// Position to copy the blitted to in the base image
core::position2d<s32> pos_to(0,0);
// Position to copy the blitted from in the blitted image
core::position2d<s32> pos_from(0,0);
// Blit
image->copyToWithAlpha(baseimg, pos_to,
core::rect<s32>(pos_from, dim),
video::SColor(255,255,255,255),
NULL);
// Drop image
image->drop();
}
}
else
{
// A special texture modification
dstream<<"getTextureDirect(): generating \""<<name<<"\""
<<std::endl;
if(name.substr(0,6) == "[crack")
{
u16 progression = stoi(name.substr(6));
// Size of the base image
core::dimension2d<u32> dim(16, 16);
// Size of the crack image
//core::dimension2d<u32> dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
// Position to copy the crack to in the base image
core::position2d<s32> pos_base(0, 0);
// Position to copy the crack from in the crack image
core::position2d<s32> pos_other(0, 16 * progression);
video::IImage *crackimage = driver->createImageFromFile(
porting::getDataPath("crack.png").c_str());
crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
core::rect<s32>(pos_other, dim),
video::SColor(255,255,255,255),
NULL);
crackimage->drop();
}
else if(name.substr(0,12) == "[progressbar")
{
float value = stof(name.substr(12));
make_progressbar(value, baseimg);
}
else
{
dstream<<"WARNING: getTextureDirect(): Invalid "
" texture: \""<<name<<"\""<<std::endl;
}
}
}
// If no resulting image, return NULL
if(baseimg == NULL)
{
dstream<<"getTextureDirect(): baseimg is NULL (attempted to"
" create texture \""<<texture_name<<"\""<<std::endl;
return NULL;
}
// Then copy the right part of blittedimage to baseimage /*// DEBUG: Paint some pixels
video::SColor c(255,255,0,0);
blittedimage->copyToWithAlpha(baseimage, v2s32(0,0), baseimg->setPixel(1,1, c);
core::rect<s32>(pos_other, dim), baseimg->setPixel(1,14, c);
video::SColor(255,255,255,255), baseimg->setPixel(14,1, c);
NULL); baseimg->setPixel(14,14, c);*/
blittedimage->drop();
// Create texture from resulting image // Create texture from resulting image
t = driver->addTexture(texture_name.c_str(), baseimg);
baseimg->drop();
video::ITexture *newtexture = driver->addTexture(newname, baseimage); dstream<<"getTextureDirect(): created texture \""<<texture_name
<<"\""<<std::endl;
baseimage->drop(); return t;
return newtexture;
} }
video::ITexture * make_crack(u16 progression, video::ITexture *original, void make_progressbar(float value, video::IImage *image)
const char *newname, video::IVideoDriver* driver)
{ {
if(original == NULL) if(image == NULL)
return NULL; return;
// Size of the base image core::dimension2d<u32> size = image->getDimension();
core::dimension2d<u32> dim(16, 16);
// Size of the crack image
//core::dimension2d<u32> dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
// Position to copy the crack to in the base image
core::position2d<s32> pos_base(0, 0);
// Position to copy the crack from in the crack image
core::position2d<s32> pos_other(0, 16 * progression);
video::IImage *baseimage = driver->createImage(original, pos_base, dim);
assert(baseimage);
video::IImage *crackimage = driver->createImageFromFile(porting::getDataPath("crack.png").c_str());
assert(crackimage);
// Then copy the right part of crackimage to baseimage
crackimage->copyToWithAlpha(baseimage, v2s32(0,0),
core::rect<s32>(pos_other, dim),
video::SColor(255,255,255,255),
NULL);
crackimage->drop();
// Create texture from resulting image
video::ITexture *newtexture = driver->addTexture(newname, baseimage);
baseimage->drop();
return newtexture;
}
#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
core::position2d<s32> pos_base(0, 0);
// Position to copy the grass from in the grass image
core::position2d<s32> pos_other(0, 0);
video::IImage *baseimage = driver->createImage(original, pos_base, dim);
assert(baseimage);
video::IImage *grassimage = driver->createImageFromFile(porting::getDataPath("grass_side.png").c_str());
assert(grassimage);
// Then copy the right part of grassimage to baseimage
grassimage->copyToWithAlpha(baseimage, v2s32(0,0),
core::rect<s32>(pos_other, dim),
video::SColor(255,255,255,255),
NULL);
grassimage->drop();
// Create texture from resulting image
video::ITexture *newtexture = driver->addTexture(newname, baseimage);
baseimage->drop();
return newtexture;
}
#endif
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();
video::IImage *baseimage = driver->createImage(original, pos_base, dim);
assert(baseimage);
core::dimension2d<u32> size = baseimage->getDimension();
u32 barheight = 1; u32 barheight = 1;
u32 barpad_x = 1; u32 barpad_x = 1;
@ -242,177 +297,9 @@ video::ITexture * make_progressbar(float value, video::ITexture *original,
u32 x = x0 + barpos.X; u32 x = x0 + barpos.X;
for(u32 y=barpos.Y; y<barpos.Y+barheight; y++) for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
{ {
baseimage->setPixel(x,y, *c); image->setPixel(x,y, *c);
} }
} }
video::ITexture *newtexture = driver->addTexture(newname, baseimage);
baseimage->drop();
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
} }

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "debug.h" #include "debug.h"
#include "utility.h" #include "utility.h"
#include "texture.h"
#include <jmutex.h> #include <jmutex.h>
#include <jmutexautolock.h> #include <jmutexautolock.h>
@ -36,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
threads, because texture pointers have to be handled in threads, because texture pointers have to be handled in
background threads. background threads.
*/ */
#if 0
class TextureCache class TextureCache
{ {
public: public:
@ -73,12 +74,55 @@ private:
core::map<std::string, video::ITexture*> m_textures; core::map<std::string, video::ITexture*> m_textures;
JMutex m_mutex; JMutex m_mutex;
}; };
#endif
/*
A thread-safe texture pointer cache
*/
class TextureCache
{
public:
TextureCache()
{
m_mutex.Init();
assert(m_mutex.IsInitialized());
}
void set(const TextureSpec &spec, video::ITexture *texture)
{
if(texture == NULL)
return;
JMutexAutoLock lock(m_mutex);
m_textures[spec] = texture;
}
video::ITexture* get(const TextureSpec &spec)
{
JMutexAutoLock lock(m_mutex);
core::map<TextureSpec, video::ITexture*>::Node *n;
n = m_textures.find(spec);
if(n != NULL)
return n->getValue();
return NULL;
}
private:
core::map<TextureSpec, video::ITexture*> m_textures;
JMutex m_mutex;
};
/* /*
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.
Queues tasks to be done in the main thread. Queues tasks to be done in the main thread.
Also caches texture specification strings to ids and textures.
*/ */
class IrrlichtWrapper class IrrlichtWrapper
@ -103,30 +147,55 @@ public:
return m_device->getTimer()->getRealTime(); return m_device->getTimer()->getRealTime();
} }
/* /*
Path can contain stuff like Format of a texture name:
"/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3" "stone.png" (filename in image data directory)
"[crack1" (a name starting with "[" is a special feature)
"[progress1.0" (a name starting with "[" is a special feature)
*/ */
video::ITexture* getTexture(const std::string &spec); /*
Loads texture defined by "name" and assigns a texture id to it.
If texture has to be generated, generates it.
If the texture has already been loaded, returns existing id.
*/
textureid_t getTextureId(const std::string &name);
// The reverse of the above
std::string getTextureName(textureid_t id);
// Gets a texture based on a filename
video::ITexture* getTexture(const std::string &name);
// Gets a texture based on a TextureSpec (a textureid_t is fine too)
video::ITexture* getTexture(const TextureSpec &spec);
private: private:
/* /*
Non-thread-safe variants of stuff, for internal use Non-thread-safe variants of stuff, for internal use
*/ */
video::ITexture* getTextureDirect(const std::string &spec);
// DEPRECATED NO-OP
//video::ITexture* getTextureDirect(const std::string &spec);
// Constructs a texture according to spec
video::ITexture* getTextureDirect(const TextureSpec &spec);
/* /*
Members Members
*/ */
// The id of the thread that can (and has to) use irrlicht directly
threadid_t m_main_thread; threadid_t m_main_thread;
// The irrlicht device
JMutex m_device_mutex; JMutex m_device_mutex;
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
TextureCache m_texturecache;
RequestQueue<std::string, video::ITexture*, u8, u8> m_get_texture_queue; // Queued texture fetches (to be processed by the main thread)
RequestQueue<TextureSpec, video::ITexture*, u8, u8> m_get_texture_queue;
// Cache of textures by spec
TextureCache m_texturecache;
// A mapping from texture id to string spec
MutexedIdGenerator<std::string> m_namecache;
}; };
#endif #endif

@ -104,8 +104,11 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
Gaming ideas: Gaming ideas:
------------- -------------
- Aim for something like controlling a single dwarf in Dwarf Fortress. - Aim for something like controlling a single dwarf in Dwarf Fortress
- The player could go faster by a crafting a boat, or riding an animal
- Random NPC traders. what else?
Documentation: Documentation:
-------------- --------------
@ -165,6 +168,20 @@ TODO: Make fetching sector's blocks more efficient when rendering
TODO: Flowing water animation TODO: Flowing water animation
FIXME: The new texture stuff is slow on wine
- A basic grassy ground block takes 20-40ms
- A bit more complicated block can take 270ms
- On linux, a similar one doesn't take long at all (14ms)
- It is NOT a bad std::string implementation of MSVC.
- Can take up to 200ms? Is it when loading textures or always?
- Updating excess amount of meshes when making footprints is too
slow. It has to be fixed.
-> implement Map::updateNodeMeshes()
The fix:
* Optimize TileSpec to only contain a reference number that
is fast to compare, which refers to a cached string, or
* Make TextureSpec for using instead of strings
Configuration: Configuration:
-------------- --------------
@ -281,18 +298,6 @@ TODO: Flowing water to actually contain flow direction information
TODO: Remove duplicate lighting implementation from Map (leave TODO: Remove duplicate lighting implementation from Map (leave
VoxelManipulator, which is faster) VoxelManipulator, which is faster)
FIXME: The new texture stuff is slow on wine
- A basic grassy ground block takes 20-40ms
- A bit more complicated block can take 270ms
- On linux, a similar one doesn't take long at all (14ms)
- Is it a bad std::string implementation of MSVC?
- Can take up to 200ms? Is it when loading textures or always?
- Updating excess amount of meshes when making footprints is too
slow. It has to be fixed.
-> implement Map::updateNodeMeshes()
TODO: Optimize TileSpec to only contain a reference number that
is fast to compare, which refers to a cached string
Doing now: Doing now:
---------- ----------
@ -360,6 +365,7 @@ Doing now:
#include "filesys.h" #include "filesys.h"
#include "config.h" #include "config.h"
#include "guiMainMenu.h" #include "guiMainMenu.h"
#include "mineral.h"
IrrlichtWrapper *g_irrlicht; IrrlichtWrapper *g_irrlicht;
@ -1445,7 +1451,6 @@ int main(int argc, char *argv[])
// C-style stuff initialization // C-style stuff initialization
initializeMaterialProperties(); initializeMaterialProperties();
init_mapnode();
// Debug handler // Debug handler
BEGIN_DEBUG_EXCEPTION_HANDLER BEGIN_DEBUG_EXCEPTION_HANDLER
@ -1683,7 +1688,8 @@ int main(int argc, char *argv[])
*/ */
init_content_inventory_texture_paths(); init_content_inventory_texture_paths();
//init_tile_textures(); init_mapnode(g_irrlicht);
init_mineral(g_irrlicht);
/* /*
GUI stuff GUI stuff
@ -2378,7 +2384,7 @@ int main(int argc, char *argv[])
bool nodefound = false; bool nodefound = false;
v3s16 nodepos; v3s16 nodepos;
v3s16 neighbourpos; v3s16 neighbourpos;
core::aabbox3d<f32> nodefacebox; core::aabbox3d<f32> nodehilightbox;
f32 mindistance = BS * 1001; f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position); v3s16 pos_i = floatToInt(player_position);
@ -2470,7 +2476,7 @@ int main(int argc, char *argv[])
nodepos = np; nodepos = np;
neighbourpos = np; neighbourpos = np;
mindistance = distance; mindistance = distance;
nodefacebox = box; nodehilightbox = box;
} }
} }
} }
@ -2513,7 +2519,16 @@ int main(int argc, char *argv[])
nodepos = np; nodepos = np;
neighbourpos = np + dirs[i]; neighbourpos = np + dirs[i];
mindistance = distance; mindistance = distance;
nodefacebox = facebox;
//nodehilightbox = facebox;
const float d = 0.502;
core::aabbox3d<f32> nodebox
(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
v3f nodepos_f = intToFloat(nodepos);
nodebox.MinEdge += nodepos_f;
nodebox.MaxEdge += nodepos_f;
nodehilightbox = nodebox;
} }
} // if distance < mindistance } // if distance < mindistance
} // for dirs } // for dirs
@ -2531,15 +2546,7 @@ int main(int argc, char *argv[])
// Visualize selection // Visualize selection
const float d = 0.502; hilightboxes.push_back(nodehilightbox);
core::aabbox3d<f32> nodebox(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
v3f nodepos_f = intToFloat(nodepos);
//v3f nodepos_f(nodepos.X*BS, nodepos.Y*BS, nodepos.Z*BS);
nodebox.MinEdge += nodepos_f;
nodebox.MaxEdge += nodepos_f;
hilightboxes.push_back(nodebox);
//hilightboxes.push_back(nodefacebox);
// Handle digging // Handle digging

@ -263,6 +263,7 @@ 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 li = 255; //DEBUG
u8 alpha = tile.alpha; u8 alpha = tile.alpha;
/*u8 alpha = 255; /*u8 alpha = 255;
@ -309,15 +310,16 @@ 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 = content_tile(mod.param, face_dir);
MapNode mn2(mod.param); MapNode mn2(mod.param);
spec = mn2.getTile(face_dir); spec = mn2.getTile(face_dir);
} }
if(mod.type == NODEMOD_CRACK) if(mod.type == NODEMOD_CRACK)
{ {
std::ostringstream os; std::ostringstream os;
os<<"[[mod:crack"<<mod.param; os<<"[crack"<<mod.param;
spec.name += os.str();
textureid_t tid = g_irrlicht->getTextureId(os.str());
spec.spec.addTid(tid);
} }
} }
@ -601,7 +603,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
*/ */
{ {
TimeTaker timer2("updateMesh() collect"); // 4-23ms for MAP_BLOCKSIZE=16
//TimeTaker timer2("updateMesh() collect");
// Lock this, as m_temp_mods will be used directly // Lock this, as m_temp_mods will be used directly
JMutexAutoLock lock(m_temp_mods_mutex); JMutexAutoLock lock(m_temp_mods_mutex);
@ -667,22 +670,25 @@ void MapBlock::updateMesh(u32 daynight_ratio)
// avg 0ms (100ms spikes when loading textures the first time) // avg 0ms (100ms spikes when loading textures the first time)
//TimeTaker timer2("updateMesh() mesh building"); //TimeTaker timer2("updateMesh() mesh building");
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);
for(u32 i=0; i<fastfaces_new.size(); i++) for(u32 i=0; i<fastfaces_new.size(); i++)
{ {
FastFace &f = fastfaces_new[i]; FastFace &f = fastfaces_new[i];
const u16 indices[] = {0,1,2,2,3,0}; const u16 indices[] = {0,1,2,2,3,0};
video::ITexture *texture = g_irrlicht->getTexture(f.tile.name); video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
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); material.setTexture(0, texture);
if(f.tile.alpha != 255) if(f.tile.alpha != 255)
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
else
material.MaterialType = video::EMT_SOLID;
collector.append(material, f.vertices, 4, indices, 6); collector.append(material, f.vertices, 4, indices, 6);
} }
@ -691,13 +697,22 @@ void MapBlock::updateMesh(u32 daynight_ratio)
/* /*
Add special graphics: Add special graphics:
- torches - torches
- flowing water
TODO: Optimize by using same meshbuffer for same textures
*/ */
// 0ms // 0ms
//TimeTaker timer2("updateMesh() adding special stuff"); //TimeTaker timer2("updateMesh() adding special stuff");
// Flowing water material
video::SMaterial material_w1;
material_w1.setFlag(video::EMF_LIGHTING, false);
material_w1.setFlag(video::EMF_BACK_FACE_CULLING, false);
material_w1.setFlag(video::EMF_BILINEAR_FILTER, false);
material_w1.setFlag(video::EMF_FOG_ENABLE, true);
material_w1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
material_w1.setTexture(0,
g_irrlicht->getTexture("water.png"));
for(s16 z=0; z<MAP_BLOCKSIZE; z++) for(s16 z=0; z<MAP_BLOCKSIZE; z++)
for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 y=0; y<MAP_BLOCKSIZE; y++)
for(s16 x=0; x<MAP_BLOCKSIZE; x++) for(s16 x=0; x<MAP_BLOCKSIZE; x++)
@ -751,17 +766,17 @@ void MapBlock::updateMesh(u32 daynight_ratio)
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
if(dir == v3s16(0,-1,0)) if(dir == v3s16(0,-1,0))
material.setTexture(0, material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str())); g_irrlicht->getTexture("torch_on_floor.png"));
else if(dir == v3s16(0,1,0)) else if(dir == v3s16(0,1,0))
material.setTexture(0, material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str())); g_irrlicht->getTexture("torch_on_ceiling.png"));
// For backwards compatibility // For backwards compatibility
else if(dir == v3s16(0,0,0)) else if(dir == v3s16(0,0,0))
material.setTexture(0, material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str())); g_irrlicht->getTexture("torch_on_floor.png"));
else else
material.setTexture(0, material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str())); g_irrlicht->getTexture("torch.png"));
u16 indices[] = {0,1,2,2,3,0}; u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector // Add to mesh collector
@ -947,19 +962,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
vertices[j].Pos += intToFloat(p + getPosRelative()); vertices[j].Pos += intToFloat(p + getPosRelative());
} }
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
u16 indices[] = {0,1,2,2,3,0}; u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector // Add to mesh collector
collector.append(material, vertices, 4, indices, 6); collector.append(material_w1, vertices, 4, indices, 6);
} }
/* /*
@ -984,19 +989,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
vertices[i].Pos += intToFloat(p + getPosRelative()); vertices[i].Pos += intToFloat(p + getPosRelative());
} }
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
material.setTexture(0,
g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
u16 indices[] = {0,1,2,2,3,0}; u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector // Add to mesh collector
collector.append(material, vertices, 4, indices, 6); collector.append(material_w1, vertices, 4, indices, 6);
} }
} }
} }

@ -31,80 +31,85 @@ ContentFeatures::~ContentFeatures()
struct ContentFeatures g_content_features[256]; struct ContentFeatures g_content_features[256];
void init_mapnode() ContentFeatures & content_features(u8 i)
{
return g_content_features[i];
}
void init_mapnode(IrrlichtWrapper *irrlicht)
{ {
u8 i; u8 i;
ContentFeatures *f = NULL; ContentFeatures *f = NULL;
i = CONTENT_STONE; i = CONTENT_STONE;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("stone.png"); f->setAllTextures(irrlicht->getTextureId("stone.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_GRASS; i = CONTENT_GRASS;
f = &g_content_features[i]; f = &g_content_features[i];
//f->setAllTextures("mud.png[[mod:sidegrass"); f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
f->setAllTextures("mud.png[[mod:blitname:grass_side.png"); irrlicht->getTextureId("grass_side.png")));
f->setTexture(0, "grass.png"); f->setTexture(0, irrlicht->getTextureId("grass.png"));
f->setTexture(1, "mud.png"); f->setTexture(1, irrlicht->getTextureId("mud.png"));
f->setInventoryImage("grass.png"); f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_GRASS_FOOTSTEPS; i = CONTENT_GRASS_FOOTSTEPS;
f = &g_content_features[i]; f = &g_content_features[i];
//f->setAllTextures("mud.png[[mod:sidegrass"); f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
f->setAllTextures("mud.png[[mod:blitname:grass_side.png"); irrlicht->getTextureId("grass_side.png")));
f->setTexture(0, "grass_footsteps.png"); f->setTexture(0, irrlicht->getTextureId("grass_footsteps.png"));
f->setTexture(1, "mud.png"); f->setTexture(1, irrlicht->getTextureId("mud.png"));
f->setInventoryImage("grass_footsteps.png"); f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_MUD; i = CONTENT_MUD;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("mud.png"); f->setAllTextures(irrlicht->getTextureId("mud.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_SAND; i = CONTENT_SAND;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("mud.png"); f->setAllTextures(irrlicht->getTextureId("mud.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_TREE; i = CONTENT_TREE;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("tree.png"); f->setAllTextures(irrlicht->getTextureId("tree.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_LEAVES; i = CONTENT_LEAVES;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("leaves.png"); f->setAllTextures(irrlicht->getTextureId("leaves.png"));
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_COALSTONE; i = CONTENT_COALSTONE;
f = &g_content_features[i]; f = &g_content_features[i];
f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL); f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
/*f->setAllTextures("coalstone.png"); /*f->setAllTextures(irrlicht->getTextureId("coalstone.png"));
f->is_ground_content = true;*/ f->is_ground_content = true;*/
i = CONTENT_WOOD; i = CONTENT_WOOD;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("wood.png"); f->setAllTextures(irrlicht->getTextureId("wood.png"));
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_MESE; i = CONTENT_MESE;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("mese.png"); f->setAllTextures(irrlicht->getTextureId("mese.png"));
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_CLOUD; i = CONTENT_CLOUD;
f = &g_content_features[i]; f = &g_content_features[i];
f->setAllTextures("cloud.png"); f->setAllTextures(irrlicht->getTextureId("cloud.png"));
f->is_ground_content = true; f->is_ground_content = true;
i = CONTENT_AIR; i = CONTENT_AIR;
@ -120,7 +125,7 @@ void init_mapnode()
i = CONTENT_WATER; i = CONTENT_WATER;
f = &g_content_features[i]; f = &g_content_features[i];
f->setInventoryImage("water.png"); f->setInventoryTexture(irrlicht->getTextureId("water.png"));
f->param_type = CPT_LIGHT; f->param_type = CPT_LIGHT;
f->light_propagates = true; f->light_propagates = true;
f->solidness = 0; // Drawn separately, makes no faces f->solidness = 0; // Drawn separately, makes no faces
@ -132,8 +137,8 @@ void init_mapnode()
i = CONTENT_WATERSOURCE; i = CONTENT_WATERSOURCE;
f = &g_content_features[i]; f = &g_content_features[i];
f->setTexture(0, "water.png", WATER_ALPHA); f->setTexture(0, irrlicht->getTextureId("water.png"), WATER_ALPHA);
f->setInventoryImage("water.png"); f->setInventoryTexture(irrlicht->getTextureId("water.png"));
f->param_type = CPT_LIGHT; f->param_type = CPT_LIGHT;
f->light_propagates = true; f->light_propagates = true;
f->solidness = 1; f->solidness = 1;
@ -145,7 +150,7 @@ void init_mapnode()
i = CONTENT_TORCH; i = CONTENT_TORCH;
f = &g_content_features[i]; f = &g_content_features[i];
f->setInventoryImage("torch_on_floor.png"); f->setInventoryTexture(irrlicht->getTextureId("torch_on_floor.png"));
f->param_type = CPT_LIGHT; f->param_type = CPT_LIGHT;
f->light_propagates = true; f->light_propagates = true;
f->solidness = 0; // drawn separately, makes no faces f->solidness = 0; // drawn separately, makes no faces
@ -184,12 +189,10 @@ TileSpec MapNode::getTile(v3s16 dir)
if(content_features(d).param_type == CPT_MINERAL) if(content_features(d).param_type == CPT_MINERAL)
{ {
u8 mineral = param & 0x1f; u8 mineral = param & 0x1f;
const char *ts = mineral_block_texture(mineral); // Add mineral block texture
if(ts[0] != 0) textureid_t tid = mineral_block_texture(mineral);
{ if(tid != 0)
spec.name += "[[mod:blitname:"; spec.spec.addTid(tid);
spec.name += ts;
}
} }
return spec; return spec;
@ -206,14 +209,15 @@ u8 MapNode::getMineral()
} }
// Pointers to c_str()s g_content_features[i].inventory_image_path // 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};
void init_content_inventory_texture_paths() void init_content_inventory_texture_paths()
{ {
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++) dstream<<"DEPRECATED "<<__FUNCTION_NAME<<std::endl;
/*for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
{ {
g_content_inventory_texture_paths[i] = g_content_inventory_texture_paths[i] =
g_content_features[i].inventory_image_path.c_str(); g_content_features[i].inventory_image_path.c_str();
} }*/
} }

@ -27,11 +27,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "exceptions.h" #include "exceptions.h"
#include "serialization.h" #include "serialization.h"
#include "tile.h" #include "tile.h"
#include "irrlichtwrapper.h"
// Initializes all kind of stuff in here. /*
// Doesn't depend on anything else. Initializes all kind of stuff in here.
// Many things depend on this. Many things depend on this.
void init_mapnode();
irrlicht: Used for getting texture ids.
*/
void init_mapnode(IrrlichtWrapper *irrlicht);
// Initializes g_content_inventory_texture_paths // Initializes g_content_inventory_texture_paths
void init_content_inventory_texture_paths(); void init_content_inventory_texture_paths();
@ -129,7 +133,8 @@ struct ContentFeatures
*/ */
TileSpec tiles[6]; TileSpec tiles[6];
std::string inventory_image_path; //std::string inventory_image_path;
TextureSpec inventory_texture;
bool is_ground_content; //TODO: Remove, use walkable instead bool is_ground_content; //TODO: Remove, use walkable instead
bool light_propagates; bool light_propagates;
@ -162,39 +167,42 @@ struct ContentFeatures
~ContentFeatures(); ~ContentFeatures();
void setAllTextures(std::string imgname, u8 alpha=255) void setAllTextures(const TextureSpec &spec, u8 alpha=255)
{ {
for(u16 i=0; i<6; i++) for(u16 i=0; i<6; i++)
{ {
tiles[i].name = porting::getDataPath(imgname.c_str()); tiles[i].spec = spec;
tiles[i].alpha = alpha; tiles[i].alpha = alpha;
} }
// Set this too so it can be left as is most times // Set this too so it can be left as is most times
if(inventory_image_path == "") /*if(inventory_image_path == "")
inventory_image_path = porting::getDataPath(imgname.c_str()); inventory_image_path = porting::getDataPath(imgname.c_str());*/
if(inventory_texture.empty())
inventory_texture = spec;
} }
void setTexture(u16 i, std::string imgname, u8 alpha=255) void setTexture(u16 i, const TextureSpec &spec, u8 alpha=255)
{ {
tiles[i].name = porting::getDataPath(imgname.c_str()); tiles[i].spec = spec;
tiles[i].alpha = alpha; tiles[i].alpha = alpha;
} }
void setInventoryImage(std::string imgname) void setInventoryTexture(const TextureSpec &spec)
{
inventory_texture = spec;
}
/*void setInventoryImage(std::string imgname)
{ {
inventory_image_path = porting::getDataPath(imgname.c_str()); inventory_image_path = porting::getDataPath(imgname.c_str());
} }*/
}; };
// Initialized by init_mapnode() /*
extern struct ContentFeatures g_content_features[256]; Call this to access the ContentFeature list
*/
inline ContentFeatures & content_features(u8 i) ContentFeatures & content_features(u8 i);
{
return g_content_features[i];
}
extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
/* /*
If true, the material allows light propagation and brightness is stored If true, the material allows light propagation and brightness is stored
@ -203,7 +211,7 @@ extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
*/ */
inline bool light_propagates_content(u8 m) inline bool light_propagates_content(u8 m)
{ {
return g_content_features[m].light_propagates; return content_features(m).light_propagates;
//return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE); //return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
} }
@ -214,7 +222,7 @@ inline bool light_propagates_content(u8 m)
*/ */
inline bool sunlight_propagates_content(u8 m) inline bool sunlight_propagates_content(u8 m)
{ {
return g_content_features[m].sunlight_propagates; return content_features(m).sunlight_propagates;
//return (m == CONTENT_AIR || m == CONTENT_TORCH); //return (m == CONTENT_AIR || m == CONTENT_TORCH);
} }
@ -228,7 +236,7 @@ inline bool sunlight_propagates_content(u8 m)
*/ */
inline u8 content_solidness(u8 m) inline u8 content_solidness(u8 m)
{ {
return g_content_features[m].solidness; return content_features(m).solidness;
/*// As of now, every pseudo node like torches are added to this /*// 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;
@ -241,28 +249,28 @@ inline u8 content_solidness(u8 m)
// NOTE: Don't use, use "content_features(m).whatever" instead // NOTE: Don't use, use "content_features(m).whatever" instead
inline bool content_walkable(u8 m) inline bool content_walkable(u8 m)
{ {
return g_content_features[m].walkable; return content_features(m).walkable;
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH); //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
} }
// NOTE: Don't use, use "content_features(m).whatever" instead // NOTE: Don't use, use "content_features(m).whatever" instead
inline bool content_liquid(u8 m) inline bool content_liquid(u8 m)
{ {
return g_content_features[m].liquid_type != LIQUID_NONE; return content_features(m).liquid_type != LIQUID_NONE;
//return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE); //return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
} }
// NOTE: Don't use, use "content_features(m).whatever" instead // 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 g_content_features[m].liquid_type == LIQUID_FLOWING; return content_features(m).liquid_type == LIQUID_FLOWING;
//return (m == CONTENT_WATER); //return (m == CONTENT_WATER);
} }
// NOTE: Don't use, use "content_features(m).whatever" instead // 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 g_content_features[m].liquid_type == LIQUID_SOURCE; return content_features(m).liquid_type == LIQUID_SOURCE;
//return (m == CONTENT_WATERSOURCE); //return (m == CONTENT_WATERSOURCE);
} }
@ -279,21 +287,21 @@ inline u8 make_liquid_flowing(u8 m)
// NOTE: Don't use, use "content_features(m).whatever" instead // NOTE: Don't use, use "content_features(m).whatever" instead
inline bool content_pointable(u8 m) inline bool content_pointable(u8 m)
{ {
return g_content_features[m].pointable; return content_features(m).pointable;
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE); //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
} }
// NOTE: Don't use, use "content_features(m).whatever" instead // NOTE: Don't use, use "content_features(m).whatever" instead
inline bool content_diggable(u8 m) inline bool content_diggable(u8 m)
{ {
return g_content_features[m].diggable; return content_features(m).diggable;
//return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE); //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
} }
// NOTE: Don't use, use "content_features(m).whatever" instead // 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 g_content_features[m].buildable_to; return content_features(m).buildable_to;
//return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE); //return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
} }
@ -303,7 +311,7 @@ inline bool content_buildable_to(u8 m)
*/ */
/*inline bool is_ground_content(u8 m) /*inline bool is_ground_content(u8 m)
{ {
return g_content_features[m].is_ground_content; return content_features(m).is_ground_content;
}*/ }*/
/* /*
@ -622,7 +630,7 @@ struct MapNode
} }
// Translate deprecated stuff // Translate deprecated stuff
MapNode *translate_to = g_content_features[d].translate_to; MapNode *translate_to = content_features(d).translate_to;
if(translate_to) if(translate_to)
{ {
dstream<<"MapNode: WARNING: Translating "<<d<<" to " dstream<<"MapNode: WARNING: Translating "<<d<<" to "

49
src/mineral.cpp Normal file

@ -0,0 +1,49 @@
/*
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.
*/
#include "mineral.h"
const char *mineral_filenames[MINERAL_COUNT] =
{
NULL,
"mineral_coal.png",
"mineral_iron.png"
};
textureid_t mineral_textures[MINERAL_COUNT] = {0};
void init_mineral(IrrlichtWrapper *irrlicht)
{
for(u32 i=0; i<MINERAL_COUNT; i++)
{
if(mineral_filenames[i] == NULL)
continue;
mineral_textures[i] = irrlicht->getTextureId(mineral_filenames[i]);
}
}
textureid_t mineral_block_texture(u8 mineral)
{
if(mineral >= MINERAL_COUNT)
return 0;
return mineral_textures[mineral];
}

@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MINERAL_HEADER #define MINERAL_HEADER
#include "inventory.h" #include "inventory.h"
#include "texture.h"
#include "irrlichtwrapper.h"
/* /*
Minerals Minerals
@ -29,22 +31,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
type param. type param.
*/ */
// Caches textures
void init_mineral(IrrlichtWrapper *irrlicht);
#define MINERAL_NONE 0 #define MINERAL_NONE 0
#define MINERAL_COAL 1 #define MINERAL_COAL 1
#define MINERAL_IRON 2 #define MINERAL_IRON 2
inline const char * mineral_block_texture(u8 mineral) #define MINERAL_COUNT 3
{
switch(mineral) textureid_t mineral_block_texture(u8 mineral);
{
case MINERAL_COAL:
return "mineral_coal.png";
case MINERAL_IRON:
return "mineral_iron.png";
default:
return "";
}
}
inline CraftItem * getDiggedMineralItem(u8 mineral) inline CraftItem * getDiggedMineralItem(u8 mineral)
{ {

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h" #include "map.h"
#include "connection.h" #include "connection.h"
#include "constants.h" #include "constants.h"
#include "utility.h"
Player::Player(): Player::Player():
touching_ground(false), touching_ground(false),
@ -34,15 +35,21 @@ Player::Player():
m_position(0,0,0) m_position(0,0,0)
{ {
updateName("<not set>"); updateName("<not set>");
inventory.addList("main", PLAYER_INVENTORY_SIZE); resetInventory();
inventory.addList("craft", 9);
inventory.addList("craftresult", 1);
} }
Player::~Player() Player::~Player()
{ {
} }
void Player::resetInventory()
{
inventory.clear();
inventory.addList("main", PLAYER_INVENTORY_SIZE);
inventory.addList("craft", 9);
inventory.addList("craftresult", 1);
}
// Y direction is ignored // Y direction is ignored
void Player::accelerate(v3f target_speed, f32 max_increase) void Player::accelerate(v3f target_speed, f32 max_increase)
{ {
@ -80,6 +87,50 @@ void Player::accelerate(v3f target_speed, f32 max_increase)
#endif #endif
} }
void Player::serialize(std::ostream &os)
{
// Utilize a Settings object for storing values
Settings args;
args.setS32("version", 1);
args.set("name", m_name);
args.setFloat("pitch", m_pitch);
args.setFloat("yaw", m_yaw);
args.setV3F("position", m_position);
args.writeLines(os);
os<<"PlayerArgsEnd\n";
inventory.serialize(os);
}
void Player::deSerialize(std::istream &is)
{
Settings args;
for(;;)
{
if(is.eof())
throw SerializationError
("Player::deSerialize(): PlayerArgsEnd not found");
std::string line;
std::getline(is, line);
std::string trimmedline = trim(line);
if(trimmedline == "PlayerArgsEnd")
break;
args.parseConfigLine(line);
}
//args.getS32("version");
std::string name = args.get("name");
updateName(name.c_str());
m_pitch = args.getFloat("pitch");
m_yaw = args.getFloat("yaw");
m_position = args.getV3F("position");
inventory.deSerialize(is);
}
/* /*
RemotePlayer RemotePlayer
*/ */

@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PLAYERNAME_SIZE 20 #define PLAYERNAME_SIZE 20
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
class Map; class Map;
class Player class Player
@ -37,6 +39,8 @@ public:
Player(); Player();
virtual ~Player(); virtual ~Player();
void resetInventory();
//void move(f32 dtime, Map &map); //void move(f32 dtime, Map &map);
virtual void move(f32 dtime, Map &map) = 0; virtual void move(f32 dtime, Map &map) = 0;
@ -100,6 +104,14 @@ public:
// NOTE: Use peer_id == 0 for disconnected // NOTE: Use peer_id == 0 for disconnected
/*virtual bool isClientConnected() { return false; } /*virtual bool isClientConnected() { return false; }
virtual void setClientConnected(bool) {}*/ virtual void setClientConnected(bool) {}*/
/*
serialize() writes a bunch of text that can contain
any characters except a '\0', and such an ending that
deSerialize stops reading exactly at the right point.
*/
void serialize(std::ostream &os);
void deSerialize(std::istream &is);
bool touching_ground; bool touching_ground;
bool in_water; bool in_water;
@ -119,8 +131,6 @@ protected:
class ServerRemotePlayer : public Player class ServerRemotePlayer : public Player
{ {
public: public:
/*ServerRemotePlayer(bool client_connected):
m_client_connected(client_connected)*/
ServerRemotePlayer() ServerRemotePlayer()
{ {
} }
@ -137,18 +147,6 @@ public:
{ {
} }
/*virtual bool isClientConnected()
{
return m_client_connected;
}
virtual void setClientConnected(bool client_connected)
{
m_client_connected = client_connected;
}
// This
bool m_client_connected;*/
private: private:
}; };
@ -252,7 +250,7 @@ private:
v3f m_showpos; v3f m_showpos;
}; };
#endif #endif // !SERVER
#ifndef SERVER #ifndef SERVER
struct PlayerControl struct PlayerControl

@ -1000,7 +1000,8 @@ Server::Server(
m_time_of_day(9000), m_time_of_day(9000),
m_time_counter(0), m_time_counter(0),
m_time_of_day_send_timer(0), m_time_of_day_send_timer(0),
m_uptime(0) m_uptime(0),
m_mapsavedir(mapsavedir)
{ {
//m_flowwater_timer = 0.0; //m_flowwater_timer = 0.0;
m_liquid_transform_timer = 0.0; m_liquid_transform_timer = 0.0;
@ -1013,10 +1014,16 @@ Server::Server(
m_con_mutex.Init(); m_con_mutex.Init();
m_step_dtime_mutex.Init(); m_step_dtime_mutex.Init();
m_step_dtime = 0.0; m_step_dtime = 0.0;
// Load players
m_env.deSerializePlayers(m_mapsavedir);
} }
Server::~Server() Server::~Server()
{ {
// Save players
m_env.serializePlayers(m_mapsavedir);
// Stop threads // Stop threads
stop(); stop();
@ -1222,82 +1229,6 @@ void Server::AsyncRunStep()
} }
} }
#if 0
/*
Update water
*/
if(g_settings.getBool("water_moves") == true)
{
float interval;
if(g_settings.getBool("endless_water") == false)
interval = 1.0;
else
interval = 0.25;
float &counter = m_flowwater_timer;
counter += dtime;
if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
{
counter = 0.0;
core::map<v3s16, MapBlock*> modified_blocks;
{
JMutexAutoLock envlock(m_env_mutex);
MapVoxelManipulator v(&m_env.getMap());
v.m_disable_water_climb =
g_settings.getBool("disable_water_climb");
if(g_settings.getBool("endless_water") == false)
v.flowWater(m_flow_active_nodes, 0, false, 250);
else
v.flowWater(m_flow_active_nodes, 0, false, 50);
v.blitBack(modified_blocks);
ServerMap &map = ((ServerMap&)m_env.getMap());
// Update lighting
core::map<v3s16, MapBlock*> lighting_modified_blocks;
map.updateLighting(modified_blocks, lighting_modified_blocks);
// Add blocks modified by lighting to modified_blocks
for(core::map<v3s16, MapBlock*>::Iterator
i = lighting_modified_blocks.getIterator();
i.atEnd() == false; i++)
{
MapBlock *block = i.getNode()->getValue();
modified_blocks.insert(block->getPos(), block);
}
} // envlock
/*
Set the modified blocks unsent for all the clients
*/
JMutexAutoLock lock2(m_con_mutex);
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
if(modified_blocks.size() > 0)
{
// Remove block from sent history
client->SetBlocksNotSent(modified_blocks);
}
}
} // interval counter
}
#endif
// Periodically print some info // Periodically print some info
{ {
float &counter = m_print_info_timer; float &counter = m_print_info_timer;
@ -1476,6 +1407,9 @@ void Server::AsyncRunStep()
dout_server<<"Server: Unloaded "<<deleted_count dout_server<<"Server: Unloaded "<<deleted_count
<<" sectors from memory"<<std::endl; <<" sectors from memory"<<std::endl;
} }
// Save players
m_env.serializePlayers(m_mapsavedir);
} }
} }
} }
@ -1601,6 +1535,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
Player *player = emergePlayer(playername, "", peer_id); Player *player = emergePlayer(playername, "", peer_id);
//Player *player = m_env.getPlayer(peer_id); //Player *player = m_env.getPlayer(peer_id);
/*{
// DEBUG: Test serialization
std::ostringstream test_os;
player->serialize(test_os);
dstream<<"Player serialization test: \""<<test_os.str()
<<"\""<<std::endl;
std::istringstream test_is(test_os.str());
player->deSerialize(test_is);
}*/
// If failed, cancel // If failed, cancel
if(player == NULL) if(player == NULL)
{ {
@ -2950,7 +2894,7 @@ void Server::SendInventory(u16 peer_id)
if(!found) if(!found)
{ {
ItemSpec specs[9]; ItemSpec specs[9];
specs[0] = ItemSpec(ITEM_CRAFT, "Coal"); specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
if(checkItemCombination(items, specs)) if(checkItemCombination(items, specs))
{ {
@ -3147,6 +3091,50 @@ RemoteClient* Server::getClient(u16 peer_id)
return n->getValue(); return n->getValue();
} }
void setCreativeInventory(Player *player)
{
player->resetInventory();
// Give some good picks
{
InventoryItem *item = new ToolItem("STPick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem("MesePick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
/*
Give materials
*/
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
// add torch first
InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
player->inventory.addItem("main", item);
// Then others
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
{
// Skip some materials
if(i == CONTENT_WATER || i == CONTENT_TORCH
|| i == CONTENT_COALSTONE)
continue;
InventoryItem *item = new MaterialItem(i, 1);
player->inventory.addItem("main", item);
}
// Sign
{
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
}
Player *Server::emergePlayer(const char *name, const char *password, Player *Server::emergePlayer(const char *name, const char *password,
u16 peer_id) u16 peer_id)
{ {
@ -3162,8 +3150,16 @@ Player *Server::emergePlayer(const char *name, const char *password,
dstream<<"emergePlayer(): Player already connected"<<std::endl; dstream<<"emergePlayer(): Player already connected"<<std::endl;
return NULL; return NULL;
} }
// Got one. // Got one.
player->peer_id = peer_id; player->peer_id = peer_id;
// Reset inventory to creative if in creative mode
if(g_settings.getBool("creative_mode"))
{
setCreativeInventory(player);
}
return player; return player;
} }
@ -3271,51 +3267,15 @@ Player *Server::emergePlayer(const char *name, const char *password,
if(g_settings.getBool("creative_mode")) if(g_settings.getBool("creative_mode"))
{ {
// Give some good picks setCreativeInventory(player);
{
InventoryItem *item = new ToolItem("STPick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem("MesePick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
/*
Give materials
*/
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
// add torch first
InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
player->inventory.addItem("main", item);
// Then others
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
{
// Skip some materials
if(i == CONTENT_WATER || i == CONTENT_TORCH)
continue;
InventoryItem *item = new MaterialItem(i, 1);
player->inventory.addItem("main", item);
}
// Sign
{
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
} }
else else
{ {
{ /*{
InventoryItem *item = new ToolItem("WPick", 32000); InventoryItem *item = new ToolItem("WPick", 32000);
void* r = player->inventory.addItem("main", item); void* r = player->inventory.addItem("main", item);
assert(r == NULL); 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);

@ -508,6 +508,8 @@ private:
Queue<PeerChange> m_peer_change_queue; Queue<PeerChange> m_peer_change_queue;
std::string m_mapsavedir;
friend class EmergeThread; friend class EmergeThread;
friend class RemoteClient; friend class RemoteClient;
}; };

124
src/texture.h Normal file

@ -0,0 +1,124 @@
/*
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 TEXTURE_HEADER
#define TEXTURE_HEADER
#include "common_irrlicht.h"
//#include "utility.h"
#include "debug.h"
/*
All textures are given a "texture id".
0 = nothing (a NULL pointer texture)
*/
typedef u16 textureid_t;
/*
Every texture in the game can be specified by this.
It exists instead of specification strings because arbitary
texture combinations for map nodes are handled using this,
and strings are too slow for that purpose.
Plain texture pointers are not used because they don't contain
content information by themselves. A texture can be completely
reconstructed by just looking at this, while this also is a
fast unique key to containers.
*/
#define TEXTURE_SPEC_TEXTURE_COUNT 4
struct TextureSpec
{
TextureSpec()
{
clear();
}
TextureSpec(textureid_t id0)
{
clear();
tids[0] = id0;
}
TextureSpec(textureid_t id0, textureid_t id1)
{
clear();
tids[0] = id0;
tids[1] = id1;
}
void clear()
{
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
tids[i] = 0;
}
}
bool empty() const
{
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
if(tids[i] != 0)
return false;
}
return true;
}
void addTid(textureid_t tid)
{
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
if(tids[i] == 0)
{
tids[i] = tid;
return;
}
}
// Too many textures
assert(0);
}
bool operator==(const TextureSpec &other) const
{
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
if(tids[i] != other.tids[i])
return false;
}
return true;
}
bool operator<(const TextureSpec &other) const
{
for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
{
if(tids[i] >= other.tids[i])
return false;
}
return true;
}
// Ids of textures. They are blit on each other.
textureid_t tids[TEXTURE_SPEC_TEXTURE_COUNT];
};
#endif

@ -22,8 +22,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
//#include "utility.h" //#include "utility.h"
#include "texture.h"
#include <string> #include <string>
struct TileSpec
{
TileSpec():
alpha(255)
{
}
bool operator==(TileSpec &other)
{
return (spec == other.spec && alpha == other.alpha);
}
TextureSpec spec;
u8 alpha;
};
#if 0
struct TileSpec struct TileSpec
{ {
TileSpec(): TileSpec():
@ -52,5 +70,6 @@ struct TileSpec
std::string name; std::string name;
u8 alpha; u8 alpha;
}; };
#endif
#endif #endif

@ -760,17 +760,20 @@ class Settings
{ {
public: public:
// Returns false on EOF void writeLines(std::ostream &os)
bool parseConfigObject(std::istream &is)
{ {
if(is.eof()) for(core::map<std::string, std::string>::Iterator
return false; i = m_settings.getIterator();
i.atEnd() == false; i++)
// NOTE: This function will be expanded to allow multi-line settings {
std::string line; std::string name = i.getNode()->getKey();
std::getline(is, line); std::string value = i.getNode()->getValue();
//dstream<<"got line: \""<<line<<"\""<<std::endl; os<<name<<" = "<<value<<"\n";
}
}
bool parseConfigLine(const std::string &line)
{
std::string trimmedline = trim(line); std::string trimmedline = trim(line);
// Ignore comments // Ignore comments
@ -798,6 +801,23 @@ public:
return true; return true;
} }
// Returns false on EOF
bool parseConfigObject(std::istream &is)
{
if(is.eof())
return false;
/*
NOTE: This function might be expanded to allow multi-line
settings.
*/
std::string line;
std::getline(is, line);
//dstream<<"got line: \""<<line<<"\""<<std::endl;
return parseConfigLine(line);
}
/* /*
Read configuration file Read configuration file
@ -1089,10 +1109,7 @@ public:
float getFloat(std::string name) float getFloat(std::string name)
{ {
float f; return stof(get(name));
std::istringstream vis(get(name));
vis>>f;
return f;
} }
u16 getU16(std::string name) u16 getU16(std::string name)
@ -1128,6 +1145,34 @@ public:
return stoi(get(name)); return stoi(get(name));
} }
v3f getV3F(std::string name)
{
v3f value;
Strfnd f(get(name));
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(","));
value.Z = stof(f.next(")"));
return value;
}
void setS32(std::string name, s32 value)
{
set(name, itos(value));
}
void setFloat(std::string name, float value)
{
set(name, ftos(value));
}
void setV3F(std::string name, v3f value)
{
std::ostringstream os;
os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
set(name, os.str());
}
void clear() void clear()
{ {
m_settings.clear(); m_settings.clear();
@ -1628,5 +1673,121 @@ private:
core::list<Value> m_list; core::list<Value> m_list;
}; };
#if 0
template<typename Key, typename Value>
class MutexedCache
{
public:
MutexedCache()
{
m_mutex.Init();
assert(m_mutex.IsInitialized());
}
void set(const Key &name, const Value &value)
{
JMutexAutoLock lock(m_mutex);
m_values[name] = value;
}
bool get(const Key &name, Value *result)
{
JMutexAutoLock lock(m_mutex);
typename core::map<Key, Value>::Node *n;
n = m_values.find(name);
if(n == NULL)
return false;
*result = n->getValue();
return true;
}
private:
core::map<Key, Value> m_values;
JMutex m_mutex;
};
#endif
/*
Generates ids for comparable values.
Id=0 is reserved for "no value".
Is fast at:
- Returning value by id (very fast)
- Returning id by value
- Generating a new id for a value
Is not able to:
- Remove an id/value pair (is possible to implement but slow)
*/
template<typename T>
class MutexedIdGenerator
{
public:
MutexedIdGenerator()
{
m_mutex.Init();
assert(m_mutex.IsInitialized());
}
// Returns true if found
bool getValue(u32 id, T &value)
{
if(id == 0)
return false;
JMutexAutoLock lock(m_mutex);
if(m_id_to_value.size() < id)
return false;
value = m_id_to_value[id-1];
return true;
}
// If id exists for value, returns the id.
// Otherwise generates an id for the value.
u32 getId(const T &value)
{
JMutexAutoLock lock(m_mutex);
typename core::map<T, u32>::Node *n;
n = m_value_to_id.find(value);
if(n != NULL)
return n->getValue();
m_id_to_value.push_back(value);
u32 new_id = m_id_to_value.size();
m_value_to_id.insert(value, new_id);
return new_id;
}
private:
JMutex m_mutex;
// Values are stored here at id-1 position (id 1 = [0])
core::array<T> m_id_to_value;
core::map<T, u32> m_value_to_id;
};
/*
Checks if a string contains only supplied characters
*/
inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
{
for(u32 i=0; i<s.size(); i++)
{
bool confirmed = false;
for(u32 j=0; j<allowed_chars.size(); j++)
{
if(s[i] == allowed_chars[j])
{
confirmed = true;
break;
}
}
if(confirmed == false)
return false;
}
return true;
}
#endif #endif