139 changes: 45 additions & 94 deletions src/itemdef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ class CItemDefManager: public IWritableItemDefManager
inventory_texture(NULL),
palette(NULL)
{}

~ClientCached() {
if (wield_mesh.mesh)
wield_mesh.mesh->drop();
}

DISABLE_CLASS_COPY(ClientCached);
};
#endif

Expand All @@ -265,17 +272,9 @@ class CItemDefManager: public IWritableItemDefManager
#endif
clear();
}

virtual ~CItemDefManager()
{
#ifndef SERVER
const std::vector<ClientCached*> &values = m_clientcached.getValues();
for (ClientCached *cc : values) {
if (cc->wield_mesh.mesh)
cc->wield_mesh.mesh->drop();
delete cc;
}

#endif
for (auto &item_definition : m_item_definitions) {
delete item_definition.second;
}
Expand Down Expand Up @@ -319,103 +318,72 @@ class CItemDefManager: public IWritableItemDefManager
}
#ifndef SERVER
public:
ClientCached* createClientCachedDirect(const std::string &name,
Client *client) const
ClientCached* createClientCachedDirect(const ItemStack &item, Client *client) const
{
infostream<<"Lazily creating item texture and mesh for \""
<<name<<"\""<<std::endl;

// This is not thread-safe
sanity_check(std::this_thread::get_id() == m_main_thread);

const ItemDefinition &def = item.getDefinition(this);
std::string inventory_image = item.getInventoryImage(this);
std::string inventory_overlay = item.getInventoryOverlay(this);
std::string cache_key = def.name;
if (!inventory_image.empty())
cache_key += "/" + inventory_image;
if (!inventory_overlay.empty())
cache_key += ":" + inventory_overlay;

infostream << "Lazily creating item texture and mesh for \""
<< cache_key << "\""<<std::endl;

// Skip if already in cache
ClientCached *cc = NULL;
m_clientcached.get(name, &cc);
if(cc)
return cc;
auto it = m_clientcached.find(cache_key);
if (it != m_clientcached.end())
return it->second.get();

ITextureSource *tsrc = client->getTextureSource();
const ItemDefinition &def = get(name);

// Create new ClientCached
cc = new ClientCached();
auto cc = std::make_unique<ClientCached>();

// Create an inventory texture
cc->inventory_texture = NULL;
if (!def.inventory_image.empty())
cc->inventory_texture = tsrc->getTexture(def.inventory_image);

ItemStack item = ItemStack();
item.name = def.name;

if (!inventory_image.empty())
cc->inventory_texture = tsrc->getTexture(inventory_image);
getItemMesh(client, item, &(cc->wield_mesh));

cc->palette = tsrc->getPalette(def.palette_image);

// Put in cache
m_clientcached.set(name, cc);

return cc;
ClientCached *ptr = cc.get();
m_clientcached[cache_key] = std::move(cc);
return ptr;
}
ClientCached* getClientCached(const std::string &name,
Client *client) const
{
ClientCached *cc = NULL;
m_clientcached.get(name, &cc);
if (cc)
return cc;

if (std::this_thread::get_id() == m_main_thread) {
return createClientCachedDirect(name, client);
}

// We're gonna ask the result to be put into here
static ResultQueue<std::string, ClientCached*, u8, u8> result_queue;

// Throw a request in
m_get_clientcached_queue.add(name, 0, 0, &result_queue);
try {
while(true) {
// Wait result for a second
GetResult<std::string, ClientCached*, u8, u8>
result = result_queue.pop_front(1000);

if (result.key == name) {
return result.item;
}
}
} catch(ItemNotFoundException &e) {
errorstream << "Waiting for clientcached " << name
<< " timed out." << std::endl;
return &m_dummy_clientcached;
}
}
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
virtual video::ITexture* getInventoryTexture(const ItemStack &item,
Client *client) const
{
ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
ClientCached *cc = createClientCachedDirect(item, client);
if (!cc)
return nullptr;
return cc->inventory_texture;
}

// Get item wield mesh
virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const
virtual ItemMesh* getWieldMesh(const ItemStack &item, Client *client) const
{
ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
ClientCached *cc = createClientCachedDirect(item, client);
if (!cc)
return nullptr;
return &(cc->wield_mesh);
}

// Get item palette
virtual Palette* getPalette(const std::string &name,
Client *client) const
virtual Palette* getPalette(const ItemStack &item, Client *client) const
{
ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
ClientCached *cc = createClientCachedDirect(item, client);
if (!cc)
return nullptr;
return cc->palette;
}

