Changed: Cache extra item info responses from server

--HG--
branch : feature-item-icon-buffs
hg/atys
Nimetu 6 years ago
parent 4636e32885
commit e0a1cd3c4a

@ -4493,6 +4493,13 @@ NLMISC_COMMAND(debugItemInfoWaiters, "log ItemInfoWaiters", "")
return true; return true;
} }
NLMISC_COMMAND(debugItemInfoCache, "log ItemInfoCache", "")
{
getInventory().debugItemInfoCache();
return true;
}
NLMISC_COMMAND(debugInfoWindows, "log info windows sheetId", "") NLMISC_COMMAND(debugInfoWindows, "log info windows sheetId", "")
{ {
CInterfaceHelp::debugOpenedInfoWindows(); CInterfaceHelp::debugOpenedInfoWindows();

@ -58,6 +58,8 @@
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
extern TSessionId CharacterHomeSessionId;
extern NLMISC::CLog g_log; extern NLMISC::CLog g_log;
// Context help // Context help
extern void contextHelp (const std::string &help); extern void contextHelp (const std::string &help);
@ -156,6 +158,144 @@ void CItemImage::build(CCDBNodeBranch *branch)
nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion); nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion);
} }
uint64 CItemImage::getItemId() const
{
return ((uint64)getSerial() << 32) | getCreateTime();
}
// *************************************************************************************************
void CItemInfoCache::load(const std::string &filename)
{
try
{
CIFile f;
if (f.open(filename))
{
serial(f);
}
} catch(...)
{ }
}
void CItemInfoCache::save(const std::string &filename)
{
try
{
COFile f;
if (f.open(filename))
{
serial(f);
}
}catch(...)
{ }
}
void CItemInfoCache::serial(NLMISC::IStream &s)
{
s.serialCheck(NELID("METI"));
uint ver = 1;
s.serialVersion(ver);
uint8 byte = 1;
if (s.isReading())
{
_ItemInfoCacheMap.clear();
while(true)
{
uint64 key;
s.serial(byte);
if (byte == 0)
{
break;
}
s.serial(key);
s.serial(_ItemInfoCacheMap[key].CacheCycle);
_ItemInfoCacheMap[key].serial(s);
// these are not used in item info cache
_ItemInfoCacheMap[key].InfoVersionFromMsg = 0;
_ItemInfoCacheMap[key].InfoVersionFromSlot = 0;
_ItemInfoCacheMap[key].InfoVersionSlotServerWaiting = 0;
}
}
else
{
byte = 1;
TItemInfoCacheMap::iterator it = _ItemInfoCacheMap.begin();
while (it != _ItemInfoCacheMap.end())
{
// purge item from cache if not encountered in X save
if (it->second.CacheCycle < 10000)
{
// 'record exists' byte
s.serial(byte);
// item id (serial << 32 | createTime)
uint64 key = it->first;
s.serial(key);
uint32 cycle = it->second.CacheCycle+1;
s.serial(cycle);
// item info
it->second.serial(s);
}
++it;
}
// eof of records byte
byte = 0;
s.serial(byte);
}
}
const CClientItemInfo *CItemInfoCache::getItemInfo(uint32 serial, uint32 createTime) const
{
if (serial > 0 && createTime > 0)
{
uint64 itemId = ((uint64)serial << 32) | createTime;
return getItemInfo(itemId);
}
return NULL;
}
const CClientItemInfo *CItemInfoCache::getItemInfo(uint64 itemId) const
{
if (itemId > 0)
{
TItemInfoCacheMap::const_iterator it = _ItemInfoCacheMap.find(itemId);
if (it != _ItemInfoCacheMap.end())
return &(it->second);
}
return NULL;
}
void CItemInfoCache::readFromImpulse(uint64 itemId, CItemInfos itemInfo)
{
if (itemId > 0)
{
_ItemInfoCacheMap[itemId].readFromImpulse(itemInfo);
_ItemInfoCacheMap[itemId].CacheCycle = 0;
}
}
void CItemInfoCache::debugItemInfoCache() const
{
nlinfo("ItemInfoCache: %d entries", _ItemInfoCacheMap.size());
uint count = 0;
for (auto it = _ItemInfoCacheMap.begin(); it != _ItemInfoCacheMap.end(); ++it)
{
uint32 serial = (it->first >> 32) & 0xFFFFFFFF;
uint32 created = it->first & 0xFFFFFFFF;
nlinfo("[%-4d] cacheCycle:%d, serial:%d, createTime:%d", count++, it->second.CacheCycle, serial, created);
}
CInterfaceManager *pIM= CInterfaceManager::getInstance();
pIM->displaySystemInfo(toString("ItemInfoCache: %d entries written to client.log", _ItemInfoCacheMap.size()));
}
// ************************************************************************************************* // *************************************************************************************************
// CInventoryManager // CInventoryManager
// ************************************************************************************************* // *************************************************************************************************
@ -184,12 +324,16 @@ CInventoryManager::CInventoryManager()
BagItemEquipped[i]= false; BagItemEquipped[i]= false;
} }
_ItemInfoCacheFilename = toString("save/item_infos_%d.cache", CharacterHomeSessionId.asInt());
_ItemInfoCache.load(_ItemInfoCacheFilename);
nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0])); nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0]));
} }
// *************************************************************************** // ***************************************************************************
CInventoryManager::~CInventoryManager() CInventoryManager::~CInventoryManager()
{ {
_ItemInfoCache.save(_ItemInfoCacheFilename);
} }
// ************************************************************************************************* // *************************************************************************************************
@ -261,6 +405,11 @@ CItemImage &CInventoryManager::getServerBagItem(uint index)
nlassert(index < MAX_BAGINV_ENTRIES); nlassert(index < MAX_BAGINV_ENTRIES);
return ServerBag[index]; return ServerBag[index];
} }
const CItemImage &CInventoryManager::getServerBagItem(uint index) const
{
nlassert(index < MAX_BAGINV_ENTRIES);
return ServerBag[index];
}
// ************************************************************************************************* // *************************************************************************************************
CItemImage &CInventoryManager::getServerTempItem(uint index) CItemImage &CInventoryManager::getServerTempItem(uint index)
@ -268,6 +417,11 @@ CItemImage &CInventoryManager::getServerTempItem(uint index)
nlassert(index < MAX_TEMPINV_ENTRIES); nlassert(index < MAX_TEMPINV_ENTRIES);
return ServerTempInv[index]; return ServerTempInv[index];
} }
const CItemImage &CInventoryManager::getServerTempItem(uint index) const
{
nlassert(index < MAX_TEMPINV_ENTRIES);
return ServerTempInv[index];
}
// ************************************************************************************************* // *************************************************************************************************
CItemImage *CInventoryManager::getServerHandItem(uint index) CItemImage *CInventoryManager::getServerHandItem(uint index)
@ -3266,22 +3420,53 @@ uint CInventoryManager::getItemSheetForSlotId(uint slotId) const
return 0; return 0;
} }
// ***************************************************************************
const CClientItemInfo *CInventoryManager::getItemInfoCache(uint32 serial, uint32 createTime) const
{
return _ItemInfoCache.getItemInfo(serial, createTime);
}
// *************************************************************************** // ***************************************************************************
const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const
{ {
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId); TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
static CClientItemInfo empty; static CClientItemInfo empty;
if(it==_ItemInfoMap.end()) if (it == _ItemInfoMap.end() || !isItemInfoUpToDate(slotId))
{
// if slot has not been populated yet or out of date, then return info from cache if possible
const CItemImage *item = getServerItem(slotId);
if (item && item->getItemId() > 0) {
const CClientItemInfo *ret = _ItemInfoCache.getItemInfo(item->getItemId());
if (ret != NULL)
{
return *ret;
}
}
}
if (it == _ItemInfoMap.end())
{
return empty; return empty;
else }
return it->second; return it->second;
} }
// *************************************************************************** // ***************************************************************************
bool CInventoryManager::isItemInfoUpToDate(uint slotId) bool CInventoryManager::isItemInfoAvailable(uint slotId) const
{ {
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
return it != _ItemInfoMap.end();
}
// ***************************************************************************
bool CInventoryManager::isItemInfoUpToDate(uint slotId) const
{
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
if (it == _ItemInfoMap.end())
return true;
// true if the version already matches // true if the version already matches
return getItemInfo(slotId).InfoVersionFromMsg == getItemInfo(slotId).InfoVersionFromSlot; return it->second.InfoVersionFromMsg == it->second.InfoVersionFromSlot;
} }
// *************************************************************************** // ***************************************************************************
@ -3318,8 +3503,10 @@ void CInventoryManager::removeItemInfoWaiter(IItemInfoWaiter *waiter)
void CInventoryManager::updateItemInfoWaiters(uint itemSlotId) void CInventoryManager::updateItemInfoWaiters(uint itemSlotId)
{ {
// First verify if the versions matches. If differ, no need to update waiters since not good. // First verify if the versions matches. If differ, no need to update waiters since not good.
if(getItemInfo(itemSlotId).InfoVersionFromMsg != getItemInfo(itemSlotId).InfoVersionFromSlot) if (!isItemInfoUpToDate(itemSlotId))
{
return; return;
}
bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading; bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading;
@ -3413,10 +3600,15 @@ void CInventoryManager::onReceiveItemSheet(ICDBNode* node)
// *************************************************************************** // ***************************************************************************
void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo) void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo)
{ {
uint itemSlotId;
// update the Info // update the Info
itemSlotId= itemInfo.slotId; uint itemSlotId = itemInfo.slotId;
const CItemImage *item = getServerItem(itemSlotId);
if (item && item->getItemId() > 0)
{
_ItemInfoCache.readFromImpulse(item->getItemId(), itemInfo);
}
// write in map, from DB. // write in map, from DB.
_ItemInfoMap[itemSlotId].readFromImpulse(itemInfo); _ItemInfoMap[itemSlotId].readFromImpulse(itemInfo);
@ -3430,7 +3622,7 @@ void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo)
// *************************************************************************** // ***************************************************************************
void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion) void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion)
{ {
_ItemInfoMap[slotId].refreshInfoVersion( infoVersion ); _ItemInfoMap[slotId].refreshInfoVersion(infoVersion);
} }
// *************************************************************************** // ***************************************************************************
@ -3526,6 +3718,12 @@ void CInventoryManager::debugItemInfoWaiters()
} }
} }
// ***************************************************************************
void CInventoryManager::debugItemInfoCache() const
{
_ItemInfoCache.debugItemInfoCache();
}
// *************************************************************************** // ***************************************************************************
void CInventoryManager::sortBag() void CInventoryManager::sortBag()
{ {
@ -3681,6 +3879,14 @@ CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index)
return ServerPAInv[beastIndex][index]; return ServerPAInv[beastIndex][index];
} }
const CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index) const
{
nlassert(beastIndex < MAX_INVENTORY_ANIMAL);
nlassert(index < MAX_ANIMALINV_ENTRIES);
return ServerPAInv[beastIndex][index];
}
// *************************************************************************** // ***************************************************************************
CItemImage &CInventoryManager::getLocalItem(uint inv, uint index) CItemImage &CInventoryManager::getLocalItem(uint inv, uint index)
{ {
@ -3707,6 +3913,93 @@ CItemImage &CInventoryManager::getServerItem(uint inv, uint index)
return dummy; return dummy;
} }
// ***************************************************************************
const CItemImage *CInventoryManager::getServerItem(uint slotId) const
{
uint inv, index;
getSlotInvIndex(slotId, inv, index);
if (inv == INVENTORIES::bag)
{
return &getServerBagItem(index);
}
else if (inv >= INVENTORIES::pet_animal && inv <INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
{
return &getServerPAItem(inv-INVENTORIES::pet_animal, index);
}
else if (inv == INVENTORIES::temporary)
{
return &getServerTempItem(index);
}
else if (inv == INVENTORIES::guild)
{
// player is in guild outpost or in guild hall
if (getInventory().isInventoryAvailable(INVENTORIES::guild))
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("SERVER:GUILD:INVENTORY:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
return NULL;
}
else if (inv == INVENTORIES::player_room)
{
// player is in their room
if (getInventory().isInventoryAvailable(INVENTORIES::player_room))
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
return NULL;
}
else if (inv == INVENTORIES::trading)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:TRADING:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else if (inv == INVENTORIES::exchange)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:GIVE:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else if (inv == INVENTORIES::exchange_proposition)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:RECEIVE:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else
{
nlwarning("getServerItem: invalid inventory %d for slotId %d", inv, slotId);
}
// invalid inventory
return NULL;
}
// *************************************************************************** // ***************************************************************************
CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str) CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str)
{ {
@ -3723,3 +4016,11 @@ CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &s
if (sTmp == "inv_room") return InvRoom; if (sTmp == "inv_room") return InvRoom;
return InvUnknown; return InvUnknown;
} }
// ***************************************************************************
void CInventoryManager::getSlotInvIndex(uint slotId, uint &inv, uint &index) const
{
inv = slotId >> CItemInfos::SlotIdIndexBitSize;
index = slotId & CItemInfos::SlotIdIndexBitMask;
}

