Merge from feature-item-icon-buffs

--HG--
branch : atys
hg/atys
Nuno Gonçalves 5 years ago
commit c950019044

@ -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();

@ -4609,3 +4609,17 @@ public:
}; };
REGISTER_ACTION_HANDLER( CHandlerSortTribeFame, "sort_tribefame"); REGISTER_ACTION_HANDLER( CHandlerSortTribeFame, "sort_tribefame");
// ***************************************************************************
class CHandlerTriggerIconBuffs : public IActionHandler
{
public:
void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
{
CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_ICON_BUFFS", false);
// no node - show,
// node == false - hide
CDBCtrlSheet::setShowIconBuffs(!node || node->getValueBool());
}
};
REGISTER_ACTION_HANDLER(CHandlerTriggerIconBuffs, "trigger_show_icon_buffs");

@ -73,45 +73,47 @@ REGISTER_UI_CLASS(CDBCtrlSheet)
const uint64 NOTIFY_ANIM_MS_DURATION = 1000; const uint64 NOTIFY_ANIM_MS_DURATION = 1000;
// *************************************************************************** // state kept and changed by UI:SAVE:SHOW_ICON_BUFFS
bool CDBCtrlSheet::_ShowIconBuffs = true;
// ***************************************************************************
// ********************************************************************************************************** void CControlSheetInfoWaiter::sendRequest()
class CControlSheetTooltipInfoWaiter : public IItemInfoWaiter
{ {
public: Requesting = true;
// The item used to open this window getInventory().addItemInfoWaiter(this);
CDBCtrlSheet* CtrlSheet; }
string LuaMethodName;
public:
ucstring infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName);
virtual void infoReceived();
};
static CControlSheetTooltipInfoWaiter ControlSheetTooltipUpdater;
void CControlSheetTooltipInfoWaiter::infoReceived() void CControlSheetInfoWaiter::infoReceived()
{ {
getInventory().removeItemInfoWaiter(&ControlSheetTooltipUpdater); if (!Requesting) {
infoValidated(CtrlSheet, LuaMethodName); return;
}
getInventory().removeItemInfoWaiter(this);
infoValidated();
CtrlSheet->infoReceived();
Requesting = false;
} }
ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName) ucstring CControlSheetInfoWaiter::infoValidated() const
{ {
ucstring help; ucstring help;
if (CtrlSheet && !LuaMethodName.empty())
{
// delegate setup of context he help ( & window ) to lua // delegate setup of context he help ( & window ) to lua
CInterfaceManager *im = CInterfaceManager::getInstance(); CInterfaceManager *im = CInterfaceManager::getInstance();
CLuaState *ls= CLuaManager::getInstance().getLuaState(); CLuaState *ls= CLuaManager::getInstance().getLuaState();
{ {
CLuaStackRestorer lsr(ls, 0); CLuaStackRestorer lsr(ls, 0);
CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)ctrlSheet); CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)CtrlSheet);
ls->pushGlobalTable(); ls->pushGlobalTable();
CLuaObject game(*ls); CLuaObject game(*ls);
game = game["game"]; game = game["game"];
game.callMethodByNameNoThrow(luaMethodName.c_str(), 1, 1); game.callMethodByNameNoThrow(LuaMethodName.c_str(), 1, 1);
// retrieve result from stack // retrieve result from stack
if (!ls->empty()) if (!ls->empty())
@ -120,7 +122,8 @@ ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet,
} }
else else
{ {
nlwarning(toString("Ucstring result expected when calling '%s', possible script error", luaMethodName.c_str()).c_str()); nlwarning(toString("Ucstring result expected when calling '%s', possible script error", LuaMethodName.c_str()).c_str());
}
} }
} }
@ -237,7 +240,6 @@ int CDBCtrlSheet::luaWaitInfo(CLuaState &ls)
int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls) int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls)
{ {
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this);
uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet); uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet);
CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId);
@ -505,6 +507,7 @@ CCtrlDraggable(param)
_Useable= true; _Useable= true;
_GrayedLink= NULL; _GrayedLink= NULL;
_NeedSetup= true; _NeedSetup= true;
_ItemInfoChanged = true;
_IconW = 0; _IconW = 0;
_IconH = 0; _IconH = 0;
_SetupInit= false; _SetupInit= false;
@ -528,6 +531,11 @@ CCtrlDraggable(param)
_ItemRMClassType= NULL; _ItemRMClassType= NULL;
_ItemRMFaberStatType= NULL; _ItemRMFaberStatType= NULL;
_NotifyAnimEndTime = 0; _NotifyAnimEndTime = 0;
_HpBuffIcon = "ico_heal.tga";
_SapBuffIcon = "ico_sap.tga";
_StaBuffIcon = "ico_stamina.tga";
_FocusBuffIcon = "ico_focus.tga";
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -535,6 +543,11 @@ CDBCtrlSheet::~CDBCtrlSheet()
{ {
NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver(); NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver();
if (_ItemInfoWaiter.Requesting)
{
getInventory().removeItemInfoWaiter(&_ItemInfoWaiter);
}
if (_GuildBack) if (_GuildBack)
{ {
if (Driver) if (Driver)
@ -613,6 +626,22 @@ bool CDBCtrlSheet::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
prop = (char*) xmlGetProp( cur, (xmlChar*)"slot" ); prop = (char*) xmlGetProp( cur, (xmlChar*)"slot" );
if(prop) _DrawSlot= CInterfaceElement::convertBool(prop); if(prop) _DrawSlot= CInterfaceElement::convertBool(prop);
//
_HpBuffIcon = "ico_heal.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"hp_buff_icon" );
if (prop) _HpBuffIcon = string((const char *)prop);
_SapBuffIcon = "ico_sap.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"sap_buff_icon" );
if (prop) _SapBuffIcon = string((const char *)prop);
_StaBuffIcon = "ico_stamina.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"sta_buff_icon" );
if (prop) _StaBuffIcon = string((const char *)prop);
_FocusBuffIcon = "ico_focus.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"focus_buff_icon" );
if (prop) _FocusBuffIcon = string((const char *)prop);
updateActualType(); updateActualType();
// Init size for Type // Init size for Type
@ -1040,6 +1069,72 @@ void CDBCtrlSheet::updateIconSize()
} }
} }
// ***************************************************************************
void CDBCtrlSheet::clearIconBuffs()
{
_EnchantIcons.clear();
_BuffIcons.clear();
}
// ***************************************************************************
void CDBCtrlSheet::infoReceived()
{
if (!_ItemSheet)
{
clearIconBuffs();
return;
}
const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime());
if (itemInfo == NULL)
{
// schedule for recheck on next draw()
_ItemInfoChanged = true;
return;
}
clearIconBuffs();
// crystallized spell
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
CSBrickManager *pBM= CSBrickManager::getInstance();
for(uint i=0; i<itemInfo->Enchantment.Bricks.size(); ++i)
{
const CSBrickSheet *brick = pBM->getBrick(itemInfo->Enchantment.Bricks[i]);
if (brick)
{
if (!brick->isRoot() && !brick->isCredit() && !brick->isParameter())
{
_EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIcon()), brick->IconColor));
rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH);
}
else if (brick->isRoot())
{
// there should be single root icon and it should be first one
_EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIconBack()), brick->IconBackColor));
rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH);
}
}
}
}
// buff icons
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (itemInfo->HpBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_HpBuffIcon)));
if (itemInfo->SapBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_SapBuffIcon)));
if (itemInfo->StaBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_StaBuffIcon)));
if (itemInfo->FocusBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_FocusBuffIcon)));
// update sizes
for(uint i = 0; i < _BuffIcons.size(); ++i)
{
rVR.getTextureSizeFromId(_BuffIcons[i].TextureId, _BuffIcons[i].IconW, _BuffIcons[i].IconH);
}
}
}
// *************************************************************************** // ***************************************************************************
void CDBCtrlSheet::setupPact() void CDBCtrlSheet::setupPact()
@ -1103,6 +1198,7 @@ void CDBCtrlSheet::setupItem ()
CInterfaceManager *pIM= CInterfaceManager::getInstance(); CInterfaceManager *pIM= CInterfaceManager::getInstance();
sint32 sheet = _SheetId.getSInt32(); sint32 sheet = _SheetId.getSInt32();
// If this is the same sheet, need to resetup // If this is the same sheet, need to resetup
if (_LastSheetId != sheet || _NeedSetup) if (_LastSheetId != sheet || _NeedSetup)
{ {
@ -1203,6 +1299,9 @@ void CDBCtrlSheet::setupItem ()
// Special Item requirement // Special Item requirement
updateItemCharacRequirement(_LastSheetId); updateItemCharacRequirement(_LastSheetId);
// update item info markers
_ItemInfoChanged = true;
} }
else else
{ {
@ -1277,6 +1376,13 @@ void CDBCtrlSheet::setupItem ()
_Useable = CSkillManager::getInstance()->checkBaseSkillMetRequirement(_ItemSheet->RequiredSkill, _ItemSheet->RequiredSkillLevel); _Useable = CSkillManager::getInstance()->checkBaseSkillMetRequirement(_ItemSheet->RequiredSkill, _ItemSheet->RequiredSkillLevel);
} }
*/ */
// at each frame, update item info icon if changed
if (_ItemInfoChanged)
{
_ItemInfoChanged = false;
setupItemInfoWaiter();
}
} }
@ -2220,6 +2326,69 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti
rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color)); rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color));
} }
if (_ShowIconBuffs && !_BuffIcons.empty())
{
// there is max 4 icons
sint32 hArea = (hSheet / 4);
sint32 xIcon = x;
sint32 yIcon = y;
for (uint i = 0; i < _BuffIcons.size(); ++i)
{
sint32 wIcon = _BuffIcons[i].IconW;
sint32 hIcon = _BuffIcons[i].IconH;
if (hIcon > hArea)
{
wIcon = wIcon * ((float)hArea / hIcon);
hIcon = hArea;
}
rVR.drawRotFlipBitmap (_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _BuffIcons[i].TextureId, fastMulRGB(curSheetColor, _BuffIcons[i].Color));
xIcon += wIcon;
// move up the row for 3rd/4th icon
if (i % 3 == 1) {
xIcon = x;
yIcon += hIcon;
}
}
}
// Is the item enchanted ?
sint32 enchant = _Enchant.getSInt32();
if (enchant > 0)
{
// Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item)
enchant--;
rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor);
drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false);
}
if (_ShowIconBuffs && !_EnchantIcons.empty())
{
// should only only 2 icons at most
// draw them in single line, top-right
sint32 hArea = (hSheet / 3);
sint32 xIcon = x + wSheet - 1;
sint32 yIcon = y + hSheet - 1/* - hArea*/;
// 0 is expected to be background
for (uint i = 1; i < _EnchantIcons.size(); ++i)
{
sint32 wIcon = _EnchantIcons[i].IconW;
sint32 hIcon = _EnchantIcons[i].IconH;
if (hIcon > hArea)
{
wIcon = wIcon * ((float)hArea / hIcon);
hIcon = hArea;
}
// need to move x before draw because of right aligned
if (i == 1)
{
xIcon -= wIcon;
}
yIcon -= hIcon;
rVR.drawRotFlipBitmap(_RenderLayer + 1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[0].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[0].Color));
rVR.drawRotFlipBitmap(_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[i].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[i].Color));
}
}
// Draw Quality. -1 for lookandfeel. Draw it with global color // Draw Quality. -1 for lookandfeel. Draw it with global color
if (_DispQuality != -1) if (_DispQuality != -1)
{ {
@ -2242,15 +2411,6 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti
} }
drawNumber(x+1+crossW, y+1, wSheet, hSheet, curSheetColor, quantity, false); drawNumber(x+1+crossW, y+1, wSheet, hSheet, curSheetColor, quantity, false);
} }
// Is the item enchanted ?
sint32 enchant = _Enchant.getSInt32();
if (enchant > 0)
{
// Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item)
enchant--;
rVR.draw11RotFlipBitmap (_RenderLayer+2, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor);
drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false);
}
// if a raw material for example, must add special icon text. // if a raw material for example, must add special icon text.
displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor); displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor);
@ -3114,6 +3274,62 @@ const COutpostBuildingSheet *CDBCtrlSheet::asOutpostBuildingSheet() const
return NULL; return NULL;
} }
// ***************************************************************************
void CDBCtrlSheet::setupItemInfoWaiter()
{
const CItemSheet *item = asItemSheet();
if(!item)
{
clearIconBuffs();
return;
}
if (!useItemInfoForFamily(item->Family))
{
clearIconBuffs();
return;
}
if (getItemSerial() == 0 || getItemCreateTime() == 0)
{
clearIconBuffs();
return;
}
string luaMethodName = ((item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip");
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this);
uint itemSlotId = getInventory().getItemSlotId(ctrlSheet);
// Prepare the waiter for tooltips
_ItemInfoWaiter.ItemSheet= ctrlSheet->getSheetId();
_ItemInfoWaiter.LuaMethodName = luaMethodName;
_ItemInfoWaiter.ItemSlotId= itemSlotId;
_ItemInfoWaiter.CtrlSheet = ctrlSheet;
// send out request only if cache is not set
const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime());
if (itemInfo)
{
infoReceived();
}
else
{
// Using isInventoryPresent/Available() will fail for packers when out of range
// Getting server item however will work correctly for packer/room/guild
const CItemImage *itemImage = getInventory().getServerItem(itemSlotId);
if (itemImage)
{
_ItemInfoWaiter.sendRequest();
}
else
{
// schedule for next draw() - if inventory should not be available (ie guild),
// but user opens it anyway, then this will loop back here on every draw()
_ItemInfoChanged = true;
}
}
}
// *************************************************************************** // ***************************************************************************
void CDBCtrlSheet::getContextHelp(ucstring &help) const void CDBCtrlSheet::getContextHelp(ucstring &help) const
{ {
@ -3177,35 +3393,19 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const
{ {
if (useItemInfoForFamily(item->Family)) if (useItemInfoForFamily(item->Family))
{ {
string luaMethodName = ( (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); // call lua function to update tooltip window
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); _ItemInfoWaiter.sendRequest();
CCtrlBase *ctrlBase = const_cast<CDBCtrlSheet*>(this); help = _ItemInfoWaiter.infoValidated();
if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet)))
{
// Prepare the waiter
ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId();
ControlSheetTooltipUpdater.LuaMethodName = luaMethodName;
ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet);
ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet;
// Add the waiter
getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater);
} }
else if (!_ContextHelp.empty())
if (!_ContextHelp.empty())
{ {
help = _ContextHelp; help = _ContextHelp;
ctrlBase->setDefaultContextHelp(ucstring());
}
else
help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName);
} }
else else
if (!_ContextHelp.empty()) {
help= _ContextHelp;
else
help = getItemActualName(); help = getItemActualName();
} }
}
else else
help= _ContextHelp; help= _ContextHelp;
} }
@ -3322,21 +3522,8 @@ void CDBCtrlSheet::getContextHelpToolTip(ucstring &help) const
{ {
if (useItemInfoForFamily(item->Family)) if (useItemInfoForFamily(item->Family))
{ {
string luaMethodName = (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"; _ItemInfoWaiter.sendRequest();
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); help = _ItemInfoWaiter.infoValidated();
if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet)))
{
// Prepare the waiter
ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId();
ControlSheetTooltipUpdater.LuaMethodName = luaMethodName;
ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet);
ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet;
// Add the waiter
getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater);
}
help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName);
return; return;
} }
} }
@ -3551,6 +3738,10 @@ void CDBCtrlSheet::resetAllTexIDs()
_Stackable= 1; _Stackable= 1;
_IconW = 0; _IconW = 0;
_IconH = 0; _IconH = 0;
_ItemInfoChanged = true;
_EnchantIcons.clear();
_BuffIcons.clear();
} }
@ -4503,7 +4694,3 @@ void CDBCtrlSheet::startNotifyAnim()
_NotifyAnimEndTime = T1 + NOTIFY_ANIM_MS_DURATION; _NotifyAnimEndTime = T1 + NOTIFY_ANIM_MS_DURATION;
} }

