diff options
-rw-r--r-- | data/grass.png | bin | 1599 -> 1675 bytes | |||
-rw-r--r-- | data/grass_side.png | bin | 1695 -> 1690 bytes | |||
-rw-r--r-- | minetest.vcproj | 4 | ||||
-rw-r--r-- | src/CMakeLists.txt | 47 | ||||
-rw-r--r-- | src/environment.cpp | 181 | ||||
-rw-r--r-- | src/environment.h | 4 | ||||
-rw-r--r-- | src/inventory.cpp | 8 | ||||
-rw-r--r-- | src/inventory.h | 43 | ||||
-rw-r--r-- | src/irrlichtwrapper.cpp | 471 | ||||
-rw-r--r-- | src/irrlichtwrapper.h | 87 | ||||
-rw-r--r-- | src/main.cpp | 61 | ||||
-rw-r--r-- | src/mapblock.cpp | 73 | ||||
-rw-r--r-- | src/mapnode.cpp | 70 | ||||
-rw-r--r-- | src/mapnode.h | 76 | ||||
-rw-r--r-- | src/mineral.cpp | 49 | ||||
-rw-r--r-- | src/mineral.h | 20 | ||||
-rw-r--r-- | src/player.cpp | 57 | ||||
-rw-r--r-- | src/player.h | 28 | ||||
-rw-r--r-- | src/server.cpp | 194 | ||||
-rw-r--r-- | src/server.h | 2 | ||||
-rw-r--r-- | src/texture.h | 124 | ||||
-rw-r--r-- | src/tile.h | 19 | ||||
-rw-r--r-- | src/utility.h | 187 |
23 files changed, 1158 insertions, 647 deletions
diff --git a/data/grass.png b/data/grass.png Binary files differindex 88336c013..8fe9078ca 100644 --- a/data/grass.png +++ b/data/grass.png diff --git a/data/grass_side.png b/data/grass_side.png Binary files differindex ee12491e8..7bacbfb5e 100644 --- a/data/grass_side.png +++ b/data/grass_side.png diff --git a/minetest.vcproj b/minetest.vcproj index 71dc5763a..68c6fced7 100644 --- a/minetest.vcproj +++ b/minetest.vcproj @@ -272,6 +272,10 @@ >
</File>
<File
+ RelativePath=".\src\mineral.cpp"
+ >
+ </File>
+ <File
RelativePath=".\src\player.cpp"
>
</File>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7913f4964..d027c7cd9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,18 +38,12 @@ configure_file( "${PROJECT_BINARY_DIR}/cmake_config.h" ) -set(minetest_SRCS - guiMainMenu.cpp +set(common_SRCS + mineral.cpp porting.cpp - guiMessageMenu.cpp materials.cpp - guiTextInputMenu.cpp - guiInventoryMenu.cpp - irrlichtwrapper.cpp - guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp - tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp @@ -59,7 +53,6 @@ set(minetest_SRCS filesys.cpp connection.cpp environment.cpp - client.cpp server.cpp socket.cpp mapblock.cpp @@ -68,34 +61,24 @@ set(minetest_SRCS map.cpp player.cpp utility.cpp - main.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 - porting.cpp - 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 + ${common_SRCS} servermain.cpp - test.cpp ) include_directories( diff --git a/src/environment.cpp b/src/environment.cpp index 51ed05422..9d64ff58a 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "environment.h" +#include "filesys.h" Environment::Environment(Map *map, std::ostream &dout): m_dout(dout) @@ -192,6 +193,7 @@ void Environment::addPlayer(Player *player) DSTACK(__FUNCTION_NAME); /* 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 */ #ifndef SERVER @@ -201,8 +203,12 @@ void Environment::addPlayer(Player *player) */ assert(!(player->isLocal() == true && getLocalPlayer() != NULL)); #endif + // If peer id is non-zero, it has to be unique. if(player->peer_id != 0) assert(getPlayer(player->peer_id) == NULL); + // Name has to be unique. + assert(getPlayer(player->getName()) == NULL); + // Add. 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 void Environment::updateMeshes(v3s16 blockpos) { diff --git a/src/environment.h b/src/environment.h index fa7253170..dfc60673b 100644 --- a/src/environment.h +++ b/src/environment.h @@ -63,6 +63,10 @@ public: core::list<Player*> getPlayers(); core::list<Player*> getPlayers(bool ignore_disconnected); void printPlayers(std::ostream &o); + + void serializePlayers(const std::string &savedir); + // This loads players as ServerRemotePlayers + void deSerializePlayers(const std::string &savedir); #ifndef SERVER void updateMeshes(v3s16 blockpos); diff --git a/src/inventory.cpp b/src/inventory.cpp index 713adefdf..cbe66edb0 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -217,7 +217,7 @@ void InventoryList::serialize(std::ostream &os) os<<"\n"; } - os<<"end\n"; + os<<"EndInventoryList\n"; } void InventoryList::deSerialize(std::istream &is) @@ -238,7 +238,7 @@ void InventoryList::deSerialize(std::istream &is) std::string name; std::getline(iss, name, ' '); - if(name == "end") + if(name == "EndInventoryList") { break; } @@ -497,7 +497,7 @@ void Inventory::serialize(std::ostream &os) list->serialize(os); } - os<<"end\n"; + os<<"EndInventory\n"; } void Inventory::deSerialize(std::istream &is) @@ -514,7 +514,7 @@ void Inventory::deSerialize(std::istream &is) std::string name; std::getline(iss, name, ' '); - if(name == "end") + if(name == "EndInventory") { break; } diff --git a/src/inventory.h b/src/inventory.h index 797a67509..e7c7adaee 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -122,10 +122,12 @@ public: #ifndef SERVER video::ITexture * getImage() { - if(m_content >= USEFUL_CONTENT_COUNT) + /*if(m_content >= USEFUL_CONTENT_COUNT) 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 std::string getText() @@ -250,19 +252,19 @@ public: #ifndef SERVER video::ITexture * getImage() { - std::string basename; + std::string name; if(m_subname == "Stick") - basename = porting::getDataPath("stick.png"); + name = "stick.png"; 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") - basename = porting::getDataPath("lump_of_iron.png"); + name = "lump_of_iron.png"; else - basename = porting::getDataPath("cloud.png[[mod:crack3"); + name = "cloud.png"; // Get such a texture - return g_irrlicht->getTexture(basename); + return g_irrlicht->getTexture(name); } #endif std::string getText() @@ -330,28 +332,35 @@ public: { std::string basename; if(m_toolname == "WPick") - basename = porting::getDataPath("tool_wpick.png").c_str(); + basename = "tool_wpick.png"; else if(m_toolname == "STPick") - basename = porting::getDataPath("tool_stpick.png").c_str(); + basename = "tool_stpick.png"; else if(m_toolname == "MesePick") - basename = porting::getDataPath("tool_mesepick.png").c_str(); - // Default to cloud texture + basename = "tool_mesepick.png"; else - basename = porting::getDataPath("cloud.png").c_str(); - //basename = tile_texture_path_get(TILE_CLOUD); + basename = "cloud.png"; /* - Calculate some progress value with sane amount of + Calculate a progress value with sane amount of maximum states */ u32 maxprogress = 30; 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; std::ostringstream os; 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 std::ostringstream os; diff --git a/src/irrlichtwrapper.cpp b/src/irrlichtwrapper.cpp index 4e1ebdd74..e5cab98c6 100644 --- a/src/irrlichtwrapper.cpp +++ b/src/irrlichtwrapper.cpp @@ -17,13 +17,15 @@ void IrrlichtWrapper::Run() */ 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(); - dstream<<"got texture request with key=" - <<request.key<<std::endl; + dstream<<"got texture request with" + <<" 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.key = request.key; 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; 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) { - dstream<<"Getting texture directly: spec=" - <<spec<<std::endl; + dstream<<"Getting texture directly: spec.tids[0]=" + <<spec.tids[0]<<std::endl; t = getTextureDirect(spec); } else { // 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 m_get_texture_queue.add(spec, 0, 0, &result_queue); - dstream<<"Waiting for texture from main thread: " - <<spec<<std::endl; + dstream<<"Waiting for texture from main thread: spec.tids[0]=" + <<spec.tids[0]<<std::endl; try { // Wait result for a second - GetResult<std::string, video::ITexture*, u8, u8> + GetResult<TextureSpec, video::ITexture*, u8, u8> result = result_queue.pop_front(1000); // Check that at least something worked OK @@ -83,144 +105,177 @@ video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec) return t; } -/* - Non-thread-safe functions -*/ +// Draw a progress bar on the image +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 * make_blitname(const std::string &blitted_name, - video::ITexture *original, - const char *newname, video::IVideoDriver* driver) +video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec) { - if(original == NULL) + // This would result in NULL image + if(spec.empty()) 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); + // Don't generate existing stuff + video::ITexture *t = m_texturecache.get(spec); + if(t != NULL) + { + dstream<<"WARNING: Existing stuff requested from " + "getTextureDirect()"<<std::endl; + return t; + } - blittedimage->drop(); - - // Create texture from resulting image - - video::ITexture *newtexture = driver->addTexture(newname, baseimage); + video::IVideoDriver* driver = m_device->getVideoDriver(); - baseimage->drop(); + /* + An image will be built from files and then converted into a texture. + */ + video::IImage *baseimg = NULL; - return newtexture; -} + /* + Irrlicht requires a name for every texture, with which it + will be stored internally in irrlicht. + */ + std::string texture_name; -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 - //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(); + for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++) + { + textureid_t tid = spec.tids[i]; + if(tid == 0) + continue; - // Create texture from resulting image + std::string name = getTextureName(tid); + + // Add something to the name so that it is a unique identifier. + texture_name += "["; + texture_name += name; + texture_name += "]"; - video::ITexture *newtexture = driver->addTexture(newname, baseimage); + 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()); - baseimage->drop(); + if(image == NULL) + { + dstream<<"WARNING: Could not load image \""<<name + <<"\" from path \""<<path<<"\"" + <<" while building texture"<<std::endl; + continue; + } - return newtexture; -} + // 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 0 -video::ITexture * make_sidegrass(video::ITexture *original, - const char *newname, video::IVideoDriver* driver) -{ - if(original == NULL) + // If no resulting image, return NULL + if(baseimg == NULL) + { + dstream<<"getTextureDirect(): baseimg is NULL (attempted to" + " create texture \""<<texture_name<<"\""<<std::endl; 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(); + /*// DEBUG: Paint some pixels + video::SColor c(255,255,0,0); + baseimg->setPixel(1,1, c); + baseimg->setPixel(1,14, c); + baseimg->setPixel(14,1, c); + baseimg->setPixel(14,14, c);*/ // 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; } -#endif -video::ITexture * make_progressbar(float value, video::ITexture *original, - const char *newname, video::IVideoDriver* driver) +void make_progressbar(float value, video::IImage *image) { - 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); + if(image == NULL) + return; - core::dimension2d<u32> size = baseimage->getDimension(); + core::dimension2d<u32> size = image->getDimension(); u32 barheight = 1; u32 barpad_x = 1; @@ -242,177 +297,9 @@ video::ITexture * make_progressbar(float value, video::ITexture *original, u32 x = x0 + barpos.X; for(u32 y=barpos.Y; y<barpos.Y+barheight; y++) { - baseimage->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; + image->setPixel(x,y, *c); } - - 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 } diff --git a/src/irrlichtwrapper.h b/src/irrlichtwrapper.h index 2506af012..a695bd1e4 100644 --- a/src/irrlichtwrapper.h +++ b/src/irrlichtwrapper.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" #include "debug.h" #include "utility.h" +#include "texture.h" #include <jmutex.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 background threads. */ - +#if 0 class TextureCache { public: @@ -73,12 +74,55 @@ private: core::map<std::string, video::ITexture*> m_textures; 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 background worker threads. Queues tasks to be done in the main thread. + + Also caches texture specification strings to ids and textures. */ class IrrlichtWrapper @@ -103,30 +147,55 @@ public: return m_device->getTimer()->getRealTime(); } - /* - Path can contain stuff like - "/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3" + /* + Format of a texture name: + "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) + */ + /* + 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. */ - video::ITexture* getTexture(const std::string &spec); + 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: /* 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 */ + // The id of the thread that can (and has to) use irrlicht directly threadid_t m_main_thread; - + + // The irrlicht device JMutex m_device_mutex; IrrlichtDevice *m_device; + + // 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; - - RequestQueue<std::string, video::ITexture*, u8, u8> m_get_texture_queue; + + // A mapping from texture id to string spec + MutexedIdGenerator<std::string> m_namecache; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 388ab8089..0dc822474 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,8 +104,11 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into 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:
--------------
@@ -165,6 +168,20 @@ TODO: Make fetching sector's blocks more efficient when rendering 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:
--------------
@@ -281,18 +298,6 @@ TODO: Flowing water to actually contain flow direction information TODO: Remove duplicate lighting implementation from Map (leave
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:
----------
@@ -360,6 +365,7 @@ Doing now: #include "filesys.h"
#include "config.h"
#include "guiMainMenu.h"
+#include "mineral.h"
IrrlichtWrapper *g_irrlicht;
@@ -1445,7 +1451,6 @@ int main(int argc, char *argv[]) // C-style stuff initialization
initializeMaterialProperties();
- init_mapnode();
// Debug handler
BEGIN_DEBUG_EXCEPTION_HANDLER
@@ -1683,7 +1688,8 @@ int main(int argc, char *argv[]) */
init_content_inventory_texture_paths();
- //init_tile_textures();
+ init_mapnode(g_irrlicht);
+ init_mineral(g_irrlicht);
/*
GUI stuff
@@ -2378,7 +2384,7 @@ int main(int argc, char *argv[]) bool nodefound = false;
v3s16 nodepos;
v3s16 neighbourpos;
- core::aabbox3d<f32> nodefacebox;
+ core::aabbox3d<f32> nodehilightbox;
f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position);
@@ -2470,7 +2476,7 @@ int main(int argc, char *argv[]) nodepos = np;
neighbourpos = np;
mindistance = distance;
- nodefacebox = box;
+ nodehilightbox = box;
}
}
}
@@ -2513,7 +2519,16 @@ int main(int argc, char *argv[]) nodepos = np;
neighbourpos = np + dirs[i];
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
} // for dirs
@@ -2531,15 +2546,7 @@ int main(int argc, char *argv[]) // Visualize selection
- 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);
- //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);
+ hilightboxes.push_back(nodehilightbox);
// Handle digging
diff --git a/src/mapblock.cpp b/src/mapblock.cpp index f06dbc811..b346b0980 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -263,6 +263,7 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, //u8 li = decode_light(light); u8 li = light; + //u8 li = 255; //DEBUG u8 alpha = tile.alpha; /*u8 alpha = 255; @@ -309,15 +310,16 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir) struct NodeMod mod = n->getValue(); if(mod.type == NODEMOD_CHANGECONTENT) { - //spec = content_tile(mod.param, face_dir); MapNode mn2(mod.param); spec = mn2.getTile(face_dir); } if(mod.type == NODEMOD_CRACK) { std::ostringstream os; - os<<"[[mod:crack"<<mod.param; - spec.name += os.str(); + os<<"[crack"<<mod.param; + + 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 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) //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++) { FastFace &f = fastfaces_new[i]; const u16 indices[] = {0,1,2,2,3,0}; - 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); + video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec); material.setTexture(0, texture); if(f.tile.alpha != 255) material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + else + material.MaterialType = video::EMT_SOLID; collector.append(material, f.vertices, 4, indices, 6); } @@ -691,13 +697,22 @@ void MapBlock::updateMesh(u32 daynight_ratio) /* Add special graphics: - torches - - TODO: Optimize by using same meshbuffer for same textures + - flowing water */ // 0ms //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 y=0; y<MAP_BLOCKSIZE; y++) for(s16 x=0; x<MAP_BLOCKSIZE; x++) @@ -751,17 +766,17 @@ void MapBlock::updateMesh(u32 daynight_ratio) = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; if(dir == v3s16(0,-1,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)) material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str())); + g_irrlicht->getTexture("torch_on_ceiling.png")); // For backwards compatibility else if(dir == v3s16(0,0,0)) material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str())); + g_irrlicht->getTexture("torch_on_floor.png")); else 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}; // Add to mesh collector @@ -947,19 +962,9 @@ void MapBlock::updateMesh(u32 daynight_ratio) 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}; // 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()); } - // 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}; // Add to mesh collector - collector.append(material, vertices, 4, indices, 6); + collector.append(material_w1, vertices, 4, indices, 6); } } } diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 7625fab68..d197454fe 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -31,80 +31,85 @@ ContentFeatures::~ContentFeatures() 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; ContentFeatures *f = NULL; i = CONTENT_STONE; f = &g_content_features[i]; - f->setAllTextures("stone.png"); + f->setAllTextures(irrlicht->getTextureId("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->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"), + irrlicht->getTextureId("grass_side.png"))); + f->setTexture(0, irrlicht->getTextureId("grass.png")); + f->setTexture(1, irrlicht->getTextureId("mud.png")); + f->setInventoryTexture(irrlicht->getTextureId("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->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"), + irrlicht->getTextureId("grass_side.png"))); + f->setTexture(0, irrlicht->getTextureId("grass_footsteps.png")); + f->setTexture(1, irrlicht->getTextureId("mud.png")); + f->setInventoryTexture(irrlicht->getTextureId("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->setAllTextures(irrlicht->getTextureId("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->setAllTextures(irrlicht->getTextureId("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->setAllTextures(irrlicht->getTextureId("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->setAllTextures(irrlicht->getTextureId("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->setAllTextures(irrlicht->getTextureId("coalstone.png")); f->is_ground_content = true;*/ i = CONTENT_WOOD; f = &g_content_features[i]; - f->setAllTextures("wood.png"); + f->setAllTextures(irrlicht->getTextureId("wood.png")); f->is_ground_content = true; i = CONTENT_MESE; f = &g_content_features[i]; - f->setAllTextures("mese.png"); + f->setAllTextures(irrlicht->getTextureId("mese.png")); f->is_ground_content = true; i = CONTENT_CLOUD; f = &g_content_features[i]; - f->setAllTextures("cloud.png"); + f->setAllTextures(irrlicht->getTextureId("cloud.png")); f->is_ground_content = true; i = CONTENT_AIR; @@ -120,7 +125,7 @@ void init_mapnode() i = CONTENT_WATER; f = &g_content_features[i]; - f->setInventoryImage("water.png"); + f->setInventoryTexture(irrlicht->getTextureId("water.png")); f->param_type = CPT_LIGHT; f->light_propagates = true; f->solidness = 0; // Drawn separately, makes no faces @@ -132,8 +137,8 @@ void init_mapnode() i = CONTENT_WATERSOURCE; f = &g_content_features[i]; - f->setTexture(0, "water.png", WATER_ALPHA); - f->setInventoryImage("water.png"); + f->setTexture(0, irrlicht->getTextureId("water.png"), WATER_ALPHA); + f->setInventoryTexture(irrlicht->getTextureId("water.png")); f->param_type = CPT_LIGHT; f->light_propagates = true; f->solidness = 1; @@ -145,7 +150,7 @@ void init_mapnode() i = CONTENT_TORCH; 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->light_propagates = true; 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) { u8 mineral = param & 0x1f; - const char *ts = mineral_block_texture(mineral); - if(ts[0] != 0) - { - spec.name += "[[mod:blitname:"; - spec.name += ts; - } + // Add mineral block texture + textureid_t tid = mineral_block_texture(mineral); + if(tid != 0) + spec.spec.addTid(tid); } return spec; @@ -206,14 +209,15 @@ u8 MapNode::getMineral() } // 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() { - 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_features[i].inventory_image_path.c_str(); - } + }*/ } diff --git a/src/mapnode.h b/src/mapnode.h index c69436c9e..0c52681be 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -27,11 +27,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "serialization.h" #include "tile.h" +#include "irrlichtwrapper.h" -// Initializes all kind of stuff in here. -// Doesn't depend on anything else. -// Many things depend on this. -void init_mapnode(); +/* + Initializes all kind of stuff in here. + Many things depend on this. + + irrlicht: Used for getting texture ids. +*/ +void init_mapnode(IrrlichtWrapper *irrlicht); // Initializes g_content_inventory_texture_paths void init_content_inventory_texture_paths(); @@ -129,7 +133,8 @@ struct ContentFeatures */ 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 light_propagates; @@ -162,39 +167,42 @@ struct 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++) { - tiles[i].name = porting::getDataPath(imgname.c_str()); + tiles[i].spec = spec; 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()); + /*if(inventory_image_path == "") + 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; } - void setInventoryImage(std::string imgname) + void setInventoryTexture(const TextureSpec &spec) { - inventory_image_path = porting::getDataPath(imgname.c_str()); + inventory_texture = spec; } -}; -// Initialized by init_mapnode() -extern struct ContentFeatures g_content_features[256]; - -inline ContentFeatures & content_features(u8 i) -{ - return g_content_features[i]; -} + /*void setInventoryImage(std::string imgname) + { + inventory_image_path = porting::getDataPath(imgname.c_str()); + }*/ +}; -extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT]; +/* + Call this to access the ContentFeature list +*/ +ContentFeatures & content_features(u8 i); /* 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) { - 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); } @@ -214,7 +222,7 @@ inline bool light_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); } @@ -228,7 +236,7 @@ inline bool sunlight_propagates_content(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 if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER) return 0; @@ -241,28 +249,28 @@ inline u8 content_solidness(u8 m) // NOTE: Don't use, use "content_features(m).whatever" instead 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); } // NOTE: Don't use, use "content_features(m).whatever" instead 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); } // NOTE: Don't use, use "content_features(m).whatever" instead 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); } // NOTE: Don't use, use "content_features(m).whatever" instead 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); } @@ -279,21 +287,21 @@ inline u8 make_liquid_flowing(u8 m) // NOTE: Don't use, use "content_features(m).whatever" instead 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); } // NOTE: Don't use, use "content_features(m).whatever" instead 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); } // NOTE: Don't use, use "content_features(m).whatever" instead 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); } @@ -303,7 +311,7 @@ inline bool content_buildable_to(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 - MapNode *translate_to = g_content_features[d].translate_to; + MapNode *translate_to = content_features(d).translate_to; if(translate_to) { dstream<<"MapNode: WARNING: Translating "<<d<<" to " diff --git a/src/mineral.cpp b/src/mineral.cpp new file mode 100644 index 000000000..506f5b75c --- /dev/null +++ b/src/mineral.cpp @@ -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]; +} + + diff --git a/src/mineral.h b/src/mineral.h index e43e48ab8..aa0902e12 100644 --- a/src/mineral.h +++ b/src/mineral.h @@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define MINERAL_HEADER #include "inventory.h" +#include "texture.h" +#include "irrlichtwrapper.h" /* Minerals @@ -29,22 +31,16 @@ with this program; if not, write to the Free Software Foundation, Inc., type param. */ +// Caches textures +void init_mineral(IrrlichtWrapper *irrlicht); + #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 ""; - } -} +#define MINERAL_COUNT 3 + +textureid_t mineral_block_texture(u8 mineral); inline CraftItem * getDiggedMineralItem(u8 mineral) { diff --git a/src/player.cpp b/src/player.cpp index 8aabb030c..b260e5056 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "connection.h" #include "constants.h" +#include "utility.h" Player::Player(): touching_ground(false), @@ -34,15 +35,21 @@ Player::Player(): m_position(0,0,0) { updateName("<not set>"); - inventory.addList("main", PLAYER_INVENTORY_SIZE); - inventory.addList("craft", 9); - inventory.addList("craftresult", 1); + resetInventory(); } 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 void Player::accelerate(v3f target_speed, f32 max_increase) { @@ -80,6 +87,50 @@ void Player::accelerate(v3f target_speed, f32 max_increase) #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 */ diff --git a/src/player.h b/src/player.h index 9330bdd54..5ab027e0a 100644 --- a/src/player.h +++ b/src/player.h @@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PLAYERNAME_SIZE 20 +#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.," + class Map; class Player @@ -37,6 +39,8 @@ public: Player(); virtual ~Player(); + void resetInventory(); + //void move(f32 dtime, Map &map); virtual void move(f32 dtime, Map &map) = 0; @@ -100,6 +104,14 @@ public: // NOTE: Use peer_id == 0 for disconnected /*virtual bool isClientConnected() { return false; } 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 in_water; @@ -119,8 +131,6 @@ protected: class ServerRemotePlayer : public Player { public: - /*ServerRemotePlayer(bool client_connected): - m_client_connected(client_connected)*/ 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: }; @@ -252,7 +250,7 @@ private: v3f m_showpos; }; -#endif +#endif // !SERVER #ifndef SERVER struct PlayerControl diff --git a/src/server.cpp b/src/server.cpp index 541582b65..823a48b90 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1000,7 +1000,8 @@ Server::Server( m_time_of_day(9000), m_time_counter(0), m_time_of_day_send_timer(0), - m_uptime(0) + m_uptime(0), + m_mapsavedir(mapsavedir) { //m_flowwater_timer = 0.0; m_liquid_transform_timer = 0.0; @@ -1013,10 +1014,16 @@ Server::Server( m_con_mutex.Init(); m_step_dtime_mutex.Init(); m_step_dtime = 0.0; + + // Load players + m_env.deSerializePlayers(m_mapsavedir); } Server::~Server() { + // Save players + m_env.serializePlayers(m_mapsavedir); + // Stop threads 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 { float &counter = m_print_info_timer; @@ -1476,6 +1407,9 @@ void Server::AsyncRunStep() dout_server<<"Server: Unloaded "<<deleted_count <<" 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 = 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(player == NULL) { @@ -2950,7 +2894,7 @@ void Server::SendInventory(u16 peer_id) if(!found) { ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_CRAFT, "Coal"); + specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal"); specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); if(checkItemCombination(items, specs)) { @@ -3147,6 +3091,50 @@ RemoteClient* Server::getClient(u16 peer_id) 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, u16 peer_id) { @@ -3162,8 +3150,16 @@ Player *Server::emergePlayer(const char *name, const char *password, dstream<<"emergePlayer(): Player already connected"<<std::endl; return NULL; } + // Got one. player->peer_id = peer_id; + + // Reset inventory to creative if in creative mode + if(g_settings.getBool("creative_mode")) + { + setCreativeInventory(player); + } + return player; } @@ -3271,51 +3267,15 @@ Player *Server::emergePlayer(const char *name, const char *password, if(g_settings.getBool("creative_mode")) { - // 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) - 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); - } + setCreativeInventory(player); } 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); diff --git a/src/server.h b/src/server.h index a3e1897d9..fcc37631f 100644 --- a/src/server.h +++ b/src/server.h @@ -508,6 +508,8 @@ private: Queue<PeerChange> m_peer_change_queue; + std::string m_mapsavedir; + friend class EmergeThread; friend class RemoteClient; }; diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 000000000..f14efae11 --- /dev/null +++ b/src/texture.h @@ -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 diff --git a/src/tile.h b/src/tile.h index b903d92a8..ff495abc4 100644 --- a/src/tile.h +++ b/src/tile.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" //#include "utility.h" +#include "texture.h" #include <string> struct TileSpec @@ -31,6 +32,23 @@ struct TileSpec { } + bool operator==(TileSpec &other) + { + return (spec == other.spec && alpha == other.alpha); + } + + TextureSpec spec; + u8 alpha; +}; + +#if 0 +struct TileSpec +{ + TileSpec(): + alpha(255) + { + } + TileSpec(const std::string &a_name): name(a_name), alpha(255) @@ -52,5 +70,6 @@ struct TileSpec std::string name; u8 alpha; }; +#endif #endif diff --git a/src/utility.h b/src/utility.h index b517848b1..4f74a0649 100644 --- a/src/utility.h +++ b/src/utility.h @@ -760,17 +760,20 @@ class Settings { public: - // Returns false on EOF - bool parseConfigObject(std::istream &is) + void writeLines(std::ostream &os) { - if(is.eof()) - return false; - - // NOTE: This function will be expanded to allow multi-line settings - std::string line; - std::getline(is, line); - //dstream<<"got line: \""<<line<<"\""<<std::endl; + for(core::map<std::string, std::string>::Iterator + i = m_settings.getIterator(); + i.atEnd() == false; i++) + { + std::string name = i.getNode()->getKey(); + std::string value = i.getNode()->getValue(); + os<<name<<" = "<<value<<"\n"; + } + } + bool parseConfigLine(const std::string &line) + { std::string trimmedline = trim(line); // Ignore comments @@ -798,6 +801,23 @@ public: 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 @@ -1089,10 +1109,7 @@ public: float getFloat(std::string name) { - float f; - std::istringstream vis(get(name)); - vis>>f; - return f; + return stof(get(name)); } u16 getU16(std::string name) @@ -1128,6 +1145,34 @@ public: 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() { m_settings.clear(); @@ -1628,5 +1673,121 @@ private: 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 |