DB
1. ClientManager.cpp
Search:
CClientManager::CClientManager() :
m_pkAuthPeer(NULL),
m_iPlayerIDStart(0),
m_iPlayerDeleteLevelLimit(0),
m_iPlayerDeleteLevelLimitLower(0),
m_iShopTableSize(0),
m_pShopTable(NULL),
m_iRefineTableSize(0),
m_pRefineTable(NULL),
Add:
#ifdef ENABLE_ITEMSHOP
m_iItemshopTableCategorySize(0),
m_pItemshopTableCategories(NULL),
m_iItemshopTableItemSize(0),
m_pItemshopTableItems(NULL),
#endif
Search:
memset(g_query_count, 0, sizeof(g_query_count));
Add:
#ifdef ENABLE_ITEMSHOP
m_map_ItemshopLimitCountFlush.clear();
m_vec_usedSeeds.clear();
m_ItemshopItems.clear();
#endif
Search:
if (!InitializeTables())
{
sys_err("Table Initialize FAILED");
return false;
}
Add:
#ifdef ENABLE_ITEMSHOP
if (!InitializePromotionCodes())
{
sys_err("InitializePromotionCodes FAILED");
return false;
}
if (!InitializeRedeemedPromotionCodes())
{
sys_err("InitializeRedeemedPromotionCodes FAILED");
return false;
}
if (!InitializeItemshopSpecialOffers())
{
sys_err("InitializeItemshopSpecialOffers FAILED");
return false;
}
if (!InitializeItemshopCategoryTable())
{
sys_err("InitializeItemshopCategoryTable FAILED");
return false;
}
if (!InitializeItemshopItemTable())
{
sys_err("InitializeItemshopItemTable FAILED");
return false;
}
#endif
Search:
void CClientManager::MainLoop()
{
SQLMsg * tmp;
sys_log(0, "ClientManager pointer is %p", this);
while (!m_bShutdowned)
{
Add:
#ifdef ENABLE_ITEMSHOP
time_t now = time(0);
for (auto& specialoffer_item : m_vec_itemshopSpecialOfferItems)
{
if (specialoffer_item.times.start_time < now && !specialoffer_item.times.is_activ)
{
specialoffer_item.times.is_activ = true;
AddSingleItemshopItem(&specialoffer_item.item, specialoffer_item.llItemIndex);
}
else if (specialoffer_item.times.end_time < now)
{
RemoveSingleItemshopItem(specialoffer_item.llItemIndex);
}
}
#endif
Search:
sys_log(0, "MainLoop exited, Starting cache flushing");
signal_timer_disable();
Add:
#ifdef ENABLE_ITEMSHOP
UpdateItemshopTable();
UpdatePromotionTables();
#endif
Search:
DWORD dwPacketSize =
sizeof(DWORD) +
sizeof(BYTE) +
sizeof(WORD) + sizeof(WORD) + sizeof(TMobTable) * m_vec_mobTable.size() +
sizeof(WORD) + sizeof(WORD) + sizeof(TItemTable) * m_vec_itemTable.size() +
sizeof(WORD) + sizeof(WORD) + sizeof(TShopTable) * m_iShopTableSize +
sizeof(WORD) + sizeof(WORD) + sizeof(TSkillTable) * m_vec_skillTable.size() +
sizeof(WORD) + sizeof(WORD) + sizeof(TRefineTable) * m_iRefineTableSize +
Add:
#ifdef ENABLE_ITEMSHOP
sizeof(WORD) + sizeof(WORD) + sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize +
sizeof(WORD) + sizeof(WORD) + sizeof(TItemshopItemTable) * m_iItemshopTableItemSize +
#endif
Search:
sys_log(0, "sizeof(TMobTable) = %d", sizeof(TMobTable));
sys_log(0, "sizeof(TItemTable) = %d", sizeof(TItemTable));
sys_log(0, "sizeof(TShopTable) = %d", sizeof(TShopTable));
sys_log(0, "sizeof(TSkillTable) = %d", sizeof(TSkillTable));
sys_log(0, "sizeof(TRefineTable) = %d", sizeof(TRefineTable));
Add:
#ifdef ENABLE_ITEMSHOP
sys_log(0, "sizeof(TItemshopCategoryTable) = %d", sizeof(TItemshopCategoryTable));
sys_log(0, "sizeof(TItemshopItemTable) = %d", sizeof(TItemshopItemTable));
#endif
Search:
peer->EncodeWORD(sizeof(TSkillTable));
peer->EncodeWORD(m_vec_skillTable.size());
peer->Encode(&m_vec_skillTable[0], sizeof(TSkillTable) * m_vec_skillTable.size());
peer->EncodeWORD(sizeof(TRefineTable));
peer->EncodeWORD(m_iRefineTableSize);
peer->Encode(m_pRefineTable, sizeof(TRefineTable) * m_iRefineTableSize);
Add:
#ifdef ENABLE_ITEMSHOP
peer->EncodeWORD(sizeof(TItemshopCategoryTable));
peer->EncodeWORD(m_iItemshopTableCategorySize);
peer->Encode(m_pItemshopTableCategories, sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize);
peer->EncodeWORD(sizeof(TItemshopItemTable));
peer->EncodeWORD(m_iItemshopTableItemSize);
peer->Encode(m_pItemshopTableItems, sizeof(TItemshopItemTable) * m_iItemshopTableItemSize);
#endif
Search:
case HEADER_GD_RELOAD_PROTO:
QUERY_RELOAD_PROTO();
break;
Add:
#ifdef ENABLE_ITEMSHOP
case HEADER_GD_RELOAD_ITEMSHOP:
QUERY_RELOAD_ITEMSHOP();
break;
case HEADER_GD_BUY_ITEMSHOP:
ItemshopCheckBuy(peer, dwHandle, (TItemshopCheckBuy*)data);
break;
case HEADER_GD_PROMOTION_REDEEM:
RedeemPromotionCode(peer, dwHandle, (TPromotionRedeem*)data);
break;
#endif
Search:
if (!(thecore_heart->pulse % (thecore_heart->passes_per_sec * 5)))
{
Add:
#ifdef ENABLE_ITEMSHOP
UpdateItemshopTable();
UpdatePromotionTables();
#endif
Add to end of file:
#ifdef ENABLE_ITEMSHOP
void CClientManager::QUERY_RELOAD_ITEMSHOP()
{
UpdateItemshopTable();
UpdatePromotionTables();
if (!InitializePromotionCodes())
{
sys_err("InitializePromotionCodes FAILED");
return;
}
if (!InitializeRedeemedPromotionCodes())
{
sys_err("InitializeRedeemedPromotionCodes FAILED");
return;
}
if (!InitializeItemshopSpecialOffers())
{
sys_err("InitializeItemshopSpecialOffers FAILED");
return;
}
if (!InitializeItemshopCategoryTable())
{
sys_err("InitializeItemshopCategoryTable FAILED");
return;
}
if (!InitializeItemshopItemTable())
{
sys_err("InitializeItemshopItemTable FAILED");
return;
}
for (TPeerList::iterator i = m_peerList.begin(); i != m_peerList.end(); ++i)
{
CPeer* tmp = *i;
if (!tmp->GetChannel() || tmp == m_pkAuthPeer)
continue;
tmp->EncodeHeader(HEADER_DG_RELOAD_ITEMSHOP, 0,
sizeof(WORD) + sizeof(WORD) +
sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize +
sizeof(TItemshopItemTable) * m_iItemshopTableItemSize
);
tmp->Encode(&m_iItemshopTableCategorySize, sizeof(WORD));
tmp->Encode(&m_iItemshopTableItemSize, sizeof(WORD));
tmp->Encode(m_pItemshopTableCategories, sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize);
tmp->Encode(m_pItemshopTableItems, sizeof(TItemshopItemTable) * m_iItemshopTableItemSize);
}
}
void CClientManager::ItemshopCheckBuy(CPeer* pkPeer, DWORD dwHandle, TItemshopCheckBuy* p)
{
TItemshopBuyAnswer answer;
auto it = m_ItemshopItems.find(p->hash);
if (it != m_ItemshopItems.end())
{
if (it->second.second.llLimitCount == -1)
{
answer.canBuy = true;
answer.wCount = p->wCount;
strlcpy(answer.code, p->hash, sizeof(answer.code));
pkPeer->EncodeHeader(HEADER_DG_BUY_ITEMSHOP_ITEM, dwHandle, sizeof(TItemshopBuyAnswer));
pkPeer->Encode(&answer, sizeof(TItemshopBuyAnswer));
return;
}
else if (it->second.second.llLimitCount > 0)
{
answer.canBuy = true;
strlcpy(answer.code, p->hash, sizeof(answer.code));
it->second.second.llLimitCount--;
// NOTE: limite item buy count 1 -> Change here if needed
answer.wCount = 1;
// Increase count for flush
m_map_ItemshopLimitCountFlush[p->hash].first = it->second.first;
m_map_ItemshopLimitCountFlush[p->hash].second++;
pkPeer->EncodeHeader(HEADER_DG_BUY_ITEMSHOP_ITEM, dwHandle, sizeof(TItemshopBuyAnswer));
pkPeer->Encode(&answer, sizeof(TItemshopBuyAnswer));
if (it->second.second.llLimitCount == 0)
{
RemoveSingleItemshopItem(it->second.first);
}
else
{
for (auto& item : m_ItemshopItems)
{
if (!strcmp(item.second.second.hash, p->hash))
{
item.second.second.llLimitCount = it->second.second.llLimitCount;
for (TPeerList::iterator i = m_peerList.begin(); i != m_peerList.end(); ++i)
{
CPeer* tmp = *i;
if (!tmp->GetChannel() || tmp == m_pkAuthPeer)
continue;
tmp->EncodeHeader(HEADER_DG_REFRESH_ITEMSHOP_SINGLE_ITEM, 0, sizeof(TItemshopItemTable));
tmp->Encode(&item.second.second, sizeof(TItemshopItemTable));
}
break;
}
}
}
return;
}
}
answer.canBuy = false;
pkPeer->EncodeHeader(HEADER_DG_BUY_ITEMSHOP_ITEM, dwHandle, sizeof(TItemshopBuyAnswer));
pkPeer->Encode(&answer, sizeof(TItemshopBuyAnswer));
}
void CClientManager::RemoveSingleItemshopItem(long long llItemIndex)
{
for (const auto& item : m_ItemshopItems)
{
if (item.second.first != llItemIndex)
continue;
for (unsigned int i = 0; i < m_vec_itemshopSpecialOfferItems.size(); i++)
{
if (m_vec_itemshopSpecialOfferItems[i].llItemIndex == llItemIndex)
{
m_vec_itemshopSpecialOfferItems.erase(m_vec_itemshopSpecialOfferItems.begin() + i);
break;
}
}
for (TPeerList::iterator i = m_peerList.begin(); i != m_peerList.end(); ++i)
{
CPeer* tmp = *i;
if (!tmp->GetChannel() || tmp == m_pkAuthPeer)
continue;
tmp->EncodeHeader(HEADER_DG_REMOVE_ITEMSHOP_SINGLE_ITEM, 0, sizeof(TItemshopItemTable));
tmp->Encode(&item.second.second, sizeof(TItemshopItemTable));
}
m_ItemshopItems.erase(item.first);
break;
}
}
void CClientManager::AddSingleItemshopItem(TItemshopItemTable* item, long long llItemIndex)
{
m_ItemshopItems[item->hash].first = llItemIndex;
m_ItemshopItems[item->hash].second = *item;
for (TPeerList::iterator i = m_peerList.begin(); i != m_peerList.end(); ++i)
{
CPeer* tmp = *i;
if (!tmp->GetChannel() || tmp == m_pkAuthPeer)
continue;
tmp->EncodeHeader(HEADER_DG_ADD_ITEMSHOP_SINGLE_ITEM, 0, sizeof(TItemshopItemTable));
tmp->Encode(item, sizeof(TItemshopItemTable));
}
}
void CClientManager::UpdateItemshopTable()
{
for (const auto& item : m_map_ItemshopLimitCountFlush)
{
const long long llIndex = item.second.first;
const long long llLimitCount = item.second.second;
char query[2048];
if (llLimitCount >= 0)
{
snprintf(query, sizeof(query), "UPDATE itemshop.itemshop_items SET limitCount = limitCount - %lld WHERE itemIndex = %lld", llLimitCount, llIndex);
CDBManager::instance().AsyncQuery(query, SQL_ITEMSHOP);
}
}
m_map_ItemshopLimitCountFlush.clear();
}
void CClientManager::UpdatePromotionTables()
{
for (const auto& [key, val] : m_map_promotionCodeInfo)
{
char query[2048];
char escape_key[PROMOTION_CODE_MAX_LEN * 2 + 1];
CDBManager::instance().EscapeString(escape_key, key.c_str(), key.size());
snprintf(query, sizeof(query), "UPDATE itemshop.promotion_codes SET useCount = %lld WHERE promotion_code = '%s'", val.first, escape_key);
CDBManager::instance().AsyncQuery(query, SQL_ITEMSHOP);
}
for (const auto& [key, val] : m_map_redeemedPromotionFlush)
{
char query[2048];
char escape_key[PROMOTION_CODE_MAX_LEN * 2 + 1];
CDBManager::instance().EscapeString(escape_key, val.c_str(), val.size());
snprintf(query, sizeof(query), "INSERT itemshop.promotion_redeemed (acc_id, redeemed_code, time_redeemed) VALUES (%ld, '%s', NOW())", key, escape_key);
CDBManager::instance().AsyncQuery(query, SQL_ITEMSHOP);
}
m_map_redeemedPromotionFlush.clear();
}
void CClientManager::RedeemPromotionCode(CPeer* pkPeer, DWORD dwHandle, TPromotionRedeem* p)
{
TPromotionRedeemAnswer redeem_info;
for (const auto& redeemed : m_vec_redeemedPromotionCodes[p->accID])
{
if (!strcmp(redeemed.c_str(), p->code))
{
pkPeer->EncodeHeader(HEADER_DG_PROMOTION_CODE_REDEEM, dwHandle, sizeof(TPromotionRedeemAnswer));
redeem_info.byRedeemAnswer = REDEEM_ALREADY_REDEEMED;
pkPeer->Encode(&redeem_info, sizeof(TPromotionRedeemAnswer));
return;
}
}
if (m_map_promotionCodeInfo.find(p->code) != m_map_promotionCodeInfo.end() && m_map_promotionCodeInfo[p->code].first > 0)
{
pkPeer->EncodeHeader(HEADER_DG_PROMOTION_CODE_REDEEM, dwHandle, sizeof(TPromotionRedeemAnswer) + sizeof(TPromotionItemTable) * m_map_promotionCodeInfo[p->code].second.size());
m_map_promotionCodeInfo[p->code].first--;
redeem_info.byRedeemAnswer = REDEEM_SUCCESS;
redeem_info.reward_count = m_map_promotionCodeInfo[p->code].second.size();
m_vec_redeemedPromotionCodes[p->accID].push_back(p->code);
m_map_redeemedPromotionFlush.insert(std::pair(p->accID, p->code));
pkPeer->Encode(&redeem_info, sizeof(TPromotionRedeemAnswer));
pkPeer->Encode(m_map_promotionCodeInfo[p->code].second.data(), sizeof(TPromotionItemTable) * m_map_promotionCodeInfo[p->code].second.size());
}
else
{
pkPeer->EncodeHeader(HEADER_DG_PROMOTION_CODE_REDEEM, dwHandle, sizeof(TPromotionRedeemAnswer));
redeem_info.byRedeemAnswer = REDEEM_FAIL;
pkPeer->Encode(&redeem_info, sizeof(TPromotionRedeemAnswer));
}
}
#endif
2. ClientManager.h
Add to end of class CClientManager:
#ifdef ENABLE_ITEMSHOP
protected:
bool InitializeItemshopCategoryTable();
bool InitializeItemshopItemTable();
bool InitializeItemshopSpecialOffers();
bool InitializePromotionCodes();
bool InitializeRedeemedPromotionCodes();
void ItemshopCheckBuy(CPeer* pkPeer, DWORD dwHandle, TItemshopCheckBuy* p);
void RemoveSingleItemshopItem(long long llItemIndex);
void AddSingleItemshopItem(TItemshopItemTable* item, long long llItemIndex);
void RedeemPromotionCode(CPeer* pkPeer, DWORD dwHandle, TPromotionRedeem* p);
void UpdatePromotionTables();
void UpdateItemshopTable();
private:
void QUERY_RELOAD_ITEMSHOP();
int m_iItemshopTableCategorySize;
TItemshopCategoryTable* m_pItemshopTableCategories;
int m_iItemshopTableItemSize;
TItemshopItemTable* m_pItemshopTableItems;
std::vector<unsigned long> m_vec_usedSeeds;
std::unordered_map <std::string, std::pair<long long, TItemshopItemTable>> m_ItemshopItems;
std::unordered_map <std::string, std::pair<DWORD, long long>> m_map_ItemshopLimitCountFlush;
std::vector<TSpecialOfferItems> m_vec_itemshopSpecialOfferItems;
std::unordered_map<std::string, std::pair<long long, std::vector<TPromotionItemTable>>> m_map_promotionCodeInfo;
std::unordered_map<DWORD, std::vector<std::string>> m_vec_redeemedPromotionCodes;
std::unordered_map<DWORD, std::string> m_map_redeemedPromotionFlush;
#endif
3. ClientManagerBoot.cpp
Add:
#ifdef ENABLE_ITEMSHOP
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>
#include <random>
std::string MD5_STRING(const boost::uuids::detail::md5::digest_type& digest)
{
const auto charDigest = reinterpret_cast<const char*>(&digest);
std::string result;
boost::algorithm::hex(charDigest, charDigest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(result));
return result;
}
#endif
Add to end of file:
#ifdef ENABLE_ITEMSHOP
bool CClientManager::InitializePromotionCodes()
{
char query[2048];
snprintf(query, sizeof(query),
"SELECT "
"CODES.useCount, "
"CODES.promotion_code, "
"vnum, "
"count,"
"socket0,"
"socket1,"
"socket2,"
// NOTE: Add if needed
//"socket3,"
//"socket4,"
//"socket5,"
"attrtype0,"
"attrvalue0, "
"attrtype1,"
"attrvalue1, "
"attrtype2,"
"attrvalue2, "
"attrtype3,"
"attrvalue3, "
"attrtype4,"
"attrvalue4, "
"attrtype5,"
"attrvalue5, "
"attrtype6, "
"attrvalue6 "
"FROM "
"itemshop.promotion_rewards AS REWARDS "
"LEFT JOIN itemshop.promotion_codes AS CODES ON REWARDS.code_index = CODES.index "
"WHERE "
"REWARDS.code_index = CODES.index AND CODES.state = 'ENABLED' "
"AND count > 0"
);
std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
SQLResult* pRes = pkMsg->Get();
if (!m_map_promotionCodeInfo.empty())
{
sys_log(0, "RELOAD: itemshop offertimes");
m_map_promotionCodeInfo.clear();
}
if (!pRes->uiNumRows)
{
return true;
}
MYSQL_ROW data;
int col = 0;
while ((data = mysql_fetch_row(pRes->pSQLResult)))
{
TPromotionItemTable reward;
col = 0;
long long llPromotionUseCount;
char promotion_code[PROMOTION_CODE_MAX_LEN + 1];
str_to_number(llPromotionUseCount, data[col++]);
strlcpy(promotion_code, data[col++], sizeof(promotion_code));
str_to_number(reward.dwVnum, data[col++]);
str_to_number(reward.wCount, data[col++]);
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
{
str_to_number(reward.alSockets[i], data[col++]);
}
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
{
str_to_number(reward.aAttr[i].bType, data[col++]);
str_to_number(reward.aAttr[i].sValue, data[col++]);
}
m_map_promotionCodeInfo[promotion_code].first = llPromotionUseCount;
m_map_promotionCodeInfo[promotion_code].second.push_back(reward);
}
return true;
}
bool CClientManager::InitializeRedeemedPromotionCodes()
{
char query[2048];
snprintf(query, sizeof(query),
"SELECT "
"acc_id, "
"redeemed_code "
"FROM "
"itemshop.promotion_redeemed "
);
std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
SQLResult* pRes = pkMsg->Get();
if (!m_vec_redeemedPromotionCodes.empty())
{
sys_log(0, "RELOAD: itemshop redeemed promotion_codes");
m_vec_redeemedPromotionCodes.clear();
}
if (!pRes->uiNumRows)
{
return true;
}
MYSQL_ROW data;
int col = 0;
while ((data = mysql_fetch_row(pRes->pSQLResult)))
{
col = 0;
DWORD accID;
char code[PROMOTION_CODE_MAX_LEN + 1];
str_to_number(accID, data[col++]);
strlcpy(code, data[col++], sizeof(code));
m_vec_redeemedPromotionCodes[accID].push_back(code);
}
return true;
}
bool CClientManager::InitializeItemshopSpecialOffers()
{
char query[2048];
snprintf(query, sizeof(query),
"SELECT "
"itemIndex, "
"vnum, "
"count,"
"ABS(price), "
"discountPercent,"
"limitCount, "
"category, "
"UNIX_TIMESTAMP(endTime),"
"weight,"
"socket0,"
"socket1,"
"socket2,"
// NOTE: Add if needed
//"socket3,"
//"socket4,"
//"socket5,"
"attrtype0,"
"attrvalue0, "
"attrtype1,"
"attrvalue1, "
"attrtype2,"
"attrvalue2, "
"attrtype3,"
"attrvalue3, "
"attrtype4,"
"attrvalue4, "
"attrtype5,"
"attrvalue5, "
"attrtype6, "
"attrvalue6, "
"UNIX_TIMESTAMP(startTime), "
"UNIX_TIMESTAMP(endTime), "
"(UNIX_TIMESTAMP(NOW()) >= UNIX_TIMESTAMP(startTime))"
"FROM "
"itemshop.itemshop_items AS ITEMS "
"LEFT JOIN itemshop.itemshop_categories AS CATEGORY ON ITEMS.category = CATEGORY.category_index "
"WHERE "
"ITEMS.category = CATEGORY.category_index AND CATEGORY.category_state = 'ENABLED' "
"AND not limitCount = 0 "
"AND count > 0 "
"AND("
"(UNIX_TIMESTAMP(NOW()) < UNIX_TIMESTAMP(ITEMS.endTime))"
"AND "
"(UNIX_TIMESTAMP(ITEMS.startTime) < UNIX_TIMESTAMP(ITEMS.endTime) ))"
"ORDER BY UNIX_TIMESTAMP(startTime)"
);
std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
SQLResult* pRes = pkMsg->Get();
if (!m_vec_itemshopSpecialOfferItems.empty())
{
sys_log(0, "RELOAD: itemshop offertimes");
m_vec_itemshopSpecialOfferItems.clear();
}
if (!pRes->uiNumRows)
{
return true;
}
m_vec_itemshopSpecialOfferItems.resize(pRes->uiNumRows);
memset(&m_vec_itemshopSpecialOfferItems[0], 0, sizeof(TSpecialOfferItems) * m_vec_itemshopSpecialOfferItems.size());
TSpecialOfferItems* specialoffer_items = &m_vec_itemshopSpecialOfferItems[0];
MYSQL_ROW data;
int col;
while ((data = mysql_fetch_row(pRes->pSQLResult)))
{
col = 0;
// NOTE: Random number -> First non unique after ~20.000 - 40.000 md5 hashes
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1, 4294967295);
unsigned long seed = dist(rng);
// NOTE: To prevent duplicate hashes
while (std::find(m_vec_usedSeeds.begin(), m_vec_usedSeeds.end(), seed) != m_vec_usedSeeds.end())
{
seed = dist(rng);
}
m_vec_usedSeeds.push_back(seed);
boost::uuids::detail::md5 hash;
boost::uuids::detail::md5::digest_type digest;
hash.process_bytes((char*)&seed, sizeof(seed));
hash.get_digest(digest);
strlcpy(specialoffer_items->item.hash, MD5_STRING(digest).c_str(), sizeof(specialoffer_items->item.hash));
str_to_number(specialoffer_items->llItemIndex, data[col++]);
str_to_number(specialoffer_items->item.dwVnum, data[col++]);
str_to_number(specialoffer_items->item.wCount, data[col++]);
str_to_number(specialoffer_items->item.ullPrice, data[col++]);
str_to_number(specialoffer_items->item.byDiscountPercent, data[col++]);
str_to_number(specialoffer_items->item.llLimitCount, data[col++]);
str_to_number(specialoffer_items->item.byCategory, data[col++]);
str_to_number(specialoffer_items->item.end_time, data[col++]);
str_to_number(specialoffer_items->item.weight, data[col++]);
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
{
str_to_number(specialoffer_items->item.alSockets[i], data[col++]);
}
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
{
str_to_number(specialoffer_items->item.aAttr[i].bType, data[col++]);
str_to_number(specialoffer_items->item.aAttr[i].sValue, data[col++]);
}
str_to_number(specialoffer_items->times.start_time, data[col++]);
str_to_number(specialoffer_items->times.end_time, data[col++]);
str_to_number(specialoffer_items->times.is_activ, data[col++]);
++specialoffer_items;
}
return true;
}
bool CClientManager::InitializeItemshopCategoryTable()
{
char query[2048];
snprintf(query, sizeof(query),
"SELECT "
"category_index, "
"category_name, "
"category_icon "
"FROM "
"itemshop.itemshop_categories "
"WHERE category_state = 'ENABLED'"
);
std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
SQLResult* pRes = pkMsg->Get();
if (m_pItemshopTableCategories)
{
sys_log(0, "RELOAD: itemshop_categories");
delete[] m_pItemshopTableCategories;
m_pItemshopTableCategories = NULL;
}
if (!pRes->uiNumRows)
{
m_iItemshopTableCategorySize = 0;
m_pItemshopTableCategories = new TItemshopCategoryTable[m_iItemshopTableCategorySize];
memset(m_pItemshopTableCategories, 0, sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize);
return true;
}
m_iItemshopTableCategorySize = pRes->uiNumRows;
m_pItemshopTableCategories = new TItemshopCategoryTable[m_iItemshopTableCategorySize];
memset(m_pItemshopTableCategories, 0, sizeof(TItemshopCategoryTable) * m_iItemshopTableCategorySize);
TItemshopCategoryTable* prt = m_pItemshopTableCategories;
MYSQL_ROW data;
while ((data = mysql_fetch_row(pRes->pSQLResult)))
{
int col = 0;
str_to_number(prt->index, data[col++]);
strlcpy(prt->info.category, data[col++], sizeof(prt->info.category));
strlcpy(prt->info.icon, data[col++], sizeof(prt->info.icon));
prt++;
}
return true;
}
bool CClientManager::InitializeItemshopItemTable()
{
char query[2048];
snprintf(query, sizeof(query),
"SELECT "
"itemIndex, "
"vnum, "
"count,"
"ABS(price), "
"discountPercent,"
"limitCount, "
"category, "
"UNIX_TIMESTAMP(endTime),"
"weight,"
"socket0,"
"socket1,"
"socket2,"
// NOTE: Add if needed
//"socket3,"
//"socket4,"
//"socket5,"
"attrtype0,"
"attrvalue0, "
"attrtype1,"
"attrvalue1, "
"attrtype2,"
"attrvalue2, "
"attrtype3,"
"attrvalue3, "
"attrtype4,"
"attrvalue4, "
"attrtype5,"
"attrvalue5, "
"attrtype6, "
"attrvalue6 "
"FROM "
"itemshop.itemshop_items AS ITEMS "
"LEFT JOIN itemshop.itemshop_categories AS CATEGORY ON ITEMS.category = CATEGORY.category_index "
"WHERE "
"ITEMS.category = CATEGORY.category_index AND CATEGORY.category_state = 'ENABLED' "
"AND not limitCount = 0 "
"AND count > 0 "
"AND("
"(UNIX_TIMESTAMP(ITEMS.startTime) <= 0 AND UNIX_TIMESTAMP(ITEMS.endTime) <= 0) OR"
"(UNIX_TIMESTAMP(NOW()) >= UNIX_TIMESTAMP(ITEMS.startTime) AND UNIX_TIMESTAMP(NOW()) < UNIX_TIMESTAMP(ITEMS.endTime))"
")"
);
std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
SQLResult* pRes = pkMsg->Get();
m_ItemshopItems.clear();
if (m_pItemshopTableItems)
{
sys_log(0, "RELOAD: itemshop_items");
delete[] m_pItemshopTableItems;
m_pItemshopTableItems = NULL;
}
if (!pRes->uiNumRows)
{
m_iItemshopTableItemSize = 0;
m_pItemshopTableItems = new TItemshopItemTable[m_iItemshopTableItemSize];
memset(m_pItemshopTableItems, 0, sizeof(TItemshopItemTable) * m_iItemshopTableItemSize);
return true;
}
m_iItemshopTableItemSize = pRes->uiNumRows;
m_pItemshopTableItems = new TItemshopItemTable[m_iItemshopTableItemSize];
memset(m_pItemshopTableItems, 0, sizeof(TItemshopItemTable) * m_iItemshopTableItemSize);
TItemshopItemTable* prt = m_pItemshopTableItems;
MYSQL_ROW data;
while ((data = mysql_fetch_row(pRes->pSQLResult)))
{
int col = 0;
// NOTE: Random number -> First non unique after ~20.000 - 40.000 md5 hashes
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1, 4294967295);
unsigned long seed = dist(rng);
// NOTE: To prevent duplicate hashes
while (std::find(m_vec_usedSeeds.begin(), m_vec_usedSeeds.end(), seed) != m_vec_usedSeeds.end())
{
seed = dist(rng);
}
m_vec_usedSeeds.push_back(seed);
boost::uuids::detail::md5 hash;
boost::uuids::detail::md5::digest_type digest;
hash.process_bytes((char*)&seed, sizeof(seed));
hash.get_digest(digest);
strlcpy(prt->hash, MD5_STRING(digest).c_str(), sizeof(prt->hash));
long long llIndex;
str_to_number(llIndex, data[col++]);
str_to_number(prt->dwVnum, data[col++]);
str_to_number(prt->wCount, data[col++]);
str_to_number(prt->ullPrice, data[col++]);
str_to_number(prt->byDiscountPercent, data[col++]);
str_to_number(prt->llLimitCount, data[col++]);
str_to_number(prt->byCategory, data[col++]);
str_to_number(prt->end_time, data[col++]);
str_to_number(prt->weight, data[col++]);
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
{
str_to_number(prt->alSockets[i], data[col++]);
}
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
{
str_to_number(prt->aAttr[i].bType, data[col++]);
str_to_number(prt->aAttr[i].sValue, data[col++]);
}
m_ItemshopItems[prt->hash].first = llIndex;
m_ItemshopItems[prt->hash].second = *prt;
prt++;
}
m_vec_usedSeeds.clear();
return true;
}
#endif
4. DBManager.h
Search:
SQL_PLAYER,
SQL_ACCOUNT,
SQL_COMMON,
Add:
#ifdef ENABLE_ITEMSHOP
SQL_ITEMSHOP,
#endif
5. Main.cpp
Search:
if (CConfig::instance().GetValue("SQL_COMMON", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (common)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_COMMON, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success COMMON\n");
}
else
{
sys_err("SQL_COMMON not configured");
return false;
}
Add:
#ifdef ENABLE_ITEMSHOP
if (CConfig::instance().GetValue("SQL_ITEMSHOP", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (itemshop)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_ITEMSHOP, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success ITEMSHOP\n");
}
else
{
sys_err("SQL_ITEMSHOP not configured");
return false;
}
#endif