@ -37,7 +37,7 @@
#include "game_share/item_family.h" #include "game_share/item_family.h"
// //
#include "../time_client.h" #include "../time_client.h"
#include "item_info_waiter.h"
class CItemSheet; class CItemSheet;
class CPactSheet; class CPactSheet;
@ -53,6 +53,25 @@ namespace NLGUI
class CViewRenderer; class CViewRenderer;
} }
class CDBCtrlSheet;
// ***************************************************************************
// Item info request from server
class CControlSheetInfoWaiter : public IItemInfoWaiter
{
public:
CDBCtrlSheet* CtrlSheet;
string LuaMethodName;
bool Requesting;
CControlSheetInfoWaiter()
: IItemInfoWaiter(), Requesting(false)
{ }
public:
ucstring infoValidated() const;
void sendRequest();
virtual void infoReceived();
};
// *************************************************************************** // ***************************************************************************
/** Common info for CDBCtrlSheet and CDBGroupListSheet /** Common info for CDBCtrlSheet and CDBGroupListSheet
@ -580,8 +599,13 @@ public:
// start notify anim (at the end of regen usually) // start notify anim (at the end of regen usually)
void startNotifyAnim(); void startNotifyAnim();
protected: // callback from info waiter
void infoReceived();
// set enchant/buff marker visiblility
static void setShowIconBuffs(bool b) { _ShowIconBuffs = b; }
protected:
inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const; inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const;
void setupItem(); void setupItem();
@ -622,6 +646,7 @@ protected:
NLMISC::CCDBNodeLeaf *_ItemRMFaberStatType; NLMISC::CCDBNodeLeaf *_ItemRMFaberStatType;
mutable sint32 _LastSheetId; mutable sint32 _LastSheetId;
bool _ItemInfoChanged;
/// Display /// Display
sint32 _DispSlotBmpId; // Display slot bitmap id sint32 _DispSlotBmpId; // Display slot bitmap id
@ -632,6 +657,26 @@ protected:
sint32 _DispOverBmpId; // Over Icon sint32 _DispOverBmpId; // Over Icon
sint32 _DispOver2BmpId; // Over Icon N0 2 for bricks / items. Useful for items when _DispOverBmpId is used to paint user color on the item. sint32 _DispOver2BmpId; // Over Icon N0 2 for bricks / items. Useful for items when _DispOverBmpId is used to paint user color on the item.
std::string _HpBuffIcon;
std::string _SapBuffIcon;
std::string _StaBuffIcon;
std::string _FocusBuffIcon;
// texture ids to show
struct SBuffIcon
{
SBuffIcon(sint32 txid, NLMISC::CRGBA col=NLMISC::CRGBA::White)
:TextureId(txid), Color(col), IconW(0), IconH(0)
{ }
sint32 TextureId;
NLMISC::CRGBA Color;
sint32 IconW;
sint32 IconH;
};
std::vector<SBuffIcon> _BuffIcons;
std::vector<SBuffIcon> _EnchantIcons;
// Level Brick or Quality // Level Brick or Quality
union union
{ {
@ -751,16 +796,21 @@ protected:
sint64 _NotifyAnimEndTime; sint64 _NotifyAnimEndTime;
mutable CControlSheetInfoWaiter _ItemInfoWaiter;
private: private:
mutable TSheetType _ActualType; mutable TSheetType _ActualType;
static CDBCtrlSheet *_CurrSelection; static CDBCtrlSheet *_CurrSelection;
static CDBCtrlSheet *_CurrMenuSheet; static CDBCtrlSheet *_CurrMenuSheet;
static bool _ShowIconBuffs;
private: private:
void updateActualType() const; void updateActualType() const;
void updateIconSize(); void updateIconSize();
void resetAllTexIDs(); void resetAllTexIDs();
void setupInit(); void setupInit();
// remove enchant and buff markers from item icon
void clearIconBuffs();
void setupCharBitmaps(sint32 maxW, sint32 maxLine, sint32 maxWChar= 1000, bool topDown= false); void setupCharBitmaps(sint32 maxW, sint32 maxLine, sint32 maxWChar= 1000, bool topDown= false);
void resetCharBitmaps(); void resetCharBitmaps();
@ -769,6 +819,9 @@ private:
// special for items // special for items
void updateItemCharacRequirement(sint32 sheetId); void updateItemCharacRequirement(sint32 sheetId);
// Send ITEM_INFO:GET request to server to fetch Buffs, Enchant info
void setupItemInfoWaiter();
// update armour color, and cache // update armour color, and cache
void updateArmourColor(sint8 col); void updateArmourColor(sint8 col);

@ -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);
@ -127,6 +129,8 @@ CItemImage::CItemImage()
Sheet = NULL; Sheet = NULL;
Quality = NULL; Quality = NULL;
Quantity = NULL; Quantity = NULL;
CreateTime = NULL;
Serial = NULL;
UserColor = NULL; UserColor = NULL;
Price = NULL; Price = NULL;
Weight= NULL; Weight= NULL;
@ -141,6 +145,8 @@ void CItemImage::build(CCDBNodeBranch *branch)
Sheet = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SHEET"), false)); Sheet = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SHEET"), false));
Quality = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUALITY"), false)); Quality = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUALITY"), false));
Quantity = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUANTITY"), false)); Quantity = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUANTITY"), false));
CreateTime = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("CREATE_TIME"), false));
Serial = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SERIAL"), false));
UserColor = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false)); UserColor = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false));
Price = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("PRICE"), false)); Price = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("PRICE"), false));
Weight = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("WEIGHT"), false)); Weight = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("WEIGHT"), false));
@ -149,7 +155,145 @@ void CItemImage::build(CCDBNodeBranch *branch)
ResaleFlag = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false)); ResaleFlag = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false));
// Should always have at least those one:(ie all but Price) // Should always have at least those one:(ie all but Price)
nlassert(Sheet && Quality && Quantity && 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()));
} }
// ************************************************************************************************* // *************************************************************************************************
@ -180,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);
} }
// ************************************************************************************************* // *************************************************************************************************
@ -257,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)
@ -264,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)
@ -3262,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() || !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()) 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;
} }
// *************************************************************************** // ***************************************************************************
@ -3314,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;
@ -3409,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);
@ -3522,6 +3718,12 @@ void CInventoryManager::debugItemInfoWaiters()
} }
} }
// ***************************************************************************
void CInventoryManager::debugItemInfoCache() const
{
_ItemInfoCache.debugItemInfoCache();
}
// *************************************************************************** // ***************************************************************************
void CInventoryManager::sortBag() void CInventoryManager::sortBag()
{ {
@ -3677,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)
{ {
@ -3703,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)
{ {
@ -3719,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;
}

@ -31,7 +31,7 @@ namespace NLMISC{
class CCDBNodeBranch; class CCDBNodeBranch;
} }
class CDBCtrlSheet; class CDBCtrlSheet;
class IItermInfoWaiter;
const uint MAX_TEMPINV_ENTRIES = INVENTORIES::NbTempInvSlots; const uint MAX_TEMPINV_ENTRIES = INVENTORIES::NbTempInvSlots;
const uint MAX_BAGINV_ENTRIES = INVENTORIES::NbBagSlots; const uint MAX_BAGINV_ENTRIES = INVENTORIES::NbBagSlots;
@ -60,6 +60,8 @@ public:
NLMISC::CCDBNodeLeaf *Sheet; NLMISC::CCDBNodeLeaf *Sheet;
NLMISC::CCDBNodeLeaf *Quality; NLMISC::CCDBNodeLeaf *Quality;
NLMISC::CCDBNodeLeaf *Quantity; NLMISC::CCDBNodeLeaf *Quantity;
NLMISC::CCDBNodeLeaf *CreateTime;
NLMISC::CCDBNodeLeaf *Serial;
NLMISC::CCDBNodeLeaf *UserColor; NLMISC::CCDBNodeLeaf *UserColor;
NLMISC::CCDBNodeLeaf *Price; NLMISC::CCDBNodeLeaf *Price;
NLMISC::CCDBNodeLeaf *Weight; NLMISC::CCDBNodeLeaf *Weight;
@ -72,10 +74,13 @@ 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); }
uint16 getQuantity() const { return (uint16) (Quantity ? Quantity->getValue16() : 0); } uint16 getQuantity() const { return (uint16) (Quantity ? Quantity->getValue16() : 0); }
uint32 getCreateTime() const { return (uint32) (CreateTime ? CreateTime->getValue32() : 0); }
uint32 getSerial() const { return (uint32) (Serial ? Serial->getValue32() : 0); }
uint8 getUserColor() const { return (uint8) (UserColor ? UserColor->getValue16() : 0); } uint8 getUserColor() const { return (uint8) (UserColor ? UserColor->getValue16() : 0); }
uint32 getPrice() const { return (uint32) (Price ? Price->getValue32() : 0); } uint32 getPrice() const { return (uint32) (Price ? Price->getValue32() : 0); }
uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); } uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); }
@ -87,6 +92,8 @@ public:
void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); } void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); }
void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); } void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); }
void setQuantity(uint16 quantity) { if (Quantity) Quantity->setValue16((sint16) quantity); } void setQuantity(uint16 quantity) { if (Quantity) Quantity->setValue16((sint16) quantity); }
void setCreateTime(uint32 create_time) { if (CreateTime) CreateTime->setValue32((sint32) create_time); }
void setSerial(uint32 serial) { if (Serial) Serial->setValue32((sint32) serial); }
void setUserColor(uint8 uc) { if (UserColor) UserColor->setValue8((sint8) uc); } void setUserColor(uint8 uc) { if (UserColor) UserColor->setValue8((sint8) uc); }
void setPrice(uint32 price) { if (Price) Price->setValue32((sint32) price); } void setPrice(uint32 price) { if (Price) Price->setValue32((sint32) price); }
void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); } void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); }
@ -108,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)
@ -122,21 +133,25 @@ public:
void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; } void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; }
}; };
class CItemInfoCache
class IItemInfoWaiter
{ {
public: public:
IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;} void load(const std::string &filename);
virtual ~IItemInfoWaiter() {} void save(const std::string &filename);
// The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested void serial(NLMISC::IStream &s);
uint ItemSheet;
// The item SlotId to retrieve info. // retrieve pointer to item info or null if error
uint ItemSlotId; const CClientItemInfo *getItemInfo(uint32 serial, uint32 createTime) const;
const CClientItemInfo *getItemInfo(uint64 itemId) const;
// Called when the info is received for this slot.
virtual void infoReceived() =0;
};
// set/update item info in cache
void readFromImpulse(uint64 itemId, CItemInfos itemInfo);
void debugItemInfoCache() const;
private:
typedef std::map<uint64, CClientItemInfo> TItemInfoCacheMap;
TItemInfoCacheMap _ItemInfoCacheMap;
};
// *************************************************************************** // ***************************************************************************
/** This manager gives direct access to inventory slots (bag, temporary inventory, hands, and equip inventory) /** This manager gives direct access to inventory slots (bag, temporary inventory, hands, and equip inventory)
@ -189,8 +204,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)
@ -200,8 +217,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 };
@ -267,9 +287,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
@ -279,6 +303,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();
@ -294,6 +319,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
@ -318,6 +346,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;

@ -0,0 +1,39 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RZ_ITEM_INFO_WAITER_H
#define RZ_ITEM_INFO_WAITER_H
class IItemInfoWaiter
{
public:
IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;}
virtual ~IItemInfoWaiter() {}
// The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested
uint ItemSheet;
// The item SlotId to retrieve info.
uint ItemSlotId;
// Called when the info is received for this slot.
virtual void infoReceived() =0;
};
#endif // RZ_DBCTRL_SHEET_INFO_WAITER_H
/* End of item_info_waiter.h */