@ -74,6 +74,7 @@ public:
CItemImage(); CItemImage();
// build from a branch // build from a branch
void build(NLMISC::CCDBNodeBranch *branch); void build(NLMISC::CCDBNodeBranch *branch);
uint64 getItemId() const;
// shortcuts to avoid NULL pointer tests // shortcuts to avoid NULL pointer tests
uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); } uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); }
uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); } uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); }
@ -114,11 +115,15 @@ public:
// This is the InfoVersionFromSlot when last request was sent to server // This is the InfoVersionFromSlot when last request was sent to server
uint16 InfoVersionSlotServerWaiting; uint16 InfoVersionSlotServerWaiting;
// Used to track cache age (reset on use, +1 on every save)
uint32 CacheCycle;
CClientItemInfo() CClientItemInfo()
{ {
InfoVersionFromMsg= 0; InfoVersionFromMsg= 0;
InfoVersionFromSlot= 0; InfoVersionFromSlot= 0;
InfoVersionSlotServerWaiting= 0; InfoVersionSlotServerWaiting= 0;
CacheCycle= 0;
} }
/// Set InfoVersion from Info message (info requested by the player) /// Set InfoVersion from Info message (info requested by the player)
@ -128,6 +133,25 @@ public:
void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; } void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; }
}; };
class CItemInfoCache
{
public:
void load(const std::string &filename);
void save(const std::string &filename);
void serial(NLMISC::IStream &s);
// retrieve pointer to item info or null if error
const CClientItemInfo *getItemInfo(uint32 serial, uint32 createTime) const;
const CClientItemInfo *getItemInfo(uint64 itemId) const;
// set/update item info in cache
void readFromImpulse(uint64 itemId, CItemInfos itemInfo);
void debugItemInfoCache() const;
private:
typedef std::map<uint64, CClientItemInfo> TItemInfoCacheMap;
TItemInfoCacheMap _ItemInfoCacheMap;
};
class IItemInfoWaiter class IItemInfoWaiter
{ {
@ -195,8 +219,10 @@ public:
// SERVER INVENTORY // SERVER INVENTORY
// get item of bag (local inventory) // get item of bag (local inventory)
CItemImage &getServerBagItem(uint index); CItemImage &getServerBagItem(uint index);
const CItemImage &getServerBagItem(uint index) const;
// get temporary item (local inventory) // get temporary item (local inventory)
CItemImage &getServerTempItem(uint index); CItemImage &getServerTempItem(uint index);
const CItemImage &getServerTempItem(uint index) const;
// get hand item (local inventory) // get hand item (local inventory)
CItemImage *getServerHandItem(uint index); CItemImage *getServerHandItem(uint index);
// get equip item (local inventory) // get equip item (local inventory)
@ -206,8 +232,11 @@ public:
void setServerMoney(uint64 value); void setServerMoney(uint64 value);
// get item of pack animal (server inventory). beastIndex ranges from 0 to MAX_INVENTORY_ANIMAL-1 // get item of pack animal (server inventory). beastIndex ranges from 0 to MAX_INVENTORY_ANIMAL-1
CItemImage &getServerPAItem(uint beastIndex, uint index); CItemImage &getServerPAItem(uint beastIndex, uint index);
const CItemImage &getServerPAItem(uint beastIndex, uint index) const;
// get the item Image for the given inventory. assert if bad inventory // get the item Image for the given inventory. assert if bad inventory
CItemImage &getServerItem(uint inv, uint index); CItemImage &getServerItem(uint inv, uint index);
// get the item Image for the given slotId or NULL if bad
const CItemImage *getServerItem(uint slotId) const;
// Drag'n'Drop Management // Drag'n'Drop Management
enum TFrom { Slot, TextList, IconList, Nowhere }; enum TFrom { Slot, TextList, IconList, Nowhere };
@ -273,9 +302,13 @@ public:
uint16 getItemSlotId(CDBCtrlSheet *ctrl); uint16 getItemSlotId(CDBCtrlSheet *ctrl);
uint16 getItemSlotId(const std::string &itemDb, uint slotIndex); uint16 getItemSlotId(const std::string &itemDb, uint slotIndex);
const CClientItemInfo &getItemInfo(uint slotId) const; const CClientItemInfo &getItemInfo(uint slotId) const;
// get item info from cache
const CClientItemInfo *getItemInfoCache(uint32 serial, uint32 createTime) const;
uint getItemSheetForSlotId(uint slotId) const; uint getItemSheetForSlotId(uint slotId) const;
// Returns true if the item info is already in slot cache
bool isItemInfoAvailable(uint slotId) const;
// Returns true if the item info version already matches // Returns true if the item info version already matches
bool isItemInfoUpToDate(uint slotId); bool isItemInfoUpToDate(uint slotId) const;
// Add a Waiter on ItemInfo (ItemHelp opening). no-op if here, but reorder (returns true if the version already matches or if waiter is NULL) // Add a Waiter on ItemInfo (ItemHelp opening). no-op if here, but reorder (returns true if the version already matches or if waiter is NULL)
void addItemInfoWaiter(IItemInfoWaiter *waiter); void addItemInfoWaiter(IItemInfoWaiter *waiter);
// remove a Waiter on ItemInfo (ItemHelp closing). no-op if not here. NB: no delete // remove a Waiter on ItemInfo (ItemHelp closing). no-op if not here. NB: no delete
@ -285,6 +318,7 @@ public:
void onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion); void onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion);
// Log for debug // Log for debug
void debugItemInfoWaiters(); void debugItemInfoWaiters();
void debugItemInfoCache() const;
void sortBag(); void sortBag();
@ -300,6 +334,9 @@ public:
enum TInvType { InvBag, InvPA0, InvPA1, InvPA2, InvPA3, InvPA4, InvPA5, InvPA6, InvGuild, InvRoom, InvUnknown }; enum TInvType { InvBag, InvPA0, InvPA1, InvPA2, InvPA3, InvPA4, InvPA5, InvPA6, InvGuild, InvRoom, InvUnknown };
static TInvType invTypeFromString(const std::string &str); static TInvType invTypeFromString(const std::string &str);
// inventory and slot from slotId
void getSlotInvIndex(uint slotId, uint &inv, uint &index) const;
private: private:
// LOCAL INVENTORY // LOCAL INVENTORY
@ -324,6 +361,8 @@ private:
CDBCtrlSheet *DNDCurrentItem; CDBCtrlSheet *DNDCurrentItem;
// ItemExtraInfo management. // ItemExtraInfo management.
std::string _ItemInfoCacheFilename;
CItemInfoCache _ItemInfoCache;
typedef std::map<uint, CClientItemInfo> TItemInfoMap; typedef std::map<uint, CClientItemInfo> TItemInfoMap;
TItemInfoMap _ItemInfoMap; TItemInfoMap _ItemInfoMap;
typedef std::list<IItemInfoWaiter*> TItemInfoWaiters; typedef std::list<IItemInfoWaiter*> TItemInfoWaiters;

Loading…
Cancel
Save