Expand All @@ -428,7 +396,7 @@ class CItemDefManager: public IWritableItemDefManager
if (!colorstring.empty() && parseColorString(colorstring, directcolor, true))
return directcolor;
// See if there is a palette
Palette *palette = getPalette(stack.name, client);
Palette *palette = getPalette(stack, client);
const std::string &index = stack.metadata.getString("palette_index", 0);
if (palette && !index.empty())
return (*palette)[mystoi(index, 0, 255)];
Expand Down Expand Up @@ -573,20 +541,7 @@ class CItemDefManager: public IWritableItemDefManager
registerAlias(name, convert_to);
}
}
void processQueue(IGameDef *gamedef)
{
#ifndef SERVER
//NOTE this is only thread safe for ONE consumer thread!
while(!m_get_clientcached_queue.empty())
{
GetRequest<std::string, ClientCached*, u8, u8>
request = m_get_clientcached_queue.pop();

m_get_clientcached_queue.pushResult(request,
createClientCachedDirect(request.key, (Client *)gamedef));
}
#endif
}
private:
// Key is name
std::map<std::string, ItemDefinition*> m_item_definitions;
Expand All @@ -595,12 +550,8 @@ class CItemDefManager: public IWritableItemDefManager
#ifndef SERVER
// The id of the thread that is allowed to use irrlicht directly
std::thread::id m_main_thread;
// A reference to this can be returned when nothing is found, to avoid NULLs
mutable ClientCached m_dummy_clientcached;
// Cached textures and meshes
mutable MutexedMap<std::string, ClientCached*> m_clientcached;
// Queued clientcached fetches (to be processed by the main thread)
mutable RequestQueue<std::string, ClientCached*, u8, u8> m_get_clientcached_queue;
mutable std::unordered_map<std::string, std::unique_ptr<ClientCached>> m_clientcached;
#endif
};

Expand Down
37 changes: 9 additions & 28 deletions src/itemdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ class IItemDefManager
virtual bool isKnown(const std::string &name) const=0;
#ifndef SERVER
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
Client *client) const=0;
// Get item wield mesh
virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const=0;
virtual video::ITexture* getInventoryTexture(const ItemStack &item, Client *client) const=0;

/**
* Get wield mesh
*
* Returns nullptr if there is an inventory image
*/
virtual ItemMesh* getWieldMesh(const ItemStack &item, Client *client) const = 0;
// Get item palette
virtual Palette* getPalette(const std::string &name,
Client *client) const = 0;
virtual Palette* getPalette(const ItemStack &item, Client *client) const = 0;
// Returns the base color of an item stack: the color of all
// tiles that do not define their own color.
virtual video::SColor getItemstackColor(const ItemStack &stack,
Expand All @@ -144,23 +146,6 @@ class IWritableItemDefManager : public IItemDefManager

virtual ~IWritableItemDefManager() = default;

// Get item definition
virtual const ItemDefinition& get(const std::string &name) const=0;
// Get alias definition
virtual const std::string &getAlias(const std::string &name) const=0;
// Get set of all defined item names and aliases
virtual void getAll(std::set<std::string> &result) const=0;
// Check if item is known
virtual bool isKnown(const std::string &name) const=0;
#ifndef SERVER
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
Client *client) const=0;
// Get item wield mesh
virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const=0;
#endif

// Replace the textures of registered nodes with the ones specified in
// the texture pack's override.txt files
virtual void applyTextureOverrides(const std::vector<TextureOverride> &overrides)=0;
Expand All @@ -177,11 +162,7 @@ class IWritableItemDefManager : public IItemDefManager
virtual void registerAlias(const std::string &name,
const std::string &convert_to)=0;

virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual void deSerialize(std::istream &is, u16 protocol_version)=0;

// Do stuff asked by threads that can only be done in the main thread
virtual void processQueue(IGameDef *gamedef)=0;
};

IWritableItemDefManager* createItemDefManager();
8 changes: 1 addition & 7 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,13 +562,7 @@ v2f Settings::getV2F(const std::string &name) const

v3f Settings::getV3F(const std::string &name) const
{
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;
return str_to_v3f(get(name));
}


Expand Down
13 changes: 13 additions & 0 deletions src/util/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hex.h"
#include "porting.h"
#include "translation.h"
#include "strfnd.h"

#include <algorithm>
#include <array>
Expand Down Expand Up @@ -897,3 +898,15 @@ void safe_print_string(std::ostream &os, const std::string &str)
}
os.setf(flags);
}


v3f str_to_v3f(const std::string &str)
{
v3f value;
Strfnd f(str);
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(","));
value.Z = stof(f.next(")"));
return value;
}
8 changes: 8 additions & 0 deletions src/util/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -765,3 +765,11 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_
* brackets (e.g. "a\x1eb" -> "a<1e>b").
*/
void safe_print_string(std::ostream &os, const std::string &str);

/**
* Parses a string of form `(1, 2, 3)` to a v3f
*
* @param str String
* @return
*/
v3f str_to_v3f(const std::string &str);