Now texture handling is fast. Also now players are saved on disk.
authorPerttu Ahola <celeron55@gmail.com>
Thu, 27 Jan 2011 23:38:16 +0000 (01:38 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Thu, 27 Jan 2011 23:38:16 +0000 (01:38 +0200)
23 files changed:
data/grass.png
data/grass_side.png
minetest.vcproj
src/CMakeLists.txt
src/environment.cpp
src/environment.h
src/inventory.cpp
src/inventory.h
src/irrlichtwrapper.cpp
src/irrlichtwrapper.h
src/main.cpp
src/mapblock.cpp
src/mapnode.cpp
src/mapnode.h
src/mineral.cpp [new file with mode: 0644]
src/mineral.h
src/player.cpp
src/player.h
src/server.cpp
src/server.h
src/texture.h [new file with mode: 0644]
src/tile.h
src/utility.h

index 88336c01383752157b9842bd5e0a7230cc47b546..8fe9078caffee8e3a78b9ccd6b70b1782ad8955d 100644 (file)
Binary files a/data/grass.png and b/data/grass.png differ
index ee12491e8deb8177f481b7038ae3d908b734e966..7bacbfb5efe30f092fdde40e89c924f1b7a6cdac 100644 (file)
Binary files a/data/grass_side.png and b/data/grass_side.png differ
index 71dc5763a266c4729fd2850f3bf841dc92019a01..68c6fced79916e6eac2c04ee3acf37422c09329e 100644 (file)
                                RelativePath=".\src\materials.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\src\mineral.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\src\player.cpp"\r
                                >\r
index 7913f496426b190c7ec39b114816f96cdcab0588..d027c7cd96b3452c71b179558b238bdcdc9ee4f8 100644 (file)
@@ -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(
index 51ed05422fbdb22424b63207e0da818c88f5d5ad..9d64ff58a48c9483c79dcb6473ca2da8375b1f63 100644 (file)
@@ -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)
 {
index fa7253170b49779fa2af3e7a6538f566211e5781..dfc60673b66698c1b1bc82ff47301079b97cdd66 100644 (file)
@@ -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);
index 713adefdf70ec416ce1e53f445015b486f0e5700..cbe66edb00b623c255891c6e7f85983aa0e07e94 100644 (file)
@@ -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;
                }
index 797a675094a342ea77b94d311d2158e96dd2df5f..e7c7adaee3b3d194d2b6572d52a7f7f1606f69e9 100644 (file)
@@ -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;
index 4e1ebdd74e977af28298e3f44c08659c6f8ba7f4..e5cab98c6cf41838207720636dd82f0deb9fbcdb 100644 (file)
@@ -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
 }
 
 
index 2506af012833bffd7a26415f36916e2010bbd0e0..a695bd1e4e5fc9d1df1b2d6cdf5d2c7bac83e0cb 100644 (file)
@@ -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
index 388ab8089eeb166888f48b80b88993fdeb892130..0dc822474ec9e61b0903564d9cbccfe8d09132d7 100644 (file)
@@ -104,8 +104,11 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
 Gaming ideas:\r
 -------------\r
 \r
-- Aim for something like controlling a single dwarf in Dwarf Fortress.\r
+- Aim for something like controlling a single dwarf in Dwarf Fortress\r
 \r
+- The player could go faster by a crafting a boat, or riding an animal\r
+\r
+- Random NPC traders. what else?\r
 \r
 Documentation:\r
 --------------\r
@@ -165,6 +168,20 @@ TODO: Make fetching sector's blocks more efficient when rendering
 \r
 TODO: Flowing water animation\r
 \r
+FIXME: The new texture stuff is slow on wine\r
+       - A basic grassy ground block takes 20-40ms\r
+       - A bit more complicated block can take 270ms\r
+         - On linux, a similar one doesn't take long at all (14ms)\r
+           - It is NOT a bad std::string implementation of MSVC.\r
+       - Can take up to 200ms? Is it when loading textures or always?\r
+       - Updating excess amount of meshes when making footprints is too\r
+         slow. It has to be fixed.\r
+         -> implement Map::updateNodeMeshes()\r
+       The fix:\r
+    * Optimize TileSpec to only contain a reference number that\r
+         is fast to compare, which refers to a cached string, or\r
+       * Make TextureSpec for using instead of strings\r
+\r
 Configuration:\r
 --------------\r
 \r
@@ -281,18 +298,6 @@ TODO: Flowing water to actually contain flow direction information
 TODO: Remove duplicate lighting implementation from Map (leave\r
       VoxelManipulator, which is faster)\r
 \r
-FIXME: The new texture stuff is slow on wine\r
-       - A basic grassy ground block takes 20-40ms\r
-       - A bit more complicated block can take 270ms\r
-         - On linux, a similar one doesn't take long at all (14ms)\r
-           - Is it a bad std::string implementation of MSVC?\r
-       - Can take up to 200ms? Is it when loading textures or always?\r
-       - Updating excess amount of meshes when making footprints is too\r
-         slow. It has to be fixed.\r
-         -> implement Map::updateNodeMeshes()\r
-       TODO: Optimize TileSpec to only contain a reference number that\r
-             is fast to compare, which refers to a cached string\r
-\r
 Doing now:\r
 ----------\r
 \r
@@ -360,6 +365,7 @@ Doing now:
 #include "filesys.h"\r
 #include "config.h"\r
 #include "guiMainMenu.h"\r
+#include "mineral.h"\r
 \r
 IrrlichtWrapper *g_irrlicht;\r
 \r
