]> git.lizzy.rs Git - minetest.git/commitdiff
Source image tracking in tile generation (#12514)
author20kdc <asdd2808@gmail.com>
Fri, 17 Feb 2023 23:03:03 +0000 (23:03 +0000)
committerGitHub <noreply@github.com>
Fri, 17 Feb 2023 23:03:03 +0000 (00:03 +0100)
src/client/client.h
src/client/tile.cpp
src/network/clientpackethandler.cpp

index 3c7fc0db2de95703bc1ffddc5d69aaea1fd2fc83..44a0de719d7ae68b729cb1694db57bbe3edeb36d 100644 (file)
@@ -552,8 +552,6 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        std::vector<std::string> m_remote_media_servers;
        // Media downloader, only exists during init
        ClientMediaDownloader *m_media_downloader;
-       // Set of media filenames pushed by server at runtime
-       std::unordered_set<std::string> m_media_pushed_files;
        // Pending downloads of dynamic media (key: token)
        std::vector<std::pair<u32, std::shared_ptr<SingleMediaDownloader>>> m_pending_media_downloads;
 
index d36459bb25116ca337da5caeab1c64313a079091..35e5585a0052c20834599c26097e1f221b4efdce 100644 (file)
@@ -171,6 +171,7 @@ struct TextureInfo
 {
        std::string name;
        video::ITexture *texture;
+       std::set<std::string> sourceImages;
 
        TextureInfo(
                        const std::string &name_,
@@ -180,6 +181,17 @@ struct TextureInfo
                texture(texture_)
        {
        }
+
+       TextureInfo(
+                       const std::string &name_,
+                       video::ITexture *texture_,
+                       std::set<std::string> &sourceImages_
+               ):
+               name(name_),
+               texture(texture_),
+               sourceImages(sourceImages_)
+       {
+       }
 };
 
 /*
@@ -379,19 +391,26 @@ class TextureSource : public IWritableTextureSource
        // This should be only accessed from the main thread
        SourceImageCache m_sourcecache;
 
+       // Rebuild images and textures from the current set of source images
+       // Shall be called from the main thread.
+       // You ARE expected to be holding m_textureinfo_cache_mutex
+       void rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti);
+
        // Generate a texture
        u32 generateTexture(const std::string &name);
 
        // Generate image based on a string like "stone.png" or "[crack:1:0".
        // if baseimg is NULL, it is created. Otherwise stuff is made on it.
-       bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);
+       // source_image_names is important to determine when to flush the image from a cache (dynamic media)
+       bool generateImagePart(std::string part_of_name, video::IImage *& baseimg, std::set<std::string> &source_image_names);
 
        /*! Generates an image from a full string like
         * "stone.png^mineral_coal.png^[crack:1:0".
         * Shall be called from the main thread.
         * The returned Image should be dropped.
+        * source_image_names is important to determine when to flush the image from a cache (dynamic media)
         */
-       video::IImage* generateImage(const std::string &name);
+       video::IImage* generateImage(const std::string &name, std::set<std::string> &source_image_names);
 
        // Thread-safe cache of what source images are known (true = known)
        MutexedMap<std::string, bool> m_source_image_existence;
@@ -592,7 +611,9 @@ u32 TextureSource::generateTexture(const std::string &name)
        video::IVideoDriver *driver = RenderingEngine::get_video_driver();
        sanity_check(driver);
 
-       video::IImage *img = generateImage(name);
+       // passed into texture info for dynamic media tracking
+       std::set<std::string> source_image_names;
+       video::IImage *img = generateImage(name, source_image_names);
 
        video::ITexture *tex = NULL;
 
@@ -613,7 +634,7 @@ u32 TextureSource::generateTexture(const std::string &name)
        MutexAutoLock lock(m_textureinfo_cache_mutex);
 
        u32 id = m_textureinfo_cache.size();
-       TextureInfo ti(name, tex);
+       TextureInfo ti(name, tex, source_image_names);
        m_textureinfo_cache.push_back(ti);
        m_name_to_id[name] = id;
 
@@ -677,7 +698,8 @@ Palette* TextureSource::getPalette(const std::string &name)
        auto it = m_palettes.find(name);
        if (it == m_palettes.end()) {
                // Create palette
-               video::IImage *img = generateImage(name);
+               std::set<std::string> source_image_names; // unused, sadly.
+               video::IImage *img = generateImage(name, source_image_names);
                if (!img) {
                        warningstream << "TextureSource::getPalette(): palette \"" << name
                                << "\" could not be loaded." << std::endl;
@@ -749,6 +771,26 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
 
        m_sourcecache.insert(name, img, true);
        m_source_image_existence.set(name, true);
+
+       // now we need to check for any textures that need updating
+       MutexAutoLock lock(m_textureinfo_cache_mutex);
+
+       video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+       sanity_check(driver);
+
+       // Recreate affected textures
+       u32 affected = 0;
+       for (TextureInfo &ti : m_textureinfo_cache) {
+               if (ti.name.empty())
+                       continue; // Skip dummy entry
+               // If the source image was used, we need to rebuild this texture
+               if (ti.sourceImages.find(name) != ti.sourceImages.end()) {
+                       rebuildTexture(driver, ti);
+                       affected++;
+               }
+       }
+       if (affected > 0)
+               verbosestream << "TextureSource: inserting \"" << name << "\" caused rebuild of " << affected << " textures." << std::endl;
 }
 
 void TextureSource::rebuildImagesAndTextures()
@@ -765,25 +807,36 @@ void TextureSource::rebuildImagesAndTextures()
        for (TextureInfo &ti : m_textureinfo_cache) {
                if (ti.name.empty())
                        continue; // Skip dummy entry
+               rebuildTexture(driver, ti);
+       }
+}
 
-               video::IImage *img = generateImage(ti.name);
+void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
+{
+       if (ti.name.empty())
+               return; // this shouldn't happen, just a precaution
+
+       // replaces the previous sourceImages
+       // shouldn't really need to be done, but can't hurt
+       std::set<std::string> source_image_names;
+       video::IImage *img = generateImage(ti.name, source_image_names);
 #if ENABLE_GLES
-               img = Align2Npot2(img, driver);
+       img = Align2Npot2(img, driver);
 #endif
-               // Create texture from resulting image
-               video::ITexture *t = NULL;
-               if (img) {
-                       t = driver->addTexture(ti.name.c_str(), img);
-                       guiScalingCache(io::path(ti.name.c_str()), driver, img);
-                       img->drop();
-               }
-               video::ITexture *t_old = ti.texture;
-               // Replace texture
-               ti.texture = t;
-
-               if (t_old)
-                       m_texture_trash.push_back(t_old);
+       // Create texture from resulting image
+       video::ITexture *t = NULL;
+       if (img) {
+               t = driver->addTexture(ti.name.c_str(), img);
+               guiScalingCache(io::path(ti.name.c_str()), driver, img);
+               img->drop();
        }
+       video::ITexture *t_old = ti.texture;
+       // Replace texture
+       ti.texture = t;
+       ti.sourceImages = source_image_names;
+
+       if (t_old)
+               m_texture_trash.push_back(t_old);
 }
 
 inline static void applyShadeFactor(video::SColor &color, u32 factor)
@@ -901,7 +954,7 @@ static video::IImage *createInventoryCubeImage(
        return result;
 }
 
-video::IImage* TextureSource::generateImage(const std::string &name)
+video::IImage* TextureSource::generateImage(const std::string &name, std::set<std::string> &source_image_names)
 {
        // Get the base image
 
@@ -954,7 +1007,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
                using a recursive call.
        */
        if (last_separator_pos != -1) {
-               baseimg = generateImage(name.substr(0, last_separator_pos));
+               baseimg = generateImage(name.substr(0, last_separator_pos), source_image_names);
        }
 
        /*
@@ -972,7 +1025,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
                        && last_part_of_name[last_part_of_name.size() - 1] == paren_close) {
                std::string name2 = last_part_of_name.substr(1,
                                last_part_of_name.size() - 2);
-               video::IImage *tmp = generateImage(name2);
+               video::IImage *tmp = generateImage(name2, source_image_names);
                if (!tmp) {
                        errorstream << "generateImage(): "
                                "Failed to generate \"" << name2 << "\""
@@ -987,7 +1040,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
                } else {
                        baseimg = tmp;
                }
-       } else if (!generateImagePart(last_part_of_name, baseimg)) {
+       } else if (!generateImagePart(last_part_of_name, baseimg, source_image_names)) {
                // Generate image according to part of name
                errorstream << "generateImage(): "
                                "Failed to generate \"" << last_part_of_name << "\""
@@ -1101,7 +1154,7 @@ void blitBaseImage(video::IImage* &src, video::IImage* &dst)
 }
 
 bool TextureSource::generateImagePart(std::string part_of_name,
-               video::IImage *& baseimg)
+               video::IImage *& baseimg, std::set<std::string> &source_image_names)
 {
        const char escape = '\\'; // same as in generateImage()
        video::IVideoDriver *driver = RenderingEngine::get_video_driver();
@@ -1109,6 +1162,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
 
        // Stuff starting with [ are special commands
        if (part_of_name.empty() || part_of_name[0] != '[') {
+               source_image_names.insert(part_of_name);
                video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
                if (image == NULL) {
                        if (!part_of_name.empty()) {
@@ -1246,7 +1300,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
                                infostream<<"Adding \""<<filename
                                                <<"\" to combined ("<<x<<","<<y<<")"
                                                <<std::endl;
-                               video::IImage *img = generateImage(filename);
+                               video::IImage *img = generateImage(filename, source_image_names);
                                if (img) {
                                        core::dimension2d<u32> dim = img->getDimension();
                                        core::position2d<s32> pos_base(x, y);
@@ -1410,15 +1464,15 @@ bool TextureSource::generateImagePart(std::string part_of_name,
                        std::string imagename_right = sf.next("{");
 
                        // Generate images for the faces of the cube
-                       video::IImage *img_top = generateImage(imagename_top);
-                       video::IImage *img_left = generateImage(imagename_left);
-                       video::IImage *img_right = generateImage(imagename_right);
+                       video::IImage *img_top = generateImage(imagename_top, source_image_names);
+                       video::IImage *img_left = generateImage(imagename_left, source_image_names);
+                       video::IImage *img_right = generateImage(imagename_right, source_image_names);
 
                        if (img_top == NULL || img_left == NULL || img_right == NULL) {
                                errorstream << "generateImagePart(): Failed to create textures"
                                                << " for inventorycube \"" << part_of_name << "\""
                                                << std::endl;
-                               baseimg = generateImage(imagename_top);
+                               baseimg = generateImage(imagename_top, source_image_names);
                                return true;
                        }
 
@@ -1444,7 +1498,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
 
                        if (baseimg == NULL)
                                baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
-                       video::IImage *img = generateImage(filename);
+                       video::IImage *img = generateImage(filename, source_image_names);
                        if (img)
                        {
                                core::dimension2d<u32> dim = img->getDimension();
@@ -1526,7 +1580,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
                        sf.next(":");
                        std::string filename = unescape_string(sf.next_esc(":", escape), escape);
 
-                       video::IImage *img = generateImage(filename);
+                       video::IImage *img = generateImage(filename, source_image_names);
                        if (img) {
                                apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
                                                img->getDimension());
index 8a323872ac0c0a2a9c54fbed9bc4017a4ecb1faf..9c9d8276e834ea3600c598f78a111ab18b3229ca 100644 (file)
@@ -1592,14 +1592,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
                verbosestream << "with " << filedata.size() << " bytes ";
        verbosestream << "(cached=" << cached << ")" << std::endl;
 
-       if (m_media_pushed_files.count(filename) != 0) {
-               // Ignore (but acknowledge). Previously this was for sync purposes,
-               // but even in new versions media cannot be replaced at runtime.
-               if (m_proto_ver >= 40)
-                       sendHaveMedia({ token });
-               return;
-       }
-
        if (!filedata.empty()) {
                // LEGACY CODEPATH
                // Compute and check checksum of data
@@ -1618,7 +1610,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
 
                // Actually load media
                loadMedia(filedata, filename, true);
-               m_media_pushed_files.insert(filename);
 
                // Cache file for the next time when this client joins the same server
                if (cached)
@@ -1626,8 +1617,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
                return;
        }
 
-       m_media_pushed_files.insert(filename);
-
        // create a downloader for this file
        auto downloader(std::make_shared<SingleMediaDownloader>(cached));
        m_pending_media_downloads.emplace_back(token, downloader);