aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/client.h2
-rw-r--r--src/client/tile.cpp118
-rw-r--r--src/network/clientpackethandler.cpp11
3 files changed, 86 insertions, 45 deletions
diff --git a/src/client/client.h b/src/client/client.h
index 3c7fc0db2..44a0de719 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -552,8 +552,6 @@ private:
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;
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index d36459bb2..35e5585a0 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -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 @@ private:
// 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());
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 8a323872a..9c9d8276e 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -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);