@ -161,6 +161,8 @@ bool CHugeListObs::init()
case Trading: case Trading:
_Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false);
_Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false);
_Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false);
_Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false);
_Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false);
_Items[k].Price = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:PRICE").c_str(), (int) k), false); _Items[k].Price = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:PRICE").c_str(), (int) k), false);
_Items[k].Weight = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:WEIGHT").c_str(), (int) k), false); _Items[k].Weight = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:WEIGHT").c_str(), (int) k), false);
@ -181,6 +183,7 @@ bool CHugeListObs::init()
if ((_Items[k].SlotType == NULL) || (_Items[k].Quality == NULL) || (_Items[k].SheetIDOrSkill == NULL) || if ((_Items[k].SlotType == NULL) || (_Items[k].Quality == NULL) || (_Items[k].SheetIDOrSkill == NULL) ||
(_Items[k].Price == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].Price == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) ||
(_Items[k].UserColor==NULL) || (_Items[k].NameId==NULL) || (_Items[k].Quantity==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].NameId==NULL) || (_Items[k].Quantity==NULL) ||
(_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL) ||
(_Items[k].PriceRetire==NULL) || (_Items[k].SellerType==NULL) || (_Items[k].ResaleTimeLeft==NULL) || (_Items[k].PriceRetire==NULL) || (_Items[k].SellerType==NULL) || (_Items[k].ResaleTimeLeft==NULL) ||
(_Items[k].VendorNameId==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].VendorNameId==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) ||
(_Items[k].RMFaberStatType == NULL) || (_Items[k].PrerequisitValid == NULL) || (_Items[k].RMFaberStatType == NULL) || (_Items[k].PrerequisitValid == NULL) ||
@ -191,6 +194,8 @@ bool CHugeListObs::init()
case ItemForMissions: case ItemForMissions:
_Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false);
_Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false);
_Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false);
_Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false);
_Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false);
_Items[k].LogicTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:LOGIC_TEXT_ID").c_str(), (int) k), false); _Items[k].LogicTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:LOGIC_TEXT_ID").c_str(), (int) k), false);
_Items[k].DescTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:DESC_TEXT_ID").c_str(), (int) k), false); _Items[k].DescTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:DESC_TEXT_ID").c_str(), (int) k), false);
@ -205,7 +210,7 @@ bool CHugeListObs::init()
(_Items[k].LogicTextID == NULL) || (_Items[k].DescTextID == NULL) || (_Items[k].LogicTextID == NULL) || (_Items[k].DescTextID == NULL) ||
(_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) ||
(_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) ||
(_Items[k].NameId==NULL) (_Items[k].NameId==NULL) || (_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL)
) )
return false; return false;
break; break;
@ -383,6 +388,8 @@ void CHugeListObs::update(ICDBNode * /* node */)
{ {
page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32();
page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16();
page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32();
page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32();
page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32();
page.Items[k].Price = (uint32) _Items[k].Price->getValue32(); page.Items[k].Price = (uint32) _Items[k].Price->getValue32();
page.Items[k].Weight= (uint16) _Items[k].Weight->getValue16(); page.Items[k].Weight= (uint16) _Items[k].Weight->getValue16();
@ -420,6 +427,8 @@ void CHugeListObs::update(ICDBNode * /* node */)
case ItemForMissions: case ItemForMissions:
page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32();
page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16();
page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32();
page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32();
page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32();
page.Items[k].LogicTextID = (uint32) _Items[k].LogicTextID->getValue32(); page.Items[k].LogicTextID = (uint32) _Items[k].LogicTextID->getValue32();
page.Items[k].DescTextID = (uint32) _Items[k].DescTextID->getValue32(); page.Items[k].DescTextID = (uint32) _Items[k].DescTextID->getValue32();
@ -569,6 +578,10 @@ void CHugeListObs::updateUIItemPage(uint index)
case Trading: case Trading:
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false);
if (leaf) leaf->setValue32(currItem.Quality); if (leaf) leaf->setValue32(currItem.Quality);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false);
if (leaf) leaf->setValue32(currItem.Serial);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false);
if (leaf) leaf->setValue32(currItem.CreateTime);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false);
if (leaf) leaf->setValue32(currItem.SlotType); if (leaf) leaf->setValue32(currItem.SlotType);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false);
@ -610,6 +623,10 @@ void CHugeListObs::updateUIItemPage(uint index)
case ItemForMissions: case ItemForMissions:
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false);
if (leaf) leaf->setValue32(currItem.Quality); if (leaf) leaf->setValue32(currItem.Quality);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false);
if (leaf) leaf->setValue32(currItem.Serial);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false);
if (leaf) leaf->setValue32(currItem.CreateTime);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false);
if (leaf) leaf->setValue32(currItem.SlotType); if (leaf) leaf->setValue32(currItem.SlotType);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false);