@@ -1445,7 +1451,6 @@ int main(int argc, char *argv[])
        \r
        // C-style stuff initialization\r
        initializeMaterialProperties();\r
-       init_mapnode();\r
 \r
        // Debug handler\r
        BEGIN_DEBUG_EXCEPTION_HANDLER\r
@@ -1683,7 +1688,8 @@ int main(int argc, char *argv[])
        */\r
 \r
        init_content_inventory_texture_paths();\r
-       //init_tile_textures();\r
+       init_mapnode(g_irrlicht);\r
+       init_mineral(g_irrlicht);\r
 \r
        /*\r
                GUI stuff\r
@@ -2378,7 +2384,7 @@ int main(int argc, char *argv[])
                bool nodefound = false;\r
                v3s16 nodepos;\r
                v3s16 neighbourpos;\r
-               core::aabbox3d<f32> nodefacebox;\r
+               core::aabbox3d<f32> nodehilightbox;\r
                f32 mindistance = BS * 1001;\r
                \r
                v3s16 pos_i = floatToInt(player_position);\r
@@ -2470,7 +2476,7 @@ int main(int argc, char *argv[])
                                                nodepos = np;\r
                                                neighbourpos = np;\r
                                                mindistance = distance;\r
-                                               nodefacebox = box;\r
+                                               nodehilightbox = box;\r
                                        }\r
                                }\r
                        }\r
@@ -2513,7 +2519,16 @@ int main(int argc, char *argv[])
                                                        nodepos = np;\r
                                                        neighbourpos = np + dirs[i];\r
                                                        mindistance = distance;\r
-                                                       nodefacebox = facebox;\r
+\r
+                                                       //nodehilightbox = facebox;\r
+\r
+                                                       const float d = 0.502;\r
+                                                       core::aabbox3d<f32> nodebox\r
+                                                                       (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
+                                                       v3f nodepos_f = intToFloat(nodepos);\r
+                                                       nodebox.MinEdge += nodepos_f;\r
+                                                       nodebox.MaxEdge += nodepos_f;\r
+                                                       nodehilightbox = nodebox;\r
                                                }\r
                                        } // if distance < mindistance\r
                                } // for dirs\r
@@ -2531,15 +2546,7 @@ int main(int argc, char *argv[])
                        \r
                        // Visualize selection\r
 \r
-                       const float d = 0.502;\r
-                       core::aabbox3d<f32> nodebox(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
-                       v3f nodepos_f = intToFloat(nodepos);\r
-                       //v3f nodepos_f(nodepos.X*BS, nodepos.Y*BS, nodepos.Z*BS);\r
-                       nodebox.MinEdge += nodepos_f;\r
-                       nodebox.MaxEdge += nodepos_f;\r
-                       hilightboxes.push_back(nodebox);\r
-                       \r
-                       //hilightboxes.push_back(nodefacebox);\r
+                       hilightboxes.push_back(nodehilightbox);\r
 \r
                        // Handle digging\r
                        \r
index f06dbc81120ab98e99867c91e714d3b6cf4e009b..b346b098090ffd5edd055ae8e8a662c4ad017752 100644 (file)
@@ -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);
                        }
                }
        }
index 7625fab68f31a74d61654a3b1eef31b017320dde..d197454fee0b25098ec80a4958b53d6c99ff1ac3 100644 (file)
@@ -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();
-       }
+       }*/
 }
 
index c69436c9ed19ec09547ba02778c788e0d0840d30..0c52681be02df2d052ce8bfbb6d564c6d4fb59c5 100644 (file)
@@ -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 (file)
index 0000000..506f5b7
--- /dev/null
@@ -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];
+}
+
+
index e43e48ab88076f66b655947235bd2da4edb2d038..aa0902e122b8dc1ba6a69cbbfff4c39e9563c33d 100644 (file)
@@ -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)
 {
index 8aabb030c24f84f46fd7822b813beff0bc1376f4..b260e5056063efdb77be45fea7050240ef3610e8 100644 (file)
@@ -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
 */
index 9330bdd54300e0a7c6a25fb5fc2e2a89fc8fb629..5ab027e0abeec6ddad486e440e219f2db656a506 100644 (file)
@@ -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
index 541582b65789ee565b3a73260d005b79bd70af61..823a48b900b7d86b2424b26ea8627545ddb6878c 100644 (file)
@@ -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);
index a3e1897d9360d23dd270fcfc0b4b463c70adf840..fcc37631fb62b9f9e773009bceabedcafe4f341a 100644 (file)
@@ -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 (file)
index 0000000..f14efae
--- /dev/null
@@ -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
index b903d92a823f30e41ad79e89d3a1b100ea9feb68..ff495abc4969112e88404af493d07ef4bbe9dcfb 100644 (file)
@@ -22,8 +22,26 @@ 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
+{
+       TileSpec():
+               alpha(255)
+       {
+       }
+
+       bool operator==(TileSpec &other)
+       {
+               return (spec == other.spec && alpha == other.alpha);
+       }
+       
+       TextureSpec spec;
+       u8 alpha;
+};
+
+#if 0
 struct TileSpec
 {
        TileSpec():
@@ -52,5 +70,6 @@ struct TileSpec
        std::string name;
        u8 alpha;
 };
+#endif
 
 #endif
index b517848b1223440d9dc3564d3d3828134075405e..4f74a0649a20178b6c109d30d83132a8f3d5dbbd 100644 (file)
@@ -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