Skip to content

Commit

Permalink
Closes #35 Fix for attribute serialization and reward container saving.
Browse files Browse the repository at this point in the history
- Attributes can't use same stream as Augments because attributes use uint8_t's as indicators, and augments writes a uint32_t directly where an indicator should be, so we give augments their own stream.

- Normalized the saving for reward items so they are handled the same way other item saving is done.

- Removed 7 day limit as it was causing problems (only items with the attributes for date were showing up in container, but stackables can't have custom attributes like date).
  • Loading branch information
Codinablack committed Dec 22, 2024
1 parent 79f0ffa commit 6bca150
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 102 deletions.
138 changes: 47 additions & 91 deletions src/iologindata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,43 +485,25 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
if ((result = db.storeQuery(fmt::format("SELECT `sid`, `pid`, `itemtype`, `count`, `attributes`, `augments` FROM `player_rewarditems` WHERE `player_id` = {:d} ORDER BY `sid` DESC", player->getGUID())))) {
loadItems(itemMap, result);

// Map to store containers (bags) for each unique DATE attribute
std::unordered_map<int64_t, Container*> dateContainers;

// Get the current time and calculate the time 7 days ago
time_t now = std::time(nullptr);
time_t seven_days_ago = now - (7 * 24 * 60 * 60); // 7 days in seconds


for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
const std::pair<Item*, uint32_t>& pair = it->second;
Item* item = pair.first;
int32_t pid = pair.second;

if (pid == 0) {
auto& rewardChest = player->getRewardChest();
rewardChest.internalAddThing(item);
} else {
ItemMap::const_iterator it2 = itemMap.find(pid);
if (it2 == itemMap.end()) {
continue;
}

int64_t rewardDate = item->getIntAttr(ITEM_ATTRIBUTE_DATE);

// Skip items older than 7 days
if (rewardDate < static_cast<int64_t>(seven_days_ago)) {
continue;
}

// Create or get existing container for the given DATE attribute
Container* container = nullptr;
auto containerIt = dateContainers.find(rewardDate);
if (containerIt != dateContainers.end()) {
container = containerIt->second;
}
else {
container = new Container(ITEM_REWARD_CONTAINER);
container->setIntAttr(ITEM_ATTRIBUTE_DATE, rewardDate); // Set the DATE attribute on the container
container->setIntAttr(ITEM_ATTRIBUTE_REWARDID, item->getIntAttr(ITEM_ATTRIBUTE_REWARDID));
dateContainers[rewardDate] = container;
Container* container = it2->second.first->getContainer();
if (container) {
container->internalAddThing(item);
}
}

container->internalAddThing(item);
}

for (auto& pair : dateContainers) {
player->getRewardChest().internalAddThing(pair.second);
}
}

Expand Down Expand Up @@ -637,14 +619,15 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
item->serializeAttr(propWriteStream);
auto attributesData = propWriteStream.getStream();

auto augmentStream = PropWriteStream();
const auto& augments = item->getAugments();
propWriteStream.clear();
propWriteStream.write<uint32_t>(augments.size());
augmentStream.clear();
augmentStream.write<uint32_t>(augments.size());

for (const auto& augment : augments) {
augment->serialize(propWriteStream);
augment->serialize(augmentStream);
}
auto augmentsData = propWriteStream.getStream();
auto augmentsData = augmentStream.getStream();

if (!query_insert.addRow(fmt::format("{:d}, {:d}, {:d}, {:d}, {:d}, {:s}, {:s}",
player->getGUID(), pid, runningId, item->getID(), item->getSubType(),
Expand All @@ -671,15 +654,16 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
item->serializeAttr(propWriteStream);
auto attributesData = propWriteStream.getStream();

auto augmentStream = PropWriteStream();
const auto& augments = item->getAugments();
propWriteStream.clear();
propWriteStream.write<uint32_t>(augments.size());
augmentStream.clear();
augmentStream.write<uint32_t>(augments.size());

for (const auto& augment : augments) {
augment->serialize(propWriteStream);
augment->serialize(augmentStream);
}

auto augmentsData = propWriteStream.getStream();
auto augmentsData = augmentStream.getStream();

if (!query_insert.addRow(fmt::format("{:d}, {:d}, {:d}, {:d}, {:d}, {:s}, {:s}",
player->getGUID(), parentId, runningId, item->getID(), item->getSubType(),
Expand Down Expand Up @@ -733,56 +717,40 @@ bool IOLoginData::saveAugments(const Player* player, DBInsert& query_insert, Pro



bool IOLoginData::addRewardItems(uint32_t playerId, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream)
bool IOLoginData::addRewardItems(uint32_t playerID, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream)
{
using ContainerBlock = std::pair<Container*, int32_t>;
std::list<ContainerBlock> queue;

int32_t runningId = 100;
Database& db = Database::getInstance();

DBResult_ptr result = db.storeQuery(fmt::format("SELECT MAX(pid) as max_pid FROM `player_rewarditems` WHERE `player_id` = {:d}", playerId));
int32_t runningId = 1;
int32_t pidCounter = 1;

if (result) {
int32_t maxPid = result->getNumber<int32_t>("max_pid"); // parent container count

if (maxPid > 0) {
pidCounter = maxPid + 1; // id's start at 1
}
}

int32_t parentPid = pidCounter; // very top parent id to start, then traverse using pidCounter

for (const auto& it : itemList) {
int32_t pid = it.first;
Item* item = it.second;

++runningId;
propWriteStream.clear();
item->serializeAttr(propWriteStream);

auto attributesData = propWriteStream.getStream();

auto augmentStream = PropWriteStream();
const auto& augments = item->getAugments();
propWriteStream.clear();
propWriteStream.write<uint32_t>(augments.size());

augmentStream.clear();
augmentStream.write(augments.size());
for (const auto& augment : augments) {
augment->serialize(propWriteStream);
augment->serialize(augmentStream);
}
auto augmentsData = propWriteStream.getStream();
auto augmentsData = augmentStream.getStream();

if (!query_insert.addRow(fmt::format("{:d}, {:d}, {:d}, {:d}, {:d}, {:s}, {:s}",
playerId, parentPid, runningId, item->getID(), item->getSubType(),
playerID, pid, runningId, item->getID(), item->getSubType(),
db.escapeString(attributesData),
db.escapeString(augmentsData)))) {
return false;
}
}

if (Container* container = item->getContainer()) {
queue.emplace_back(container, runningId);
}

++runningId; // Always increment SID upwards
}

while (!queue.empty()) {
Expand All @@ -792,38 +760,37 @@ bool IOLoginData::addRewardItems(uint32_t playerId, const ItemBlockList& itemLis
queue.pop_front();

for (Item* item : container->getItemList()) {
++runningId;
propWriteStream.clear();
item->serializeAttr(propWriteStream);

auto attributesData = propWriteStream.getStream();

auto augmentStream = PropWriteStream();
const auto& augments = item->getAugments();
propWriteStream.clear();
propWriteStream.write<uint32_t>(augments.size());

augmentStream.clear();
augmentStream.write(augments.size());
for (const auto& augment : augments) {
augment->serialize(propWriteStream);
augment->serialize(augmentStream);
}
auto augmentsData = propWriteStream.getStream();
auto augmentsData = augmentStream.getStream();

if (!query_insert.addRow(fmt::format("{:d}, {:d}, {:d}, {:d}, {:d}, {:s}, {:s}",
playerId, parentPid, runningId, item->getID(), item->getSubType(),
playerID, parentId, runningId, item->getID(), item->getSubType(),
db.escapeString(attributesData),
db.escapeString(augmentsData)))) {
return false;
}
}

Container* subContainer = item->getContainer();
if (subContainer) {
if (Container* subContainer = item->getContainer()) {
queue.emplace_back(subContainer, runningId);
}

++runningId; // Always increment SID upwards
}
}

return query_insert.execute();
}


bool IOLoginData::savePlayer(Player* player)
{
if (player->getHealth() <= 0) {
Expand Down Expand Up @@ -1005,18 +972,8 @@ bool IOLoginData::savePlayer(Player* player)
DBInsert rewardQuery("INSERT INTO `player_rewarditems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`, `augments`) VALUES ");
itemList.clear();

int32_t pidCounter = 1;

for (Item* item : player->getRewardChest().getItemList()) {
if (Container* container = item->getContainer()) {
int32_t currentPid = pidCounter++;
for (Item* subItem : container->getItemList()) {
itemList.emplace_back(currentPid, subItem);
}
}
else {
itemList.emplace_back(0, item);
}
itemList.emplace_back(0, item);
}

if (!saveItems(player, itemList, rewardQuery, propWriteStream)) {
Expand Down Expand Up @@ -1229,7 +1186,6 @@ void IOLoginData::loadItems(ItemMap& itemMap, DBResult_ptr result)
if (item) {
// Deserialize the item's attributes
if (!item->unserializeAttr(propStream)) {

}

if (!item->unserializeAugments(augmentStream)) {
Expand Down
23 changes: 13 additions & 10 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream& propStream)
}

default:
return ATTR_READ_ERROR;
return ATTR_READ_CONTINUE;
}

return ATTR_READ_CONTINUE;
Expand Down Expand Up @@ -973,11 +973,8 @@ void Item::serializeAttr(PropWriteStream& propWriteStream) const
const ItemAttributes::CustomAttributeMap* customAttrMap = attributes->getCustomAttributeMap();
propWriteStream.write<uint8_t>(ATTR_CUSTOM_ATTRIBUTES);
propWriteStream.write<uint64_t>(static_cast<uint64_t>(customAttrMap->size()));
for (const auto &entry : *customAttrMap) {
// Serializing key type and value
for (const auto& entry : *customAttrMap) {
propWriteStream.writeString(entry.first);

// Serializing value type and value
entry.second.serialize(propWriteStream);
}
}
Expand All @@ -997,11 +994,11 @@ void Item::serializeAttr(PropWriteStream& propWriteStream) const
propWriteStream.write<uint16_t>(imbuementSlots);
}

propWriteStream.write<uint32_t>(ATTR_IMBUEMENTS);
propWriteStream.write<uint32_t>(imbuements.size());

if (hasImbuements()) {
for (auto entry : imbuements) {
const auto& imbues = getImbuements();
propWriteStream.write<uint8_t>(ATTR_IMBUEMENTS);
propWriteStream.write<uint32_t>(imbues.size());
for (const auto& entry : imbues) {
entry->serialize(propWriteStream);
}
}
Expand All @@ -1010,9 +1007,10 @@ void Item::serializeAttr(PropWriteStream& propWriteStream) const
propWriteStream.write<uint8_t>(ATTR_REWARDID);
propWriteStream.write<uint32_t>(getIntAttr(ITEM_ATTRIBUTE_REWARDID));
}

}



bool Item::hasProperty(ITEMPROPERTY prop) const
{
const ItemType& it = items[id];
Expand Down Expand Up @@ -1803,6 +1801,11 @@ std::vector<std::shared_ptr<Imbuement>>& Item::getImbuements() {
return imbuements;
}

const std::vector<std::shared_ptr<Imbuement>>& Item::getImbuements() const
{
return imbuements;
}

const bool Item::addAugment(std::shared_ptr<Augment>& augment)
{
if (std::find(augments.begin(), augments.end(), augment) != augments.end()) {
Expand Down
2 changes: 2 additions & 0 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,8 @@ class Item : virtual public Thing
bool addImbuement(std::shared_ptr<Imbuement> imbuement, bool created = true);
bool removeImbuement(std::shared_ptr<Imbuement> imbuement, bool decayed = false);
std::vector<std::shared_ptr<Imbuement>>& getImbuements();
const std::vector<std::shared_ptr<Imbuement>>& getImbuements() const;


const bool addAugment(std::string_view augmentName);
const bool addAugment(std::shared_ptr<Augment>& augment);
Expand Down
1 change: 0 additions & 1 deletion src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1900,7 +1900,6 @@ void Monster::death(Creature*)
auto count = uniform_random(1, lootBlock.countmax);

if (chance <= adjustedChance) {
// Ensure that the mostScoreContributor can receive multiple unique items
auto lootItem = Item::CreateItem(lootBlock.id, count);
if (!lootItem->isStackable()) {
lootItem->setIntAttr(ITEM_ATTRIBUTE_DATE, currentTime);
Expand Down

0 comments on commit 6bca150

Please sign in to comment.