@ -124,6 +124,8 @@ private:
// //
NLMISC::CCDBNodeLeaf *SlotType; NLMISC::CCDBNodeLeaf *SlotType;
NLMISC::CCDBNodeLeaf *Quality; NLMISC::CCDBNodeLeaf *Quality;
NLMISC::CCDBNodeLeaf *Serial;
NLMISC::CCDBNodeLeaf *CreateTime;
NLMISC::CCDBNodeLeaf *SheetIDOrSkill; NLMISC::CCDBNodeLeaf *SheetIDOrSkill;
// //
NLMISC::CCDBNodeLeaf *LogicTextID; // valid if the item is to be obtained for a mission NLMISC::CCDBNodeLeaf *LogicTextID; // valid if the item is to be obtained for a mission
@ -157,6 +159,8 @@ private:
GuildName(NULL), GuildName(NULL),
SlotType(NULL), SlotType(NULL),
Quality(NULL), Quality(NULL),
Serial(NULL),
CreateTime(NULL),
SheetIDOrSkill(NULL), SheetIDOrSkill(NULL),
LogicTextID(NULL), LogicTextID(NULL),
DescTextID(NULL), DescTextID(NULL),
@ -216,6 +220,8 @@ private:
TRADE_SLOT_TYPE::TTradeSlotType SlotType; TRADE_SLOT_TYPE::TTradeSlotType SlotType;
uint16 Quality; uint16 Quality;
uint32 Serial;
uint32 CreateTime;
uint32 SheetIDOrSkill; uint32 SheetIDOrSkill;
uint32 LogicTextID; // Valid if the item is to be obtained as a mission reward uint32 LogicTextID; // Valid if the item is to be obtained as a mission reward
uint32 DescTextID; // Valid if the item is to be obtained as a mission reward uint32 DescTextID; // Valid if the item is to be obtained as a mission reward

Loading…
Cancel
Save