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