-
-
Notifications
You must be signed in to change notification settings - Fork 647
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
1,145 additions
and
698 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/creatures/players/components/player_forge_history.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* Canary - A free and open-source MMORPG server emulator | ||
* Copyright (©) 2019-2022 OpenTibiaBR <[email protected]> | ||
* Repository: https://github.com/opentibiabr/canary | ||
* License: https://github.com/opentibiabr/canary/blob/main/LICENSE | ||
* Contributors: https://github.com/opentibiabr/canary/graphs/contributors | ||
* Website: https://docs.opentibiabr.org/ | ||
*/ | ||
|
||
#include "creatures/players/components/player_forge_history.hpp" | ||
|
||
#include "database/database.hpp" | ||
#include "creatures/players/player.hpp" | ||
#include "utils/tools.hpp" | ||
#include "game/scheduling/save_manager.hpp" | ||
|
||
PlayerForgeHistory::PlayerForgeHistory(Player &player) : m_player(player) {} | ||
|
||
const std::vector<ForgeHistory>& PlayerForgeHistory::get() const { | ||
return m_history; | ||
} | ||
|
||
void PlayerForgeHistory::add(const ForgeHistory& history) { | ||
m_history.push_back(history); | ||
m_modifiedHistory.push_back(history); | ||
} | ||
|
||
void PlayerForgeHistory::remove(int historyId) { | ||
m_removedHistoryIds.push_back(historyId); | ||
m_history.erase( | ||
std::remove_if(m_history.begin(), m_history.end(), | ||
[historyId](const ForgeHistory& h) { return h.id == historyId; }), | ||
m_history.end() | ||
); | ||
} | ||
|
||
bool PlayerForgeHistory::load() { | ||
auto playerGUID = m_player.getGUID(); | ||
Database& db = Database::getInstance(); | ||
auto query = fmt::format("SELECT * FROM forge_history WHERE player_id = {}", playerGUID); | ||
const DBResult_ptr& result = db.storeQuery(query); | ||
if (!result) { | ||
g_logger().debug("Failed to load forge history for player with ID: {}", playerGUID); | ||
return false; | ||
} | ||
|
||
do { | ||
ForgeHistory history; | ||
history.id = result->getNumber<int>("id"); | ||
history.actionType = static_cast<ForgeAction_t>(result->getNumber<uint8_t>("action_type")); | ||
history.description = result->getString("description"); | ||
history.createdAt = result->getNumber<uint64_t>("done_at"); | ||
history.success = result->getNumber<bool>("is_success"); | ||
m_history.push_back(history); | ||
} while (result->next()); | ||
|
||
return true; | ||
} | ||
|
||
bool PlayerForgeHistory::save() { | ||
if (m_modifiedHistory.empty() && m_removedHistoryIds.empty()) { | ||
return true; | ||
} | ||
|
||
auto playerGUID = m_player.getGUID(); | ||
auto removedHistoryIds = m_removedHistoryIds; | ||
auto modifiedHistory = m_modifiedHistory; | ||
|
||
auto forgeHistorySaveTask = [playerGUID, removedHistoryIds, modifiedHistory]() mutable { | ||
Database& db = Database::getInstance(); | ||
|
||
if (!removedHistoryIds.empty()) { | ||
std::string idsToDelete = fmt::format("{}", fmt::join(removedHistoryIds, ", ")); | ||
std::string deleteQuery = fmt::format( | ||
"DELETE FROM `forge_history` WHERE `player_id` = {} AND `id` IN ({})", | ||
playerGUID, idsToDelete | ||
); | ||
|
||
if (!db.executeQuery(deleteQuery)) { | ||
g_logger().error("Failed to delete forge history entries for player with ID: {}", playerGUID); | ||
return; | ||
} | ||
|
||
removedHistoryIds.clear(); | ||
} | ||
|
||
DBInsert insertQuery("INSERT INTO `forge_history` (`id`, `player_id`, `action_type`, `description`, `done_at`, `is_success`) VALUES "); | ||
insertQuery.upsert({ "action_type", "description", "done_at", "is_success" }); | ||
|
||
for (const auto& history : modifiedHistory) { | ||
auto row = fmt::format("{}, {}, {}, {}, {}, {}", | ||
history.id, | ||
playerGUID, | ||
history.actionType, | ||
db.escapeString(history.description), | ||
history.createdAt, | ||
history.success ? 1 : 0); | ||
|
||
if (!insertQuery.addRow(row)) { | ||
g_logger().warn("Failed to add forge history entry for player with ID: {}", playerGUID); | ||
return; | ||
} | ||
|
||
g_logger().debug("Added forge history entry date: {}, for player with ID: {}", formatDate(history.createdAt / 1000), playerGUID); | ||
} | ||
|
||
if (!insertQuery.execute()) { | ||
g_logger().error("Failed to execute insertion for forge history entries for player with ID: {}", playerGUID); | ||
return; | ||
} | ||
}; | ||
|
||
g_saveManager().addTask(forgeHistorySaveTask, "PlayerForgeHistory::save - forgeHistorySaveTask"); | ||
m_modifiedHistory.clear(); | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* Canary - A free and open-source MMORPG server emulator | ||
* Copyright (©) 2019-2022 OpenTibiaBR <[email protected]> | ||
* Repository: https://github.com/opentibiabr/canary | ||
* License: https://github.com/opentibiabr/canary/blob/main/LICENSE | ||
* Contributors: https://github.com/opentibiabr/canary/graphs/contributors | ||
* Website: https://docs.opentibiabr.org/ | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "enums/forge_conversion.hpp" | ||
|
||
class Player; | ||
|
||
struct ForgeHistory { | ||
ForgeAction_t actionType = ForgeAction_t::FUSION; | ||
uint8_t tier = 0; | ||
uint8_t bonus = 0; | ||
|
||
uint64_t createdAt; | ||
|
||
uint16_t id = 0; | ||
|
||
uint64_t cost = 0; | ||
uint64_t dustCost = 0; | ||
uint64_t coresCost = 0; | ||
uint64_t gained = 0; | ||
|
||
bool success = false; | ||
bool tierLoss = false; | ||
bool successCore = false; | ||
bool tierCore = false; | ||
bool convergence = false; | ||
|
||
std::string description; | ||
std::string firstItemName; | ||
std::string secondItemName; | ||
}; | ||
|
||
class PlayerForgeHistory { | ||
public: | ||
PlayerForgeHistory(Player &player); | ||
|
||
const std::vector<ForgeHistory>& get() const; | ||
void add(const ForgeHistory& history); | ||
void remove(int historyId); | ||
|
||
bool load(); | ||
bool save(); | ||
|
||
private: | ||
std::vector<ForgeHistory> m_history; | ||
std::vector<ForgeHistory> m_modifiedHistory; | ||
std::vector<uint16_t> m_removedHistoryIds; | ||
Player &m_player; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/** | ||
* Canary - A free and open-source MMORPG server emulator | ||
* Copyright (©) 2019-2022 OpenTibiaBR <[email protected]> | ||
* Repository: https://github.com/opentibiabr/canary | ||
* License: https://github.com/opentibiabr/canary/blob/main/LICENSE | ||
* Contributors: https://github.com/opentibiabr/canary/graphs/contributors | ||
* Website: https://docs.opentibiabr.org/ | ||
*/ | ||
|
||
#include "creatures/players/components/player_stash.hpp" | ||
|
||
#include "database/database.hpp" | ||
#include "items/item.hpp" | ||
#include "creatures/players/player.hpp" | ||
#include "game/scheduling/save_manager.hpp" | ||
|
||
PlayerStash::PlayerStash(Player &player) : m_player(player) { } | ||
|
||
void PlayerStash::add(uint16_t itemId, uint32_t amount) { | ||
const auto it = m_stashItems.find(itemId); | ||
if (it != m_stashItems.end()) { | ||
m_stashItems[itemId] += amount; | ||
} else { | ||
m_stashItems[itemId] = amount; | ||
} | ||
|
||
m_modifiedItems[itemId] = m_stashItems[itemId]; // Track added/modified items | ||
m_removedItems.erase(itemId); // Remove from removed if it was there | ||
} | ||
|
||
uint32_t PlayerStash::getCount(uint16_t itemId) const { | ||
const auto it = m_stashItems.find(itemId); | ||
if (it != m_stashItems.end()) { | ||
return it->second; | ||
} | ||
return 0; | ||
} | ||
|
||
bool PlayerStash::remove(uint16_t itemId, uint32_t amount) { | ||
auto it = m_stashItems.find(itemId); | ||
if (it != m_stashItems.end()) { | ||
if (it->second > amount) { | ||
m_stashItems[itemId] -= amount; | ||
m_modifiedItems[itemId] = m_stashItems[itemId]; // Track modified item | ||
} else if (it->second == amount) { | ||
m_stashItems.erase(itemId); | ||
m_removedItems.insert(itemId); // Track removed item | ||
m_modifiedItems.erase(itemId); // Ensure it's not in added items | ||
} else { | ||
return false; | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
bool PlayerStash::find(uint16_t itemId) const { | ||
return m_stashItems.find(itemId) != m_stashItems.end(); | ||
} | ||
|
||
const std::map<uint16_t, uint32_t>& PlayerStash::getItems() const { | ||
return m_stashItems; | ||
} | ||
|
||
uint16_t PlayerStash::getSize() const { | ||
uint16_t size = 0; | ||
for (const auto& [itemId, itemCount] : m_stashItems) { | ||
Check warning on line 67 in src/creatures/players/components/player_stash.cpp GitHub Actions / cppcheck[cppcheck] src/creatures/players/components/player_stash.cpp#L67
Raw output
|
||
size += ceil(itemCount / static_cast<float_t>(Item::items[itemId].stackSize)); | ||
} | ||
return size; | ||
} | ||
|
||
bool PlayerStash::save() { | ||
if (m_modifiedItems.empty() && m_removedItems.empty()) { | ||
return true; | ||
} | ||
|
||
const auto playerGUID = m_player.getGUID(); | ||
auto removedItems = m_removedItems; | ||
auto modifiedItems = m_modifiedItems; | ||
|
||
auto stashSaveTask = [playerGUID, removedItems, modifiedItems]() mutable { | ||
Database& db = Database::getInstance(); | ||
|
||
if (!removedItems.empty()) { | ||
std::string removedItemIds = fmt::format("{}", fmt::join(removedItems, ", ")); | ||
std::string deleteQuery = fmt::format( | ||
"DELETE FROM `player_stash` WHERE `player_id` = {} AND `item_id` IN ({})", | ||
playerGUID, removedItemIds | ||
); | ||
|
||
if (!db.executeQuery(deleteQuery)) { | ||
g_logger().error("[PlayerStash::save] - Failed to delete removed items for player: {}", playerGUID); | ||
return; | ||
} | ||
|
||
removedItems.clear(); | ||
} | ||
|
||
DBInsert insertQuery("INSERT INTO `player_stash` (`player_id`, `item_id`, `item_count`) VALUES "); | ||
insertQuery.upsert({ "item_count" }); | ||
|
||
for (const auto& [itemId, itemCount] : modifiedItems) { | ||
auto row = fmt::format("{}, {}, {}", playerGUID, itemId, itemCount); | ||
if (!insertQuery.addRow(row)) { | ||
g_logger().warn("[PlayerStash::save] - Failed to add row for stash item: {}", itemId); | ||
return; | ||
} | ||
} | ||
|
||
if (!insertQuery.execute()) { | ||
g_logger().error("[PlayerStash::save] - Failed to execute insertion for modified stash items for player: {}", playerGUID); | ||
return; | ||
} | ||
}; | ||
|
||
g_saveManager().addTask(stashSaveTask, "PlayerStash::save - stashSaveTask"); | ||
m_modifiedItems.clear(); | ||
|
||
return true; | ||
} | ||
|
||
bool PlayerStash::load() { | ||
Database& db = Database::getInstance(); | ||
auto query = fmt::format("SELECT `item_count`, `item_id` FROM `player_stash` WHERE `player_id` = {}", m_player.getGUID()); | ||
const DBResult_ptr& result = db.storeQuery(query); | ||
if (!result) { | ||
g_logger().debug("[PlayerStash::load] - Failed to load stash items for player: {}", m_player.getName()); | ||
return false; | ||
} | ||
|
||
do { | ||
int itemId = result->getNumber<uint16_t>("item_id"); | ||
int itemCount = result->getNumber<uint32_t>("item_count"); | ||
// The PlayerStash::add function should not be used, to avoid incrementing the add/modified maps | ||
m_stashItems[itemId] = itemCount; | ||
} while (result->next()); | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* Canary - A free and open-source MMORPG server emulator | ||
* Copyright (©) 2019-2022 OpenTibiaBR <[email protected]> | ||
* Repository: https://github.com/opentibiabr/canary | ||
* License: https://github.com/opentibiabr/canary/blob/main/LICENSE | ||
* Contributors: https://github.com/opentibiabr/canary/graphs/contributors | ||
* Website: https://docs.opentibiabr.org/ | ||
*/ | ||
|
||
#pragma once | ||
|
||
class Player; | ||
|
||
class PlayerStash { | ||
public: | ||
PlayerStash(Player &player); | ||
|
||
void add(uint16_t itemId, uint32_t count = 1); | ||
|
||
uint32_t getCount(uint16_t itemId) const; | ||
|
||
bool remove(uint16_t itemId, uint32_t amount); | ||
|
||
bool find(uint16_t itemId) const; | ||
|
||
const std::map<uint16_t, uint32_t>& getItems() const; | ||
|
||
uint16_t getSize() const; | ||
|
||
bool load(); | ||
|
||
bool save(); | ||
|
||
private: | ||
// Map of <itemId, itemCount> for the stash | ||
std::map<uint16_t, uint32_t> m_stashItems; | ||
std::map<uint16_t, uint32_t> m_modifiedItems; | ||
std::set<uint16_t> m_removedItems; | ||
Player& m_player; | ||
}; |
Oops, something went wrong.