Implement bazaar item identity and offline trading rework

This commit is contained in:
Vayle
2026-03-19 22:18:32 -04:00
90 changed files with 5379 additions and 2165 deletions
+2
View File
@@ -191,6 +191,7 @@ set(repositories
repositories/base/base_character_leadership_abilities_repository.h
repositories/base/base_character_material_repository.h
repositories/base/base_character_memmed_spells_repository.h
repositories/base/base_character_offline_transactions_repository.h
repositories/base/base_character_parcels_containers_repository.h
repositories/base/base_character_parcels_repository.h
repositories/base/base_character_peqzone_flags_repository.h
@@ -389,6 +390,7 @@ set(repositories
repositories/character_leadership_abilities_repository.h
repositories/character_material_repository.h
repositories/character_memmed_spells_repository.h
repositories/character_offline_transactions_repository.h
repositories/character_parcels_containers_repository.h
repositories/character_parcels_repository.h
repositories/character_peqzone_flags_repository.h
+42 -39
View File
@@ -188,11 +188,11 @@ Bazaar::GetSearchResults(
);
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
search_criteria_trader.append(fmt::format(" AND trader.character_id = {}", search.trader_id));
}
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
search_criteria_trader.append(fmt::format(" AND trader.character_id = {}", search.trader_id));
}
}
@@ -263,16 +263,24 @@ Bazaar::GetSearchResults(
}
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
std::vector<std::string> trader_items_ids{};
std::unordered_set<std::string> trader_items_ids{};
auto const trader_results = TraderRepository::GetBazaarTraderDetails(
db,
search_criteria_trader,
search.item_name,
field_criteria_items,
where_criteria_items,
search.max_results
);
auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader);
if (trader_results.empty()) {
LogTradingDetail("Bazaar - No traders found in bazaar search.");
return all_entries;
}
for (auto const &i: trader_results) {
trader_items_ids.push_back(std::to_string(i.trader.item_id));
trader_items_ids.emplace(std::to_string(i.trader.item_id));
}
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
@@ -291,43 +299,38 @@ Bazaar::GetSearchResults(
all_entries.reserve(trader_results.size());
for (auto const& t:trader_results) {
if (!item_results.contains(t.trader.item_id)) {
continue;
}
for (auto const& t:trader_results) {
if (!item_results.contains(t.trader.item_id)) {
continue;
}
BazaarSearchResultsFromDB_Struct r{};
r.count = 1;
r.trader_id = t.trader.char_id;
r.serial_number = t.trader.item_sn;
r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id;
r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable;
r.icon_id = item_results.at(t.trader.item_id).icon;
r.trader_zone_id = t.trader.char_zone_id;
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
r.trader_entity_id = t.trader.char_entity_id;
r.serial_number_RoF = fmt::format("{:016}\0", t.trader.item_sn);
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
r.trader_name = fmt::format("{:.63}\0", t.trader_name);
r.item_stat = item_results.at(t.trader.item_id).stats;
BazaarSearchResultsFromDB_Struct r{};
r.count = 1;
r.trader_id = t.trader.character_id;
r.item_unique_id = t.trader.item_unique_id;
r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id;
r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable;
r.icon_id = item_results.at(t.trader.item_id).icon;
r.trader_zone_id = t.trader.char_zone_id;
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
r.trader_entity_id = t.trader.char_entity_id;
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
r.trader_name = fmt::format("{:.63}\0", t.trader_name);
r.item_stat = item_results.at(t.trader.item_id).stats;
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (convert ||
char_zone_id != Zones::BAZAAR ||
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
) {
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
}
}
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (convert ||
char_zone_id != Zones::BAZAAR ||
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
) {
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
}
}
all_entries.push_back(r);
}
if (all_entries.size() > search.max_results) {
all_entries.resize(search.max_results);
}
all_entries.push_back(r);
}
LogTrading("Returning [{}] items from search results", all_entries.size());
+541 -3
View File
@@ -33,6 +33,7 @@
#include "common/repositories/character_data_repository.h"
#include "common/repositories/character_languages_repository.h"
#include "common/repositories/character_leadership_abilities_repository.h"
#include "common/repositories/character_parcels_containers_repository.h"
#include "common/repositories/character_parcels_repository.h"
#include "common/repositories/character_pet_name_repository.h"
#include "common/repositories/character_skills_repository.h"
@@ -49,6 +50,8 @@
#include "common/repositories/raid_details_repository.h"
#include "common/repositories/raid_members_repository.h"
#include "common/repositories/reports_repository.h"
#include "common/repositories/item_unique_id_reservations_repository.h"
#include "common/repositories/offline_character_sessions_repository.h"
#include "common/repositories/trader_repository.h"
#include "common/repositories/variables_repository.h"
#include "common/repositories/zone_repository.h"
@@ -56,8 +59,10 @@
#include "common/strings.h"
#include "common/zone_store.h"
#include <map>
#include <algorithm>
#include <map>
#include "common/repositories/sharedbank_repository.h"
extern Client client;
@@ -187,7 +192,7 @@ void Database::LoginIP(uint32 account_id, const std::string& login_ip)
QueryDatabase(query);
}
int16 Database::GetAccountStatus(uint32 account_id)
AccountStatus::StatusRecord Database::GetAccountStatus(uint32 account_id)
{
auto e = AccountRepository::FindOne(*this, account_id);
@@ -199,7 +204,11 @@ int16 Database::GetAccountStatus(uint32 account_id)
AccountRepository::UpdateOne(*this, e);
}
return e.status;
AccountStatus::StatusRecord result{};
result.status = e.status;
result.offline = e.offline;
return result;
}
uint32 Database::CreateAccount(
@@ -2242,6 +2251,7 @@ void Database::ClearGuildOnlineStatus()
void Database::ClearTraderDetails()
{
TraderRepository::Truncate(*this);
AccountRepository::ClearAllOfflineStatus(*this);
}
void Database::ClearBuyerDetails()
@@ -2265,3 +2275,531 @@ uint64_t Database::GetNextTableId(const std::string &table_name)
return 1;
}
bool Database::ReserveItemUniqueId(const std::string &item_unique_id)
{
return ItemUniqueIdReservationsRepository::Reserve(*this, item_unique_id);
}
std::string Database::ReserveNewItemUniqueId()
{
return ItemUniqueIdReservationsRepository::ReserveNew(*this);
}
bool Database::EnsureItemUniqueId(std::string &item_unique_id)
{
if (item_unique_id.empty()) {
item_unique_id = ReserveNewItemUniqueId();
}
if (item_unique_id.empty()) {
return false;
}
return ReserveItemUniqueId(item_unique_id);
}
void Database::ConvertInventoryToNewUniqueId()
{
LogInfo("Converting inventory entries with missing item_unique_id");
auto results = InventoryRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
if (results.empty()) {
return;
}
TransactionBegin();
uint32 index = 0;
const uint32 batch_size = 1000;
std::vector<InventoryRepository::Inventory> queue{};
queue.reserve(batch_size);
for (auto &r: results) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
index++;
if (index >= batch_size) {
InventoryRepository::ReplaceMany(*this, queue);
index = 0;
queue.clear();
}
}
if (!queue.empty()) {
InventoryRepository::ReplaceMany(*this, queue);
}
TransactionCommit();
LogInfo("Converted {} records", results.size());
}
void Database::ConvertTraderToNewUniqueId()
{
LogInfo("Converting trader entries with missing item_unique_id");
auto results = TraderRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
if (results.empty()) {
return;
}
TransactionBegin();
uint32 index = 0;
const uint32 batch_size = 1000;
std::vector<TraderRepository::Trader> queue{};
queue.reserve(batch_size);
for (auto &r: results) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
index++;
if (index >= batch_size) {
TraderRepository::ReplaceMany(*this, queue);
index = 0;
queue.clear();
}
}
if (!queue.empty()) {
TraderRepository::ReplaceMany(*this, queue);
}
TransactionCommit();
LogInfo("Converted {} trader records", results.size());
}
void Database::ConvertParcelsToNewUniqueId()
{
LogInfo("Converting parcel entries with missing item_unique_id");
auto parcels = CharacterParcelsRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
auto parcel_contents = CharacterParcelsContainersRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
TransactionBegin();
if (!parcels.empty()) {
std::vector<CharacterParcelsRepository::CharacterParcels> queue{};
queue.reserve(parcels.size());
for (auto &r : parcels) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
}
if (!queue.empty()) {
CharacterParcelsRepository::ReplaceMany(*this, queue);
}
}
if (!parcel_contents.empty()) {
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> queue{};
queue.reserve(parcel_contents.size());
for (auto &r : parcel_contents) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
}
if (!queue.empty()) {
CharacterParcelsContainersRepository::ReplaceMany(*this, queue);
}
}
TransactionCommit();
LogInfo(
"Converted {} parcel rows and {} parcel container rows",
parcels.size(),
parcel_contents.size()
);
}
void Database::ConvertInventorySnapshotsToNewUniqueId()
{
LogInfo("Converting inventory snapshots with missing item_unique_id");
auto results = InventorySnapshotsRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
if (results.empty()) {
return;
}
TransactionBegin();
uint32 index = 0;
const uint32 batch_size = 1000;
std::vector<InventorySnapshotsRepository::InventorySnapshots> queue{};
queue.reserve(batch_size);
for (auto &r : results) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
index++;
if (index >= batch_size) {
InventorySnapshotsRepository::ReplaceMany(*this, queue);
index = 0;
queue.clear();
}
}
if (!queue.empty()) {
InventorySnapshotsRepository::ReplaceMany(*this, queue);
}
TransactionCommit();
LogInfo("Converted {} inventory snapshot rows", results.size());
}
void Database::ConvertSharedbankToNewUniqueId()
{
LogInfo("Converting shared bank entries with missing item_unique_id");
auto results = SharedbankRepository::GetWhere(*this, "`item_unique_id` IS NULL OR `item_unique_id` = ''");
if (results.empty()) {
return;
}
TransactionBegin();
uint32 index = 0;
const uint32 batch_size = 1000;
std::vector<SharedbankRepository::Sharedbank> queue{};
queue.reserve(batch_size);
for (auto &r: results) {
if (!EnsureItemUniqueId(r.item_unique_id)) {
continue;
}
queue.push_back(r);
index++;
if (index >= batch_size) {
SharedbankRepository::ReplaceMany(*this, queue);
index = 0;
queue.clear();
}
}
if (!queue.empty()) {
SharedbankRepository::ReplaceMany(*this, queue);
}
TransactionCommit();
LogInfo("Converted {} records", results.size());
}
void Database::ClearOfflineTradingState()
{
LogInfo("Clearing offline trading state");
ClearTraderDetails();
ClearBuyerDetails();
AccountRepository::ClearAllOfflineStatus(*this);
OfflineCharacterSessionsRepository::Truncate(*this);
}
static bool DoesColumnExist(Database &db, const std::string &table_name, const std::string &column_name)
{
auto results = db.QueryDatabase(
fmt::format(
"SHOW COLUMNS FROM `{}` LIKE '{}'",
table_name,
Strings::Escape(column_name)
)
);
return results.Success() && results.RowCount() == 1;
}
static bool GetSingleCount(Database &db, const std::string &query, uint64 &count)
{
auto results = db.QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0) {
return false;
}
auto row = results.begin();
count = row[0] ? Strings::ToUnsignedBigInt(row[0]) : 0;
return true;
}
static bool ValidateItemUniqueIdMigrationSchema(Database &db, bool verbose)
{
struct ColumnRequirement {
std::string table;
std::string column;
};
const std::vector<ColumnRequirement> required_columns = {
{"inventory", "item_unique_id"},
{"sharedbank", "item_unique_id"},
{"trader", "item_unique_id"},
{"character_parcels", "item_unique_id"},
{"character_parcels_containers", "item_unique_id"},
{"inventory_snapshots", "item_unique_id"},
{"account", "offline"},
};
const std::vector<std::string> required_tables = {
"character_offline_transactions",
"offline_character_sessions",
"item_unique_id_reservations",
};
bool success = true;
for (const auto &table_name : required_tables) {
if (db.DoesTableExist(table_name)) {
continue;
}
LogError(
"Missing required table [{}] for bazaar item unique id migration. Run database updates before continuing.",
table_name
);
success = false;
}
for (const auto &requirement : required_columns) {
if (!db.DoesTableExist(requirement.table)) {
LogError(
"Missing required table [{}] for bazaar item unique id migration. Run database updates before continuing.",
requirement.table
);
success = false;
continue;
}
if (DoesColumnExist(db, requirement.table, requirement.column)) {
continue;
}
LogError(
"Missing required column [{}].[{}] for bazaar item unique id migration. Run database updates before continuing.",
requirement.table,
requirement.column
);
success = false;
}
if (verbose && success) {
LogInfo("Bazaar item unique id migration schema validation passed");
}
return success;
}
bool Database::PreflightItemUniqueIdMigration(bool verbose)
{
struct CheckTarget {
std::string table;
bool requires_uniqueness;
};
const std::vector<CheckTarget> targets = {
{"inventory", true},
{"sharedbank", true},
{"trader", true},
{"character_parcels", false},
{"character_parcels_containers", false},
{"inventory_snapshots", false},
};
if (!ValidateItemUniqueIdMigrationSchema(*this, verbose)) {
return false;
}
bool success = true;
for (const auto &target : targets) {
uint64 missing = 0;
uint64 duplicates = 0;
const auto missing_query = fmt::format(
"SELECT COUNT(*) FROM {} WHERE item_unique_id IS NULL OR item_unique_id = ''",
target.table
);
if (!GetSingleCount(*this, missing_query, missing)) {
LogError("Failed running item unique id preflight query [{}]", missing_query);
success = false;
continue;
}
if (target.requires_uniqueness) {
const auto duplicate_query = fmt::format(
"SELECT COUNT(*) FROM (SELECT item_unique_id FROM {} WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' "
"GROUP BY item_unique_id HAVING COUNT(*) > 1) AS duplicates",
target.table
);
if (!GetSingleCount(*this, duplicate_query, duplicates)) {
LogError("Failed running item unique id duplicate preflight query [{}]", duplicate_query);
success = false;
continue;
}
}
if (verbose || missing || duplicates) {
LogInfo(
"Item unique id preflight [{}] missing [{}] duplicate_groups [{}]",
target.table,
missing,
duplicates
);
}
success = success && duplicates == 0;
}
uint64 live_cross_table_duplicates = 0;
const auto cross_table_duplicate_query =
"SELECT COUNT(*) FROM ("
"SELECT item_unique_id FROM ("
"SELECT item_unique_id FROM inventory WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' "
"UNION ALL "
"SELECT item_unique_id FROM sharedbank WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' "
"UNION ALL "
"SELECT item_unique_id FROM trader WHERE item_unique_id IS NOT NULL AND item_unique_id <> ''"
") AS live_ids GROUP BY item_unique_id HAVING COUNT(*) > 1"
") AS duplicates";
if (!GetSingleCount(*this, cross_table_duplicate_query, live_cross_table_duplicates)) {
LogError("Failed running cross-table item_unique_id preflight query");
success = false;
}
uint64 offline_sessions = 0;
if (!GetSingleCount(*this, "SELECT COUNT(*) FROM offline_character_sessions", offline_sessions)) {
LogError("Failed counting offline_character_sessions during preflight");
success = false;
}
uint64 account_offline = 0;
if (!GetSingleCount(*this, "SELECT COUNT(*) FROM account WHERE offline = 1", account_offline)) {
LogError("Failed counting offline accounts during preflight");
success = false;
}
if (verbose || live_cross_table_duplicates || offline_sessions || account_offline) {
LogInfo(
"Item unique id preflight live_cross_table_duplicates [{}] offline_sessions [{}] account_offline [{}]",
live_cross_table_duplicates,
offline_sessions,
account_offline
);
}
return success && live_cross_table_duplicates == 0;
}
bool Database::MigrateItemUniqueIdData(bool clear_trading_state, bool verbose)
{
if (!ValidateItemUniqueIdMigrationSchema(*this, verbose)) {
return false;
}
if (clear_trading_state) {
ClearOfflineTradingState();
}
ConvertInventoryToNewUniqueId();
ConvertSharedbankToNewUniqueId();
ConvertTraderToNewUniqueId();
ConvertParcelsToNewUniqueId();
ConvertInventorySnapshotsToNewUniqueId();
ItemUniqueIdReservationsRepository::PopulateFromTable(*this, "inventory", "item_unique_id");
ItemUniqueIdReservationsRepository::PopulateFromTable(*this, "sharedbank", "item_unique_id");
ItemUniqueIdReservationsRepository::PopulateFromTable(*this, "trader", "item_unique_id");
return VerifyItemUniqueIdMigration(verbose);
}
bool Database::VerifyItemUniqueIdMigration(bool verbose)
{
if (!ValidateItemUniqueIdMigrationSchema(*this, verbose)) {
return false;
}
uint64 inventory_missing = 0;
uint64 sharedbank_missing = 0;
uint64 trader_missing = 0;
uint64 parcel_missing = 0;
uint64 parcel_container_missing = 0;
uint64 snapshot_missing = 0;
uint64 inventory_duplicates = 0;
uint64 sharedbank_duplicates = 0;
uint64 trader_duplicates = 0;
uint64 live_cross_table_duplicates = 0;
uint64 offline_sessions = 0;
uint64 account_offline = 0;
const bool queries_succeeded =
GetSingleCount(*this, "SELECT COUNT(*) FROM inventory WHERE item_unique_id IS NULL OR item_unique_id = ''", inventory_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM sharedbank WHERE item_unique_id IS NULL OR item_unique_id = ''", sharedbank_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM trader WHERE item_unique_id IS NULL OR item_unique_id = ''", trader_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM character_parcels WHERE item_unique_id IS NULL OR item_unique_id = ''", parcel_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM character_parcels_containers WHERE item_unique_id IS NULL OR item_unique_id = ''", parcel_container_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM inventory_snapshots WHERE item_unique_id IS NULL OR item_unique_id = ''", snapshot_missing) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM (SELECT item_unique_id FROM inventory WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' GROUP BY item_unique_id HAVING COUNT(*) > 1) AS duplicates", inventory_duplicates) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM (SELECT item_unique_id FROM sharedbank WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' GROUP BY item_unique_id HAVING COUNT(*) > 1) AS duplicates", sharedbank_duplicates) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM (SELECT item_unique_id FROM trader WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' GROUP BY item_unique_id HAVING COUNT(*) > 1) AS duplicates", trader_duplicates) &&
GetSingleCount(
*this,
"SELECT COUNT(*) FROM ("
"SELECT item_unique_id FROM ("
"SELECT item_unique_id FROM inventory WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' "
"UNION ALL "
"SELECT item_unique_id FROM sharedbank WHERE item_unique_id IS NOT NULL AND item_unique_id <> '' "
"UNION ALL "
"SELECT item_unique_id FROM trader WHERE item_unique_id IS NOT NULL AND item_unique_id <> ''"
") AS live_ids GROUP BY item_unique_id HAVING COUNT(*) > 1"
") AS duplicates",
live_cross_table_duplicates
) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM offline_character_sessions", offline_sessions) &&
GetSingleCount(*this, "SELECT COUNT(*) FROM account WHERE offline = 1", account_offline);
if (!queries_succeeded) {
LogError("Item unique id verification failed to execute one or more validation queries");
return false;
}
if (verbose || inventory_missing || sharedbank_missing || trader_missing || parcel_missing || parcel_container_missing || snapshot_missing ||
inventory_duplicates || sharedbank_duplicates || trader_duplicates || live_cross_table_duplicates || offline_sessions || account_offline) {
LogInfo(
"Item unique id verification inventory_missing [{}] sharedbank_missing [{}] trader_missing [{}] "
"parcel_missing [{}] parcel_container_missing [{}] snapshot_missing [{}] inventory_duplicates [{}] "
"sharedbank_duplicates [{}] trader_duplicates [{}] live_cross_table_duplicates [{}] offline_sessions [{}] account_offline [{}]",
inventory_missing,
sharedbank_missing,
trader_missing,
parcel_missing,
parcel_container_missing,
snapshot_missing,
inventory_duplicates,
sharedbank_duplicates,
trader_duplicates,
live_cross_table_duplicates,
offline_sessions,
account_offline
);
}
return inventory_missing == 0 &&
sharedbank_missing == 0 &&
trader_missing == 0 &&
parcel_missing == 0 &&
parcel_container_missing == 0 &&
snapshot_missing == 0 &&
inventory_duplicates == 0 &&
sharedbank_duplicates == 0 &&
trader_duplicates == 0 &&
live_cross_table_duplicates == 0 &&
offline_sessions == 0 &&
account_offline == 0;
}
+13 -1
View File
@@ -158,8 +158,8 @@ public:
const std::string GetLiveChar(uint32 account_id);
bool SetAccountStatus(const std::string& account_name, int16 status);
bool SetLocalPassword(uint32 account_id, const std::string& password);
AccountStatus::StatusRecord GetAccountStatus(uint32 account_id);
bool UpdateLiveChar(const std::string& name, uint32 account_id);
int16 GetAccountStatus(uint32 account_id);
void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum);
uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
uint32 CreateAccount(
@@ -264,6 +264,18 @@ public:
void Decode(std::string &in);
uint64_t GetNextTableId(const std::string& table_name);
bool ReserveItemUniqueId(const std::string &item_unique_id);
std::string ReserveNewItemUniqueId();
bool EnsureItemUniqueId(std::string &item_unique_id);
bool PreflightItemUniqueIdMigration(bool verbose = false);
bool MigrateItemUniqueIdData(bool clear_trading_state = true, bool verbose = false);
bool VerifyItemUniqueIdMigration(bool verbose = false);
void ConvertInventoryToNewUniqueId();
void ConvertTraderToNewUniqueId();
void ConvertParcelsToNewUniqueId();
void ConvertInventorySnapshotsToNewUniqueId();
void ConvertSharedbankToNewUniqueId();
void ClearOfflineTradingState();
private:
Mutex Mvarcache;
+177
View File
@@ -7211,6 +7211,183 @@ ALTER TABLE `character_buffs`
.sql = R"(
ALTER TABLE `character_pet_buffs`
ADD COLUMN `suppressed` tinyint(1) unsigned NOT NULL DEFAULT 0 AFTER `instrument_mod`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9331,
.description = "2026_03_19_inventory_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `inventory` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `inventory`
DROP COLUMN `guid`,
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `ornament_hero_model`,
ADD UNIQUE INDEX `idx_item_unique_id` (`item_unique_id`);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9332,
.description = "2026_03_19_sharedbank_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `sharedbank` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `sharedbank`
DROP COLUMN `guid`,
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `ornament_hero_model`,
ADD UNIQUE INDEX `idx_item_unique_id` (`item_unique_id`);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9333,
.description = "2026_03_19_character_parcels_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `character_parcels` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_parcels`
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `aug_slot_6`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9334,
.description = "2026_03_19_character_parcels_containers_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `character_parcels_containers` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_parcels_containers`
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `item_id`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9335,
.description = "2026_03_19_inventory_snapshots_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `inventory_snapshots` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `inventory_snapshots`
DROP PRIMARY KEY,
CHANGE COLUMN `charid` `character_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_index`,
CHANGE COLUMN `slotid` `slot_id` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0' AFTER `character_id`,
CHANGE COLUMN `itemid` `item_id` INT(11) UNSIGNED NULL DEFAULT '0' AFTER `slot_id`,
CHANGE COLUMN `augslot1` `augment_one` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0' AFTER `color`,
CHANGE COLUMN `augslot2` `augment_two` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_one`,
CHANGE COLUMN `augslot3` `augment_three` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_two`,
CHANGE COLUMN `augslot4` `augment_four` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_three`,
CHANGE COLUMN `augslot5` `augment_five` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0' AFTER `augment_four`,
CHANGE COLUMN `augslot6` `augment_six` MEDIUMINT(7) NOT NULL DEFAULT '0' AFTER `augment_five`,
CHANGE COLUMN `ornamenticon` `ornament_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `custom_data`,
CHANGE COLUMN `ornamentidfile` `ornament_idfile` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `ornament_icon`,
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `ornament_hero_model`,
DROP COLUMN `guid`;
ALTER TABLE `inventory_snapshots`
ADD PRIMARY KEY (`time_index`, `character_id`, `slot_id`) USING BTREE;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9336,
.description = "2026_03_19_trader_item_unique_id.sql",
.check = "SHOW COLUMNS FROM `trader` LIKE 'item_unique_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `trader`
CHANGE COLUMN `char_id` `character_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
ADD COLUMN `item_unique_id` VARCHAR(16) NULL DEFAULT NULL AFTER `item_id`,
CHANGE COLUMN `aug_slot_1` `augment_one` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `item_unique_id`,
CHANGE COLUMN `aug_slot_2` `augment_two` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_one`,
CHANGE COLUMN `aug_slot_3` `augment_three` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_two`,
CHANGE COLUMN `aug_slot_4` `augment_four` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_three`,
CHANGE COLUMN `aug_slot_5` `augment_five` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_four`,
CHANGE COLUMN `aug_slot_6` `augment_six` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `augment_five`,
DROP COLUMN `item_sn`,
DROP INDEX `idx_trader_item_sn`,
DROP INDEX `idx_trader_char`,
ADD INDEX `charid_slotid` (`character_id`, `slot_id`) USING BTREE,
ADD INDEX `idx_trader_char` (`character_id`, `char_zone_id`, `char_zone_instance_id`) USING BTREE,
ADD UNIQUE INDEX `idx_item_unique_id` (`item_unique_id`);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9337,
.description = "2026_03_19_account_offline_status.sql",
.check = "SHOW COLUMNS FROM `account` LIKE 'offline'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `account`
ADD COLUMN `offline` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_creation`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9338,
.description = "2026_03_19_character_offline_transactions.sql",
.check = "SHOW TABLES LIKE 'character_offline_transactions'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE IF NOT EXISTS `character_offline_transactions` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`character_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`type` INT(10) UNSIGNED NULL DEFAULT '0',
`item_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`quantity` INT(11) NULL DEFAULT '0',
`price` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`buyer_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_character_id` (`character_id`)
) COLLATE='latin1_swedish_ci' ENGINE=InnoDB;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9339,
.description = "2026_03_19_offline_character_sessions.sql",
.check = "SHOW TABLES LIKE 'offline_character_sessions'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE IF NOT EXISTS `offline_character_sessions` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`account_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`character_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`mode` VARCHAR(16) NOT NULL DEFAULT 'trader',
`zone_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`instance_id` INT(11) NOT NULL DEFAULT '0',
`entity_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`started_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_account_id` (`account_id`),
KEY `idx_character_id` (`character_id`),
KEY `idx_zone_instance` (`zone_id`, `instance_id`)
) COLLATE='latin1_swedish_ci' ENGINE=InnoDB;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9340,
.description = "2026_03_19_item_unique_id_reservations.sql",
.check = "SHOW TABLES LIKE 'item_unique_id_reservations'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE IF NOT EXISTS `item_unique_id_reservations` (
`item_unique_id` VARCHAR(16) NOT NULL,
`reserved_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`item_unique_id`)
) COLLATE='latin1_swedish_ci' ENGINE=InnoDB;
)",
.content_schema_update = false
},
+6 -2
View File
@@ -58,6 +58,7 @@ namespace DatabaseSchema {
{"character_leadership_abilities", "id"},
{"character_material", "id"},
{"character_memmed_spells", "id"},
{"character_offline_transactions", "character_id"},
{"character_parcels", "char_id"},
{"character_parcels_containers", "id"},
{"character_pet_buffs", "char_id"},
@@ -80,13 +81,13 @@ namespace DatabaseSchema {
{"guilds", "id"},
{"instance_list_player", "id"},
{"inventory", "character_id"},
{"inventory_snapshots", "charid"},
{"inventory_snapshots", "character_id"},
{"keyring", "char_id"},
{"mail", "charid"},
{"player_titlesets", "char_id"},
{"quest_globals", "charid"},
{"timers", "char_id"},
{"trader", "char_id"},
{"trader", "character_id"},
{"zone_flags", "charID"}
};
}
@@ -133,6 +134,7 @@ namespace DatabaseSchema {
"character_leadership_abilities",
"character_material",
"character_memmed_spells",
"character_offline_transactions",
"character_parcels",
"character_parcels_containers",
"character_pet_buffs",
@@ -162,8 +164,10 @@ namespace DatabaseSchema {
"instance_list_player",
"inventory",
"inventory_snapshots",
"item_unique_id_reservations",
"keyring",
"mail",
"offline_character_sessions",
"petitions",
"player_titlesets",
"quest_globals",
+5
View File
@@ -45,6 +45,11 @@ namespace AccountStatus {
constexpr uint8 Max = 255;
std::string GetName(uint8 account_status);
struct StatusRecord {
int16 status;
uint32 offline;
};
}
static std::map<uint8, std::string> account_status_names = {
+3
View File
@@ -71,6 +71,8 @@ N(OP_BuyerItems),
N(OP_CameraEffect),
N(OP_Camp),
N(OP_CancelSneakHide),
N(OP_CancelOfflineTrader),
N(OP_CancelOfflineTraderResponse),
N(OP_CancelTask),
N(OP_CancelTrade),
N(OP_CashReward),
@@ -381,6 +383,7 @@ N(OP_MultiLineMsg),
N(OP_NewSpawn),
N(OP_NewTitlesAvailable),
N(OP_NewZone),
N(OP_Offline),
N(OP_OnLevelMessage),
N(OP_OpenContainer),
N(OP_OpenDiscordMerchant),
+9 -1
View File
@@ -48,6 +48,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
ClientUnknown::constants::EXPANSIONS_MASK,
ClientUnknown::INULL,
ClientUnknown::INULL,
ClientUnknown::INULL,
ClientUnknown::INULL
),
/*[ClientVersion::Client62] =*/
@@ -57,6 +58,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Client62::constants::EXPANSIONS_MASK,
Client62::INULL,
Client62::INULL,
Client62::INULL,
Client62::INULL
),
/*[ClientVersion::Titanium] =*/
@@ -66,6 +68,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Titanium::constants::EXPANSIONS_MASK,
Titanium::constants::CHARACTER_CREATION_LIMIT,
Titanium::constants::SAY_LINK_BODY_SIZE,
Titanium::INULL,
Titanium::INULL
),
/*[ClientVersion::SoF] =*/
@@ -75,6 +78,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoF::constants::EXPANSIONS_MASK,
SoF::constants::CHARACTER_CREATION_LIMIT,
SoF::constants::SAY_LINK_BODY_SIZE,
SoF::INULL,
SoF::INULL
),
/*[ClientVersion::SoD] =*/
@@ -84,6 +88,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoD::constants::EXPANSIONS_MASK,
SoD::constants::CHARACTER_CREATION_LIMIT,
SoD::constants::SAY_LINK_BODY_SIZE,
SoD::INULL,
SoD::INULL
),
/*[ClientVersion::UF] =*/
@@ -93,6 +98,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
UF::constants::EXPANSIONS_MASK,
UF::constants::CHARACTER_CREATION_LIMIT,
UF::constants::SAY_LINK_BODY_SIZE,
UF::INULL,
UF::INULL
),
/*[ClientVersion::RoF] =*/
@@ -102,6 +108,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF::constants::EXPANSIONS_MASK,
RoF::constants::CHARACTER_CREATION_LIMIT,
RoF::constants::SAY_LINK_BODY_SIZE,
RoF::INULL,
RoF::INULL
),
/*[ClientVersion::RoF2] =*/
@@ -111,7 +118,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF2::constants::EXPANSIONS_MASK,
RoF2::constants::CHARACTER_CREATION_LIMIT,
RoF2::constants::SAY_LINK_BODY_SIZE,
RoF2::constants::MAX_BAZAAR_TRADERS
RoF2::constants::MAX_BAZAAR_TRADERS,
RoF2::constants::MAX_BAZAAR_TRANSACTION
)
};
+5 -2
View File
@@ -42,6 +42,7 @@ namespace EQ
int16 CharacterCreationLimit;
size_t SayLinkBodySize;
uint32 BazaarTraderLimit;
uint64 BazaarMaxTransaction;
LookupEntry(const LookupEntry *lookup_entry) { }
LookupEntry(
@@ -50,14 +51,16 @@ namespace EQ
uint32 ExpansionsMask,
int16 CharacterCreationLimit,
size_t SayLinkBodySize,
uint32 BazaarTraderLimit
uint32 BazaarTraderLimit,
uint64 BazaarMaxTransaction
) :
Expansion(Expansion),
ExpansionBit(ExpansionBit),
ExpansionsMask(ExpansionsMask),
CharacterCreationLimit(CharacterCreationLimit),
SayLinkBodySize(SayLinkBodySize),
BazaarTraderLimit(BazaarTraderLimit)
BazaarTraderLimit(BazaarTraderLimit),
BazaarMaxTransaction(BazaarMaxTransaction)
{ }
};
+95 -18
View File
@@ -327,6 +327,7 @@ union
bool buyer;
bool untargetable;
uint32 npc_tint_id;
bool offline;
};
struct PlayerState_Struct {
@@ -3094,7 +3095,7 @@ struct BazaarSearchCriteria_Struct {
struct BazaarInspect_Struct {
uint32 action;
char player_name[64];
uint32 serial_number;
char item_unique_id[17];
uint32 item_id;
uint32 trader_id;
};
@@ -3730,6 +3731,36 @@ struct Trader_Struct {
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
};
struct TraderItems_Struct {
std::string item_unique_id;
uint32 item_id;
uint64 item_cost;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(item_unique_id),
CEREAL_NVP(item_id),
CEREAL_NVP(item_cost)
);
}
};
struct TraderClientMessaging_Struct {
/*000*/ uint32 action;
/*008*/ std::vector<TraderItems_Struct> items;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(items)
);
}
};
struct ClickTrader_Struct {
/*000*/ uint32 action;
/*004*/ uint32 unknown_004;
@@ -3743,6 +3774,52 @@ struct GetItems_Struct{
int32 charges[EQ::invtype::BAZAAR_SIZE];
};
struct Trader2_Struct {
uint32 action;
uint32 unknown_004;
uint64 items[EQ::invtype::BAZAAR_SIZE];
uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
std::string serial_number[EQ::invtype::BAZAAR_SIZE];
};
struct BazaarTraderDetails {
uint64 item_id;
std::string unique_id;
uint64 cost;
uint64 serial_number; // backwards compatibility. Not used for RoF2 as of March 2025
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(item_id),
CEREAL_NVP(unique_id),
CEREAL_NVP(cost),
CEREAL_NVP(serial_number)
);
}
};
struct ClickTraderNew_Struct {
uint32 action;
std::vector<BazaarTraderDetails> items;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(items)
);
}
};
struct GetBazaarItems_Struct {
uint64 items[EQ::invtype::BAZAAR_SIZE];
std::string serial_number[EQ::invtype::BAZAAR_SIZE];
uint32 charges[EQ::invtype::BAZAAR_SIZE];
};
struct BecomeTrader_Struct {
uint32 action;
uint16 zone_id;
@@ -3775,7 +3852,7 @@ struct TraderBuy_Struct {
/*084*/ char seller_name[64];
/*148*/ char unknown_148[32];
/*180*/ char item_name[64];
/*244*/ char serial_number[17];
/*244*/ char item_unique_id[17];
/*261*/ char unknown_261[3];
/*264*/ uint32 item_id;
/*268*/ uint32 price;
@@ -3794,12 +3871,12 @@ struct TraderItemUpdate_Struct{
};
struct TraderPriceUpdate_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 SubAction;
/*008*/ int32 SerialNumber;
/*012*/ uint32 Unknown012;
/*016*/ uint32 NewPrice;
/*020*/ uint32 Unknown016;
/*000*/ uint32 action;
/*002*/ uint32 sub_action;
/*004*/ char item_unique_id[17];
/*021*/ char unknown_021[3];
/*024*/ uint32 unknown_024;
/*028*/ uint32 new_price;
};
struct MoneyUpdate_Struct{
@@ -3814,6 +3891,7 @@ struct TraderDelItem_Struct{
uint32 trader_id;
uint32 item_id;
uint32 unknown_012;
char item_unique_id[17];
};
struct TraderClick_Struct{
@@ -3837,12 +3915,12 @@ struct SimpleMessage_Struct{
};
struct GuildMemberUpdate_Struct {
/*00*/ uint32 GuildID;
/*04*/ char MemberName[64];
/*68*/ uint16 ZoneID;
/*70*/ uint16 InstanceID; //speculated
/*72*/ uint32 LastSeen; //unix timestamp
/*76*/
/*00*/ uint32 GuildID;
/*04*/ char MemberName[64];
/*68*/ uint16 ZoneID;
/*72*/ uint16 InstanceID; //speculated
/*76*/ uint32 LastSeen; //unix timestamp
/*80*/ uint32 offline_mode;
};
struct GuildMemberLevelUpdate_Struct {
@@ -3865,6 +3943,7 @@ struct Internal_GuildMemberEntry_Struct {
uint16 zoneinstance; //network byte order
uint16 zone_id; //network byte order
uint32 online;
uint32 offline_mode;
};
struct Internal_GuildMembers_Struct { //just for display purposes, this is not actually used in the message encoding.
@@ -6419,7 +6498,7 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 count;
uint32 trader_id;
uint32 item_id;
uint32 serial_number;
std::string item_unique_id;
uint32 charges;
uint32 cost;
uint32 slot_id;
@@ -6431,7 +6510,6 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 item_stat;
bool stackable;
std::string item_name;
std::string serial_number_RoF;
std::string trader_name;
template<class Archive>
@@ -6441,7 +6519,7 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(count),
CEREAL_NVP(trader_id),
CEREAL_NVP(item_id),
CEREAL_NVP(serial_number),
CEREAL_NVP(item_unique_id),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(slot_id),
@@ -6453,7 +6531,6 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(item_stat),
CEREAL_NVP(stackable),
CEREAL_NVP(item_name),
CEREAL_NVP(serial_number_RoF),
CEREAL_NVP(trader_name)
);
}
+13 -2
View File
@@ -1099,6 +1099,7 @@ namespace PlayerEvent {
int32 charges;
uint64 total_cost;
uint64 player_money_balance;
bool offline_purchase;
// cereal
template <class Archive>
@@ -1154,7 +1155,8 @@ namespace PlayerEvent {
CEREAL_NVP(quantity),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
CEREAL_NVP(player_money_balance),
CEREAL_NVP(offline_purchase)
);
}
};
@@ -1175,7 +1177,9 @@ namespace PlayerEvent {
int32 charges;
uint64 total_cost;
uint64 player_money_balance;
bool offline_purchase;
// cereal
template <class Archive>
void serialize(Archive& ar)
{
@@ -1229,7 +1233,8 @@ namespace PlayerEvent {
CEREAL_NVP(quantity),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
CEREAL_NVP(player_money_balance),
CEREAL_NVP(offline_purchase)
);
}
};
@@ -1427,6 +1432,7 @@ namespace PlayerEvent {
struct ParcelRetrieve {
uint32 item_id;
std::string item_unique_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
@@ -1472,6 +1478,7 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_unique_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
@@ -1487,6 +1494,7 @@ namespace PlayerEvent {
struct ParcelSend {
uint32 item_id;
std::string item_unique_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
@@ -1536,6 +1544,7 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_unique_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
@@ -1554,6 +1563,7 @@ namespace PlayerEvent {
struct ParcelDelete {
uint32 char_id;
uint32 item_id;
std::string item_unique_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
@@ -1602,6 +1612,7 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_unique_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
+5 -2
View File
@@ -842,8 +842,10 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg)
#define GuildMemberBaseQuery \
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
" g.`banker`, g.`public_note`, g.`alt`, g.`online` " \
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
" g.`banker`, g.`public_note`, g.`alt`, g.`online`, a.`offline` " \
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` " \
" LEFT JOIN `account` AS a ON a.`id` = c.`account_id` "
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into)
{
//fields from `characer_`
@@ -864,6 +866,7 @@ static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into)
into.public_note = row[12] ? row[12] : "";
into.alt = row[13] ? (row[13][0] == '0' ? false : true) : false;
into.online = row[14] ? (row[14][0] == '0' ? false : true) : false;
into.offline_mode = row[15] ? (row[15][0] == '0' ? false : true) : false;
//a little sanity checking/cleanup
if (into.guild_id == 0) {
+11 -10
View File
@@ -55,16 +55,17 @@ class CharGuildInfo
uint32 time_last_on;
uint32 zone_id;
//fields from `guild_members`
uint32 guild_id;
uint8 rank;
bool tribute_enable;
uint32 total_tribute;
uint32 last_tribute; //timestamp
bool banker;
bool alt;
std::string public_note;
bool online;
// fields from `guild_members`
uint32 guild_id;
uint8 rank;
bool tribute_enable;
uint32 total_tribute;
uint32 last_tribute; // timestamp
bool banker;
bool alt;
std::string public_note;
bool online;
bool offline_mode;
};
//this object holds guild functionality shared between world and zone.
+4
View File
@@ -249,6 +249,10 @@ int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
}
int16 EQ::InventoryProfile::PushCursor(const ItemInstance &inst) {
if (inst.GetUniqueID().empty()) {
inst.CreateUniqueID();
}
m_cursor.push(inst.Clone());
return invslot::slotCursor;
}
+43 -6
View File
@@ -58,8 +58,8 @@ static inline int32 GetNextItemInstSerialNumber()
//
// class EQ::ItemInstance
//
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges)
{
if (item) {
m_item = new ItemData(*item);
}
@@ -77,8 +77,31 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_SerialNumber = GetNextItemInstSerialNumber();
}
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
EQ::ItemInstance::ItemInstance(const ItemData *item, const std::string &item_unique_id, int16 charges)
{
if (item) {
m_item = new ItemData(*item);
}
m_charges = charges;
if (m_item && m_item->IsClassCommon()) {
m_color = m_item->Color;
}
if (m_item && IsEvolving()) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
}
m_SerialNumber = GetNextItemInstSerialNumber();
if (m_item && !item_unique_id.empty()) {
SetUniqueID(item_unique_id);
}
}
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges)
{
m_item = db->GetItem(item_id);
if (m_item) {
@@ -142,9 +165,15 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
m_custom_data[iter->first] = iter->second;
}
m_SerialNumber = copy.m_SerialNumber;
m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers;
m_SerialNumber = copy.m_SerialNumber;
m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers;
if (copy.GetUniqueID().empty()) {
LogInfo("Creating unique item ID as part of clone process for item id {}", copy.GetID());
copy.CreateUniqueID();
}
m_unique_id = copy.m_unique_id;
m_exp = copy.m_exp;
m_evolveLvl = copy.m_evolveLvl;
@@ -1995,3 +2024,11 @@ void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
GetTimers().at("evolve").Disable();
}
std::string EQ::ItemInstance::GenerateUniqueID()
{
std::string unique_hash = UniqueHashGenerator::generate();
LogInventoryDetail("Generated an item serial number {}", unique_hash);
return unique_hash;
}
+86 -24
View File
@@ -23,6 +23,10 @@
#pragma once
#include <array>
#include <chrono>
#include <random>
#include "common/bodytypes.h"
#include "common/deity.h"
#include "common/eq_constants.h"
@@ -37,7 +41,6 @@
class ItemParse; // Parses item packets
class EvolveInfo; // Stores information about an evolving item family
// Specifies usage type for item inside EQ::ItemInstance
enum ItemInstTypes
{
@@ -78,6 +81,8 @@ namespace EQ
ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges = 0);
ItemInstance(const ItemData *item, const std::string &item_unique_id, int16 charges = 0);
ItemInstance(ItemInstTypes use_type);
ItemInstance(const ItemInstance& copy);
@@ -161,6 +166,14 @@ namespace EQ
int16 GetCharges() const { return m_charges; }
void SetCharges(int16 charges) { m_charges = charges; }
int16 GetQuantityFromCharges() const
{
if (GetCharges() > 0 || IsStackable() || GetItem()->MaxCharges > 0) {
return GetCharges();
}
return 1;
}
uint32 GetPrice() const { return m_price; }
void SetPrice(uint32 price) { m_price = price; }
@@ -226,8 +239,11 @@ namespace EQ
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; }
void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); }
inline int32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
int32 GetSerialNumber() const { return m_SerialNumber; }
void SetSerialNumber(int32 id) { m_SerialNumber = id; }
const std::string &GetUniqueID() const { return m_unique_id; }
void SetUniqueID(std::string sn) { m_unique_id = std::move(sn); }
void CreateUniqueID() const { m_unique_id = GenerateUniqueID(); }
std::map<std::string, ::Timer>& GetTimers() const { return m_timers; }
void SetTimer(std::string name, uint32 time);
@@ -344,28 +360,30 @@ namespace EQ
std::map<uint8, ItemInstance*>::const_iterator _cbegin() { return m_contents.cbegin(); }
std::map<uint8, ItemInstance*>::const_iterator _cend() { return m_contents.cend(); }
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
void _PutItem(uint8 index, ItemInstance *inst) { m_contents[index] = inst; }
static std::string GenerateUniqueID();
ItemInstTypes m_use_type{ItemInstNormal};// Usage type for item
const ItemData * m_item{nullptr}; // Ptr to item data
int16 m_charges{0}; // # of charges for chargeable items
uint32 m_price{0}; // Bazaar /trader price
uint32 m_color{0};
uint32 m_merchantslot{0};
int16 m_currentslot{0};
bool m_attuned{false};
int32 m_merchantcount{1};//number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber{0}; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp{0};
int8 m_evolveLvl{0};
ItemData * m_scaledItem{nullptr};
bool m_scaling{false};
uint32 m_ornamenticon{0};
uint32 m_ornamentidfile{0};
uint32 m_new_id_file{0};
uint32 m_ornament_hero_model{0};
uint32 m_recast_timestamp{0};
int m_task_delivered_count{0};
ItemInstTypes m_use_type{ ItemInstNormal }; // Usage type for item
const ItemData *m_item{ nullptr }; // Ptr to item data
int16 m_charges{ 0 }; // # of charges for chargeable items
uint32 m_price{ 0 }; // Bazaar /trader price
uint32 m_color{ 0 };
uint32 m_merchantslot{ 0 };
int16 m_currentslot{ 0 };
bool m_attuned{ false };
int32 m_merchantcount{ 1 }; // number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber{ 0 }; // Unique identifier for this instance of an item. Needed for Bazaar.
mutable std::string m_unique_id{}; // unique serial number across all zones/world TESTING March 2025
uint32 m_exp{ 0 };
int8 m_evolveLvl{ 0 };
ItemData *m_scaledItem{ nullptr };
bool m_scaling{ false };
uint32 m_ornamenticon{ 0 };
uint32 m_ornamentidfile{ 0 };
uint32 m_new_id_file{ 0 };
uint32 m_ornament_hero_model{ 0 };
uint32 m_recast_timestamp{ 0 };
int m_task_delivered_count{ 0 };
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{};
// Items inside of this item (augs or contents) {};
@@ -373,4 +391,48 @@ namespace EQ
std::map<std::string, std::string> m_custom_data {};
mutable std::map<std::string, ::Timer> m_timers {};
};
class UniqueHashGenerator
{
private:
static constexpr char ALPHANUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static constexpr size_t ALPHANUM_SIZE = sizeof(ALPHANUM) - 1;
static std::mt19937_64 &GetRng()
{
thread_local std::mt19937_64 rng = []() {
std::random_device rd;
std::array<uint32_t, 8> entropy{};
for (auto &value : entropy) {
value = rd();
}
auto now = static_cast<uint64_t>(
std::chrono::steady_clock::now().time_since_epoch().count()
);
entropy[0] ^= static_cast<uint32_t>(now);
entropy[1] ^= static_cast<uint32_t>(now >> 32);
std::seed_seq seed(entropy.begin(), entropy.end());
return std::mt19937_64(seed);
}();
return rng;
}
public:
static std::string generate()
{
auto &rng = GetRng();
std::uniform_int_distribution<size_t> dist(0, ALPHANUM_SIZE - 1);
std::array<char, 16> result;
for (int i = 0; i < 16; ++i) {
result[i] = ALPHANUM[dist(rng)];
}
return std::string(result.begin(), result.end());
}
};
}
+101 -84
View File
@@ -437,7 +437,6 @@ namespace RoF2
break;
}
default: {
LogTradingDetail("Unhandled action <red>[{}]", sub_action);
dest->FastQueuePacket(&in);
}
}
@@ -478,7 +477,7 @@ namespace RoF2
for (auto i: results) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.trader_id); //trader ID
VARSTRUCT_ENCODE_STRING(bufptr, i.serial_number_RoF.c_str()); //serial
VARSTRUCT_ENCODE_STRING(bufptr, i.item_unique_id.c_str()); //serial
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.cost); //cost
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.stackable ? i.charges : i.count); //quantity
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_id); //ID
@@ -531,7 +530,6 @@ namespace RoF2
break;
}
default: {
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
dest->FastQueuePacket(&in, ack_req);
}
}
@@ -620,10 +618,6 @@ namespace RoF2
break;
}
default: {
LogTrading(
"(RoF2) Unhandled action <red>[{}]",
in->action
);
dest->QueuePacket(inapp);
}
}
@@ -755,7 +749,7 @@ namespace RoF2
ar(bl);
//packet size
auto packet_size = bl.item_name.length() + 1 + 34;
uint32 packet_size = bl.item_name.length() + 1 + 34;
for (auto const &b: bl.trade_items) {
packet_size += b.item_name.length() + 1;
packet_size += 12;
@@ -1843,7 +1837,7 @@ namespace RoF2
e->zoneinstance = 0;
e->zone_id = htons(emu_e->zone_id);
e->unknown_one2 = htonl(1);
e->unknown04 = 0;
e->offline_mode = htonl(emu_e->offline_mode);
#undef SlideStructString
#undef PutFieldN
@@ -1860,14 +1854,12 @@ namespace RoF2
{
SETUP_DIRECT_ENCODE(GuildMemberUpdate_Struct, structs::GuildMemberUpdate_Struct);
OUT(GuildID);
memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName));
//OUT(ZoneID);
//OUT(InstanceID);
eq->InstanceID = emu->InstanceID;
eq->ZoneID = emu->ZoneID;
OUT(LastSeen);
eq->Unknown76 = 0;
eq->guild_id = emu->GuildID;
eq->last_seen = emu->LastSeen;
eq->instance_id = emu->InstanceID;
eq->zone_id = emu->ZoneID;
eq->offline_mode = emu->offline_mode;
memcpy(eq->member_name, emu->MemberName, sizeof(eq->member_name));
FINISH_ENCODE();
}
@@ -4113,26 +4105,41 @@ namespace RoF2
break;
}
case ListTraderItems: {
ENCODE_LENGTH_EXACT(Trader_Struct);
SETUP_DIRECT_ENCODE(Trader_Struct, structs::ClickTrader_Struct);
LogTrading("(RoF2) action <green>[{}]", action);
eq->action = structs::RoF2BazaarTraderBuyerActions::ListTraderItems;
std::transform(
std::begin(emu->items),
std::end(emu->items),
std::begin(eq->items),
[&](const uint32 x) {
return x;
}
);
std::copy_n(
std::begin(emu->item_cost),
EQ::invtype::BAZAAR_SIZE,
std::begin(eq->item_cost)
);
EQApplicationPacket *in = *p;
*p = nullptr;
FINISH_ENCODE();
TraderClientMessaging_Struct tcm{};
EQ::Util::MemoryStreamReader ss(reinterpret_cast<char *>(in->pBuffer), in->size);
cereal::BinaryInputArchive ar(ss);
{
ar(tcm);
}
auto buffer = new char[4404]{}; // 4404 is the fixed size of the packet for 200 item limit of RoF2
auto pos = buffer;
auto pos_unique_id = buffer + 4;
auto pos_cost = buffer + 3604;
VARSTRUCT_ENCODE_TYPE(uint32, pos, structs::RoF2BazaarTraderBuyerActions::ListTraderItems);
for (auto const &t: tcm.items) {
strn0cpy(pos_unique_id, t.item_unique_id.data(), t.item_unique_id.length() + 1);
*(uint32 *) pos_cost = t.item_cost;
pos_unique_id += 18;
pos_cost += 4;
}
for (int i = tcm.items.size(); i < EQ::invtype::BAZAAR_SIZE; i++) {
strn0cpy(pos_unique_id, "0000000000000000", 18);
pos_unique_id += 18;
}
safe_delete_array(in->pBuffer);
in->pBuffer = reinterpret_cast<unsigned char *>(buffer);
in->size = 4404;
dest->FastQueuePacket(&in);
break;
}
case TraderAck2: {
@@ -4145,7 +4152,7 @@ namespace RoF2
}
case PriceUpdate: {
SETUP_DIRECT_ENCODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
switch (emu->SubAction) {
switch (emu->sub_action) {
case BazaarPriceChange_AddItem: {
auto outapp = std::make_unique<EQApplicationPacket>(
OP_Trader,
@@ -4153,7 +4160,7 @@ namespace RoF2
);
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
data->action = emu->Action;
data->action = emu->action;
data->sub_action = BazaarPriceChange_AddItem;
LogTrading(
"(RoF2) PriceUpdate action <green>[{}] AddItem subaction <yellow>[{}]",
@@ -4171,7 +4178,7 @@ namespace RoF2
);
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
data->action = emu->Action;
data->action = emu->action;
data->sub_action = BazaarPriceChange_RemoveItem;
LogTrading(
"(RoF2) PriceUpdate action <green>[{}] RemoveItem subaction <yellow>[{}]",
@@ -4189,7 +4196,7 @@ namespace RoF2
);
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
data->action = emu->Action;
data->action = emu->action;
data->sub_action = BazaarPriceChange_UpdatePrice;
LogTrading(
"(RoF2) PriceUpdate action <green>[{}] UpdatePrice subaction <yellow>[{}]",
@@ -4214,7 +4221,7 @@ namespace RoF2
"(RoF2) BuyTraderItem action <green>[{}] item_id <green>[{}] item_sn <green>[{}] buyer <green>[{}]",
action,
eq->item_id,
eq->serial_number,
eq->item_unique_id,
eq->buyer_name
);
dest->FastQueuePacket(&in);
@@ -4253,7 +4260,7 @@ namespace RoF2
OUT_str(buyer_name);
OUT_str(seller_name);
OUT_str(item_name);
OUT_str(serial_number);
OUT_str(item_unique_id);
FINISH_ENCODE();
}
@@ -4263,15 +4270,13 @@ namespace RoF2
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
LogTrading(
"(RoF2) trader_id <green>[{}] item_id <green>[{}]",
"(RoF2) trader_id <green>[{}] item_unique_id <green>[{}]",
emu->trader_id,
emu->item_id
emu->item_unique_id
);
eq->TraderID = emu->trader_id;
auto serial = fmt::format("{:016}\n", emu->item_id);
strn0cpy(eq->SerialNumber, serial.c_str(), sizeof(eq->SerialNumber));
LogTrading("(RoF2) TraderID <green>[{}], SerialNumber: <green>[{}]", emu->trader_id, emu->item_id);
eq->trader_id = emu->trader_id;
strn0cpy(eq->item_unique_id, emu->item_unique_id, sizeof(eq->item_unique_id));
FINISH_ENCODE();
}
@@ -4318,13 +4323,12 @@ namespace RoF2
OUT_str(buyer_name);
OUT_str(seller_name);
OUT_str(item_name);
OUT_str(serial_number);
OUT_str(item_unique_id);
FINISH_ENCODE();
break;
}
default: {
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
EQApplicationPacket *in = *p;
*p = nullptr;
@@ -4460,6 +4464,7 @@ namespace RoF2
*p = nullptr;
char *InBuffer = (char *)in->pBuffer;
std::vector<uint32> p_ids { 0x430, 0x420 };
WhoAllReturnStruct *wars = (WhoAllReturnStruct*)InBuffer;
@@ -4485,8 +4490,9 @@ namespace RoF2
x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x);
InBuffer += 4;
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, std::ranges::find(p_ids.begin(), p_ids.end(), x) == p_ids.end() ? 0 : x);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0xffffffff);
char Name[64];
@@ -4722,6 +4728,10 @@ namespace RoF2
OtherData = OtherData | 0x01;
}
if (emu->offline) {
OtherData = OtherData | 0x02;
}
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
// float EmitterScalingRadius
@@ -5092,7 +5102,6 @@ namespace RoF2
}
default: {
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
LogTradingDetail("(RoF2) Pass thru OP_Barter packet action <red>[{}]", emu->action);
}
}
}
@@ -6150,21 +6159,35 @@ namespace RoF2
switch (action) {
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
emu->action = TraderOn;
std::copy_n(eq->item_cost, RoF2::invtype::BAZAAR_SIZE, emu->item_cost);
std::transform(
std::begin(eq->items),
std::end(eq->items),
std::begin(emu->serial_number),
[&](const structs::TraderItemSerial_Struct x) {
return Strings::ToUnsignedBigInt(x.serial_number,0);
unsigned char *eq_buffer = __packet->pBuffer;
auto eq = (RoF2::structs::BeginTrader_Struct *) eq_buffer;
ClickTraderNew_Struct out{};
out.action = TraderOn;
for (auto i = 0; i < RoF2::invtype::BAZAAR_SIZE; i++) {
if (eq->item_cost[i] == 0) {
continue;
}
);
FINISH_DIRECT_DECODE();
BazaarTraderDetails btd{};
btd.unique_id = eq->item_unique_ids[i].item_unique_id;
btd.cost = eq->item_cost[i];
out.items.push_back(btd);
}
std::stringstream ss{};
cereal::BinaryOutputArchive ar(ss);
{
ar(out);
}
__packet->size = static_cast<uint32>(ss.str().length());
__packet->pBuffer = new unsigned char[__packet->size]{};
memcpy(__packet->pBuffer, ss.str().data(), __packet->size);
safe_delete_array(eq_buffer);
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
break;
}
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
@@ -6187,18 +6210,14 @@ namespace RoF2
SETUP_DIRECT_DECODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
LogTrading("(RoF2) PriceUpdate action <green>[{}]", action);
emu->Action = PriceUpdate;
emu->SerialNumber = Strings::ToUnsignedBigInt(eq->serial_number, 0);
if (emu->SerialNumber == 0) {
LogTrading("(RoF2) Price change with invalid serial number <red>[{}]", eq->serial_number);
}
emu->NewPrice = eq->new_price;
emu->action = PriceUpdate;
strn0cpy(emu->item_unique_id, eq->item_unique_id, sizeof(emu->item_unique_id));
emu->new_price = eq->new_price;
FINISH_DIRECT_DECODE();
break;
}
default: {
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
}
}
}
@@ -6282,21 +6301,12 @@ namespace RoF2
IN(item_id);
IN(trader_id);
emu->action = BazaarInspect;
emu->serial_number = Strings::ToUnsignedInt(eq->serial_number, 0);
if (emu->serial_number == 0) {
LogTrading(
"(RoF2) trader_id = <green>[{}] requested a BazaarInspect with an invalid serial number of <red>[{}]",
eq->trader_id,
eq->serial_number
);
FINISH_DIRECT_DECODE();
return;
}
strn0cpy(emu->item_unique_id, eq->item_unique_id, sizeof(emu->item_unique_id));
LogTrading("(RoF2) BazaarInspect action <green>[{}] item_id <green>[{}] serial_number <green>[{}]",
action,
eq->item_id,
eq->serial_number
eq->item_unique_id
);
FINISH_DIRECT_DECODE();
break;
@@ -6333,13 +6343,12 @@ namespace RoF2
IN_str(buyer_name);
IN_str(seller_name);
IN_str(item_name);
IN_str(serial_number);
strn0cpy(emu->item_unique_id, eq->item_unique_id, sizeof(emu->item_unique_id));
FINISH_DIRECT_DECODE();
break;
}
default: {
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
}
return;
}
@@ -6444,7 +6453,15 @@ namespace RoF2
RoF2::structs::ItemSerializationHeader hdr;
//sprintf(hdr.unknown000, "06e0002Y1W00");
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
if (inst->GetUniqueID().empty()) {
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
}
else {
strn0cpy(hdr.unknown000, inst->GetUniqueID().c_str(),sizeof(hdr.unknown000));
hdr.unknown000[16] = '\0';
}
hdr.stacksize = 1;
+1
View File
@@ -306,6 +306,7 @@ namespace RoF2
const size_t SAY_LINK_BODY_SIZE = 56;
const uint32 MAX_GUILD_ID = 50000;
const uint32 MAX_BAZAAR_TRADERS = 600;
const uint64 MAX_BAZAAR_TRANSACTION = 3276700000000; //3276700000000
} /*constants*/
+56 -55
View File
@@ -3317,7 +3317,7 @@ struct BazaarInspect_Struct {
uint32 action;
uint32 unknown_004;
uint32 trader_id;
char serial_number[17];
char item_unique_id[17];
char unknown_029[3];
uint32 item_id;
uint32 unknown_036;
@@ -3560,19 +3560,21 @@ struct WhoAllPlayerPart4 {
};
struct TraderItemSerial_Struct {
char serial_number[17];
char item_unique_id[17];
uint8 unknown_018;
void operator=(uint32 a) {
auto _tmp = fmt::format("{:016}", a);
strn0cpy(this->serial_number, _tmp.c_str(), sizeof(this->serial_number));
TraderItemSerial_Struct& operator=(const char* a) {
strn0cpy(this->item_unique_id, a, sizeof(this->item_unique_id));
unknown_018 = 0;
return *this;
}
};
struct BeginTrader_Struct {
/*0000*/ uint32 action;
/*0004*/ TraderItemSerial_Struct items[200];
/*3604*/ uint32 item_cost[200];
/*0004*/ TraderItemSerial_Struct item_unique_ids[RoF2::invtype::BAZAAR_SIZE];
/*3604*/ uint32 item_cost[RoF2::invtype::BAZAAR_SIZE];
/*4404*/
};
@@ -3598,11 +3600,11 @@ struct BazaarWindowRemoveTrader_Struct {
};
struct TraderPriceUpdate_Struct {
uint32 action;
char serial_number[17];
char unknown_021[3];
uint32 unknown_024;
uint32 new_price;
/*000*/ uint32 action;
/*004*/ char item_unique_id[17];
/*021*/ char unknown_021[3];
/*024*/ uint32 unknown_024;
/*028*/ uint32 new_price;
};
struct Trader_ShowItems_Struct {
@@ -3620,22 +3622,22 @@ struct TraderStatus_Struct {
};
struct TraderBuy_Struct {
/*000*/ uint32 action;
/*004*/ uint32 method;
/*008*/ uint32 sub_action;
/*012*/ uint32 unknown_012;
/*016*/ uint32 trader_id;
/*020*/ char buyer_name[64];
/*084*/ char seller_name[64];
/*148*/ char unknown_148[32];
/*180*/ char item_name[64];
/*244*/ char serial_number[17];
/*261*/ char unknown_261[3];
/*264*/ uint32 item_id;
/*268*/ uint32 price;
/*272*/ uint32 already_sold;
/*276*/ uint32 unknown_276;
/*280*/ uint32 quantity;
/*000*/ uint32 action;
/*004*/ uint32 method;
/*008*/ uint32 sub_action;
/*012*/ uint32 unknown_012;
/*016*/ uint32 trader_id;
/*020*/ char buyer_name[64];
/*084*/ char seller_name[64];
/*148*/ char unknown_148[32];
/*180*/ char item_name[64];
/*244*/ char item_unique_id[17];
/*261*/ char unknown_261[3];
/*264*/ uint32 item_id;
/*268*/ uint32 price;
/*272*/ uint32 already_sold;
/*276*/ uint32 unknown_276;
/*280*/ uint32 quantity;
/*284*/
};
@@ -3655,10 +3657,10 @@ struct MoneyUpdate_Struct{
};
struct TraderDelItem_Struct{
/*000*/ uint32 Unknown000;
/*004*/ uint32 TraderID;
/*008*/ char SerialNumber[17];
/*024*/ uint32 Unknown012;
/*000*/ uint32 unknown_000;
/*004*/ uint32 trader_id;
/*008*/ char item_unique_id[17];
/*025*/ uint32 unknown_025;
/*028*/
};
@@ -3685,22 +3687,22 @@ struct SimpleMessage_Struct{
// Size: 52 + strings
// Other than the strings, all of this packet is network byte order (reverse from normal)
struct GuildMemberEntry_Struct {
char name[1]; // variable length
uint32 level;
uint32 banker; // 1=yes, 0=no
uint32 class_;
uint32 rank;
uint32 time_last_on;
uint32 tribute_enable;
uint32 unknown01; // Seen 0
uint32 total_tribute; // total guild tribute donated, network byte order
uint32 last_tribute; // unix timestamp
uint32 unknown_one; // unknown, set to 1
char public_note[1]; // variable length.
uint16 zoneinstance; // Seen 0s or -1 in RoF2
uint16 zone_id; // Seen 0s or -1 in RoF2
uint32 unknown_one2; // unknown, set to 1
uint32 unknown04; // Seen 0
char name[1]; // variable length
uint32 level;
uint32 banker; // 1=yes, 0=no
uint32 class_;
uint32 rank;
uint32 time_last_on;
uint32 tribute_enable;
uint32 unknown01; // Seen 0
uint32 total_tribute; // total guild tribute donated, network byte order
uint32 last_tribute; // unix timestamp
uint32 unknown_one; // unknown, set to 1
char public_note[1]; // variable length.
uint16 zoneinstance; // Seen 0s or -1 in RoF2
uint16 zone_id; // Seen 0s or -1 in RoF2
uint32 unknown_one2; // unknown, set to 1
uint32 offline_mode; // Displays OFFLINE MODE instead of Zone Name
};
//just for display purposes, this is not actually used in the message encoding other than for size.
@@ -3735,13 +3737,12 @@ struct GuildStatus_Struct
};
struct GuildMemberUpdate_Struct {
/*00*/ uint32 GuildID;
/*04*/ char MemberName[64];
/*68*/ uint16 ZoneID;
/*70*/ uint16 InstanceID; //speculated
/*72*/ uint32 LastSeen; //unix timestamp
/*76*/ uint32 Unknown76;
/*80*/
/*00*/ uint32 guild_id;
/*04*/ char member_name[64];
/*68*/ uint16 zone_id;
/*70*/ uint16 instance_id; //speculated
/*72*/ uint32 last_seen; //unix timestamp
/*76*/ uint32 offline_mode;
};
struct GuildMemberLevelUpdate_Struct {
-2
View File
@@ -226,7 +226,6 @@ namespace Titanium
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
bufptr += 4;
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
bufptr += 4;
if (row->stackable) {
strn0cpy(
@@ -2527,7 +2526,6 @@ namespace Titanium
IN(action);
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
IN(serial_number);
FINISH_DIRECT_DECODE();
break;
-2
View File
@@ -335,7 +335,6 @@ namespace UF
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
bufptr += 4;
if (row->stackable) {
strn0cpy(
@@ -3615,7 +3614,6 @@ namespace UF
IN(action);
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
IN(serial_number);
FINISH_DIRECT_DECODE();
break;
+39
View File
@@ -107,4 +107,43 @@ public:
return AccountRepository::UpdateOne(db, e);
}
static void SetOfflineStatus(Database& db, const uint32 account_id, bool offline_status)
{
auto account = FindOne(db, account_id);
if (!account.id) {
return;
}
account.offline = offline_status;
UpdateOne(db, account);
}
static void ClearAllOfflineStatus(Database& db)
{
auto query = fmt::format("UPDATE {} SET `offline` = 0 WHERE `offline` = 1;",
TableName()
);
db.QueryDatabase(query);
}
static bool GetAllOfflineStatus(Database& db, const uint32 character_id)
{
auto query = fmt::format("SELECT a.`offline` "
"FROM `account` AS a "
"INNER JOIN character_data AS c ON c.account_id = a.id "
"WHERE c.id = {}",
character_id
);
auto results = db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return false;
}
auto row = results.begin();
bool const status = static_cast<int16>(Strings::ToInt(row[0]));
return status;
}
};
@@ -39,6 +39,7 @@ public:
uint8_t rulesflag;
time_t suspendeduntil;
uint32_t time_creation;
uint8_t offline;
std::string ban_reason;
std::string suspend_reason;
std::string crc_eqgame;
@@ -74,6 +75,7 @@ public:
"rulesflag",
"suspendeduntil",
"time_creation",
"offline",
"ban_reason",
"suspend_reason",
"crc_eqgame",
@@ -105,6 +107,7 @@ public:
"rulesflag",
"UNIX_TIMESTAMP(suspendeduntil)",
"time_creation",
"offline",
"ban_reason",
"suspend_reason",
"crc_eqgame",
@@ -170,6 +173,7 @@ public:
e.rulesflag = 0;
e.suspendeduntil = 0;
e.time_creation = 0;
e.offline = 0;
e.ban_reason = "";
e.suspend_reason = "";
e.crc_eqgame = "";
@@ -231,11 +235,12 @@ public:
e.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
e.suspendeduntil = strtoll(row[18] ? row[18] : "-1", nullptr, 10);
e.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.ban_reason = row[20] ? row[20] : "";
e.suspend_reason = row[21] ? row[21] : "";
e.crc_eqgame = row[22] ? row[22] : "";
e.crc_skillcaps = row[23] ? row[23] : "";
e.crc_basedata = row[24] ? row[24] : "";
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
e.ban_reason = row[21] ? row[21] : "";
e.suspend_reason = row[22] ? row[22] : "";
e.crc_eqgame = row[23] ? row[23] : "";
e.crc_skillcaps = row[24] ? row[24] : "";
e.crc_basedata = row[25] ? row[25] : "";
return e;
}
@@ -288,11 +293,12 @@ public:
v.push_back(columns[17] + " = " + std::to_string(e.rulesflag));
v.push_back(columns[18] + " = FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
v.push_back(columns[19] + " = " + std::to_string(e.time_creation));
v.push_back(columns[20] + " = '" + Strings::Escape(e.ban_reason) + "'");
v.push_back(columns[21] + " = '" + Strings::Escape(e.suspend_reason) + "'");
v.push_back(columns[22] + " = '" + Strings::Escape(e.crc_eqgame) + "'");
v.push_back(columns[23] + " = '" + Strings::Escape(e.crc_skillcaps) + "'");
v.push_back(columns[24] + " = '" + Strings::Escape(e.crc_basedata) + "'");
v.push_back(columns[20] + " = " + std::to_string(e.offline));
v.push_back(columns[21] + " = '" + Strings::Escape(e.ban_reason) + "'");
v.push_back(columns[22] + " = '" + Strings::Escape(e.suspend_reason) + "'");
v.push_back(columns[23] + " = '" + Strings::Escape(e.crc_eqgame) + "'");
v.push_back(columns[24] + " = '" + Strings::Escape(e.crc_skillcaps) + "'");
v.push_back(columns[25] + " = '" + Strings::Escape(e.crc_basedata) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -334,6 +340,7 @@ public:
v.push_back(std::to_string(e.rulesflag));
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
v.push_back(std::to_string(e.time_creation));
v.push_back(std::to_string(e.offline));
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
@@ -388,6 +395,7 @@ public:
v.push_back(std::to_string(e.rulesflag));
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
v.push_back(std::to_string(e.time_creation));
v.push_back(std::to_string(e.offline));
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
@@ -446,11 +454,12 @@ public:
e.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
e.suspendeduntil = strtoll(row[18] ? row[18] : "-1", nullptr, 10);
e.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.ban_reason = row[20] ? row[20] : "";
e.suspend_reason = row[21] ? row[21] : "";
e.crc_eqgame = row[22] ? row[22] : "";
e.crc_skillcaps = row[23] ? row[23] : "";
e.crc_basedata = row[24] ? row[24] : "";
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
e.ban_reason = row[21] ? row[21] : "";
e.suspend_reason = row[22] ? row[22] : "";
e.crc_eqgame = row[23] ? row[23] : "";
e.crc_skillcaps = row[24] ? row[24] : "";
e.crc_basedata = row[25] ? row[25] : "";
all_entries.push_back(e);
}
@@ -495,11 +504,12 @@ public:
e.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
e.suspendeduntil = strtoll(row[18] ? row[18] : "-1", nullptr, 10);
e.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.ban_reason = row[20] ? row[20] : "";
e.suspend_reason = row[21] ? row[21] : "";
e.crc_eqgame = row[22] ? row[22] : "";
e.crc_skillcaps = row[23] ? row[23] : "";
e.crc_basedata = row[24] ? row[24] : "";
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
e.ban_reason = row[21] ? row[21] : "";
e.suspend_reason = row[22] ? row[22] : "";
e.crc_eqgame = row[23] ? row[23] : "";
e.crc_skillcaps = row[24] ? row[24] : "";
e.crc_basedata = row[25] ? row[25] : "";
all_entries.push_back(e);
}
@@ -594,6 +604,7 @@ public:
v.push_back(std::to_string(e.rulesflag));
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
v.push_back(std::to_string(e.time_creation));
v.push_back(std::to_string(e.offline));
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
@@ -641,6 +652,7 @@ public:
v.push_back(std::to_string(e.rulesflag));
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
v.push_back(std::to_string(e.time_creation));
v.push_back(std::to_string(e.offline));
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
@@ -0,0 +1,451 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
#define EQEMU_BASE_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseCharacterOfflineTransactionsRepository {
public:
struct CharacterOfflineTransactions {
uint64_t id;
uint32_t character_id;
uint32_t type;
std::string item_name;
int32_t quantity;
uint64_t price;
std::string buyer_name;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"character_id",
"type",
"item_name",
"quantity",
"price",
"buyer_name",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"character_id",
"type",
"item_name",
"quantity",
"price",
"buyer_name",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("character_offline_transactions");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static CharacterOfflineTransactions NewEntity()
{
CharacterOfflineTransactions e{};
e.id = 0;
e.character_id = 0;
e.type = 0;
e.item_name = "";
e.quantity = 0;
e.price = 0;
e.buyer_name = "";
return e;
}
static CharacterOfflineTransactions GetCharacterOfflineTransactions(
const std::vector<CharacterOfflineTransactions> &character_offline_transactionss,
int character_offline_transactions_id
)
{
for (auto &character_offline_transactions : character_offline_transactionss) {
if (character_offline_transactions.id == character_offline_transactions_id) {
return character_offline_transactions;
}
}
return NewEntity();
}
static CharacterOfflineTransactions FindOne(
Database& db,
int character_offline_transactions_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
character_offline_transactions_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
CharacterOfflineTransactions e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_name = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.buyer_name = row[6] ? row[6] : "";
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int character_offline_transactions_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
character_offline_transactions_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const CharacterOfflineTransactions &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.character_id));
v.push_back(columns[2] + " = " + std::to_string(e.type));
v.push_back(columns[3] + " = '" + Strings::Escape(e.item_name) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.quantity));
v.push_back(columns[5] + " = " + std::to_string(e.price));
v.push_back(columns[6] + " = '" + Strings::Escape(e.buyer_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static CharacterOfflineTransactions InsertOne(
Database& db,
CharacterOfflineTransactions e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.type));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back("'" + Strings::Escape(e.buyer_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<CharacterOfflineTransactions> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.type));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back("'" + Strings::Escape(e.buyer_name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<CharacterOfflineTransactions> All(Database& db)
{
std::vector<CharacterOfflineTransactions> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterOfflineTransactions e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_name = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.buyer_name = row[6] ? row[6] : "";
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<CharacterOfflineTransactions> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<CharacterOfflineTransactions> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterOfflineTransactions e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_name = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.buyer_name = row[6] ? row[6] : "";
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const CharacterOfflineTransactions &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.type));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back("'" + Strings::Escape(e.buyer_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<CharacterOfflineTransactions> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.type));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back("'" + Strings::Escape(e.buyer_name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
@@ -19,18 +19,19 @@
class BaseCharacterParcelsContainersRepository {
public:
struct CharacterParcelsContainers {
uint32_t id;
uint32_t parcels_id;
uint32_t slot_id;
uint32_t item_id;
uint32_t aug_slot_1;
uint32_t aug_slot_2;
uint32_t aug_slot_3;
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
uint32_t quantity;
uint32_t evolve_amount;
uint32_t id;
uint32_t parcels_id;
uint32_t slot_id;
uint32_t item_id;
std::string item_unique_id;
uint32_t aug_slot_1;
uint32_t aug_slot_2;
uint32_t aug_slot_3;
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
uint32_t quantity;
uint32_t evolve_amount;
};
static std::string PrimaryKey()
@@ -45,6 +46,7 @@ public:
"parcels_id",
"slot_id",
"item_id",
"item_unique_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
@@ -63,6 +65,7 @@ public:
"parcels_id",
"slot_id",
"item_id",
"item_unique_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
@@ -111,18 +114,19 @@ public:
{
CharacterParcelsContainers e{};
e.id = 0;
e.parcels_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.quantity = 0;
e.evolve_amount = 0;
e.id = 0;
e.parcels_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.item_unique_id = "";
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.quantity = 0;
e.evolve_amount = 0;
return e;
}
@@ -159,18 +163,19 @@ public:
if (results.RowCount() == 1) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_unique_id = row[4] ? row[4] : "";
e.aug_slot_1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.aug_slot_6 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
return e;
}
@@ -207,14 +212,15 @@ public:
v.push_back(columns[1] + " = " + std::to_string(e.parcels_id));
v.push_back(columns[2] + " = " + std::to_string(e.slot_id));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_1));
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_2));
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_3));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[4] + " = '" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_1));
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_2));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_3));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[10] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[11] + " = " + std::to_string(e.quantity));
v.push_back(columns[12] + " = " + std::to_string(e.evolve_amount));
auto results = db.QueryDatabase(
fmt::format(
@@ -240,6 +246,7 @@ public:
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
@@ -281,6 +288,7 @@ public:
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
@@ -322,18 +330,19 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_unique_id = row[4] ? row[4] : "";
e.aug_slot_1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.aug_slot_6 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -358,18 +367,19 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_unique_id = row[4] ? row[4] : "";
e.aug_slot_1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.aug_slot_6 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -448,6 +458,7 @@ public:
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
@@ -482,6 +493,7 @@ public:
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
@@ -28,6 +28,7 @@ public:
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
std::string item_unique_id;
uint32_t slot_id;
uint32_t quantity;
uint32_t evolve_amount;
@@ -53,6 +54,7 @@ public:
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_unique_id",
"slot_id",
"quantity",
"evolve_amount",
@@ -74,6 +76,7 @@ public:
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_unique_id",
"slot_id",
"quantity",
"evolve_amount",
@@ -129,6 +132,7 @@ public:
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_unique_id = "";
e.slot_id = 0;
e.quantity = 0;
e.evolve_amount = 0;
@@ -171,21 +175,22 @@ public:
if (results.RowCount() == 1) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_unique_id = row[9] ? row[9] : "";
e.slot_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.from_name = row[13] ? row[13] : "";
e.note = row[14] ? row[14] : "";
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
return e;
}
@@ -227,12 +232,13 @@ public:
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[9] + " = " + std::to_string(e.slot_id));
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[12] + " = '" + Strings::Escape(e.from_name) + "'");
v.push_back(columns[13] + " = '" + Strings::Escape(e.note) + "'");
v.push_back(columns[14] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
v.push_back(columns[9] + " = '" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(columns[10] + " = " + std::to_string(e.slot_id));
v.push_back(columns[11] + " = " + std::to_string(e.quantity));
v.push_back(columns[12] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[13] + " = '" + Strings::Escape(e.from_name) + "'");
v.push_back(columns[14] + " = '" + Strings::Escape(e.note) + "'");
v.push_back(columns[15] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -263,6 +269,7 @@ public:
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
@@ -307,6 +314,7 @@ public:
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
@@ -346,21 +354,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_unique_id = row[9] ? row[9] : "";
e.slot_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.from_name = row[13] ? row[13] : "";
e.note = row[14] ? row[14] : "";
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -385,21 +394,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_unique_id = row[9] ? row[9] : "";
e.slot_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.from_name = row[13] ? row[13] : "";
e.note = row[14] ? row[14] : "";
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -483,6 +493,7 @@ public:
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
@@ -520,6 +531,7 @@ public:
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
@@ -35,7 +35,7 @@ public:
uint32_t ornament_icon;
uint32_t ornament_idfile;
int32_t ornament_hero_model;
uint64_t guid;
std::string item_unique_id;
};
static std::string PrimaryKey()
@@ -62,7 +62,7 @@ public:
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -85,7 +85,7 @@ public:
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -142,7 +142,7 @@ public:
e.ornament_icon = 0;
e.ornament_idfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
e.item_unique_id = "";
return e;
}
@@ -195,7 +195,7 @@ public:
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
e.item_unique_id = row[16] ? row[16] : "";
return e;
}
@@ -245,7 +245,7 @@ public:
v.push_back(columns[13] + " = " + std::to_string(e.ornament_icon));
v.push_back(columns[14] + " = " + std::to_string(e.ornament_idfile));
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[16] + " = " + std::to_string(e.guid));
v.push_back(columns[16] + " = '" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -283,7 +283,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -329,7 +329,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -379,7 +379,7 @@ public:
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
e.item_unique_id = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -420,7 +420,7 @@ public:
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
e.item_unique_id = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -511,7 +511,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -550,7 +550,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -20,23 +20,23 @@ class BaseInventorySnapshotsRepository {
public:
struct InventorySnapshots {
uint32_t time_index;
uint32_t charid;
uint32_t slotid;
uint32_t itemid;
uint32_t character_id;
uint32_t slot_id;
uint32_t item_id;
uint16_t charges;
uint32_t color;
uint32_t augslot1;
uint32_t augslot2;
uint32_t augslot3;
uint32_t augslot4;
uint32_t augslot5;
int32_t augslot6;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
int32_t augment_six;
uint8_t instnodrop;
std::string custom_data;
uint32_t ornamenticon;
uint32_t ornamentidfile;
uint32_t ornament_icon;
uint32_t ornament_idfile;
int32_t ornament_hero_model;
uint64_t guid;
std::string item_unique_id;
};
static std::string PrimaryKey()
@@ -48,23 +48,23 @@ public:
{
return {
"time_index",
"charid",
"slotid",
"itemid",
"character_id",
"slot_id",
"item_id",
"charges",
"color",
"augslot1",
"augslot2",
"augslot3",
"augslot4",
"augslot5",
"augslot6",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"instnodrop",
"custom_data",
"ornamenticon",
"ornamentidfile",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -72,23 +72,23 @@ public:
{
return {
"time_index",
"charid",
"slotid",
"itemid",
"character_id",
"slot_id",
"item_id",
"charges",
"color",
"augslot1",
"augslot2",
"augslot3",
"augslot4",
"augslot5",
"augslot6",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"instnodrop",
"custom_data",
"ornamenticon",
"ornamentidfile",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -130,23 +130,23 @@ public:
InventorySnapshots e{};
e.time_index = 0;
e.charid = 0;
e.slotid = 0;
e.itemid = 0;
e.character_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.charges = 0;
e.color = 0;
e.augslot1 = 0;
e.augslot2 = 0;
e.augslot3 = 0;
e.augslot4 = 0;
e.augslot5 = 0;
e.augslot6 = 0;
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.instnodrop = 0;
e.custom_data = "";
e.ornamenticon = 0;
e.ornamentidfile = 0;
e.ornament_icon = 0;
e.ornament_idfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
e.item_unique_id = "";
return e;
}
@@ -184,23 +184,23 @@ public:
InventorySnapshots e{};
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.charid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slotid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.itemid = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<uint16_t>(strtoul(row[4], nullptr, 10)) : 0;
e.color = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot1 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot2 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot3 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot4 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot5 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augslot6 = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.augment_one = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_two = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_three = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_four = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_five = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_six = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.custom_data = row[13] ? row[13] : "";
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_icon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_idfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
e.item_unique_id = row[17] ? row[17] : "";
return e;
}
@@ -235,23 +235,23 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.time_index));
v.push_back(columns[1] + " = " + std::to_string(e.charid));
v.push_back(columns[2] + " = " + std::to_string(e.slotid));
v.push_back(columns[3] + " = " + std::to_string(e.itemid));
v.push_back(columns[1] + " = " + std::to_string(e.character_id));
v.push_back(columns[2] + " = " + std::to_string(e.slot_id));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.charges));
v.push_back(columns[5] + " = " + std::to_string(e.color));
v.push_back(columns[6] + " = " + std::to_string(e.augslot1));
v.push_back(columns[7] + " = " + std::to_string(e.augslot2));
v.push_back(columns[8] + " = " + std::to_string(e.augslot3));
v.push_back(columns[9] + " = " + std::to_string(e.augslot4));
v.push_back(columns[10] + " = " + std::to_string(e.augslot5));
v.push_back(columns[11] + " = " + std::to_string(e.augslot6));
v.push_back(columns[6] + " = " + std::to_string(e.augment_one));
v.push_back(columns[7] + " = " + std::to_string(e.augment_two));
v.push_back(columns[8] + " = " + std::to_string(e.augment_three));
v.push_back(columns[9] + " = " + std::to_string(e.augment_four));
v.push_back(columns[10] + " = " + std::to_string(e.augment_five));
v.push_back(columns[11] + " = " + std::to_string(e.augment_six));
v.push_back(columns[12] + " = " + std::to_string(e.instnodrop));
v.push_back(columns[13] + " = '" + Strings::Escape(e.custom_data) + "'");
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
v.push_back(columns[14] + " = " + std::to_string(e.ornament_icon));
v.push_back(columns[15] + " = " + std::to_string(e.ornament_idfile));
v.push_back(columns[16] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[17] + " = " + std::to_string(e.guid));
v.push_back(columns[17] + " = '" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -274,23 +274,23 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.time_index));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -321,23 +321,23 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.time_index));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -372,23 +372,23 @@ public:
InventorySnapshots e{};
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.charid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slotid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.itemid = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<uint16_t>(strtoul(row[4], nullptr, 10)) : 0;
e.color = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot1 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot2 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot3 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot4 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot5 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augslot6 = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.augment_one = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_two = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_three = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_four = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_five = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_six = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.custom_data = row[13] ? row[13] : "";
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_icon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_idfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
e.item_unique_id = row[17] ? row[17] : "";
all_entries.push_back(e);
}
@@ -414,23 +414,23 @@ public:
InventorySnapshots e{};
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.charid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slotid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.itemid = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<uint16_t>(strtoul(row[4], nullptr, 10)) : 0;
e.color = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot1 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot2 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot3 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot4 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot5 = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augslot6 = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.augment_one = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_two = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_three = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_four = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_five = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_six = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.custom_data = row[13] ? row[13] : "";
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_icon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_idfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
e.item_unique_id = row[17] ? row[17] : "";
all_entries.push_back(e);
}
@@ -506,23 +506,23 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.time_index));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -546,23 +546,23 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.time_index));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -34,7 +34,7 @@ public:
uint32_t ornament_icon;
uint32_t ornament_idfile;
int32_t ornament_hero_model;
uint64_t guid;
std::string item_unique_id;
};
static std::string PrimaryKey()
@@ -60,7 +60,7 @@ public:
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -82,7 +82,7 @@ public:
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
"item_unique_id",
};
}
@@ -138,7 +138,7 @@ public:
e.ornament_icon = 0;
e.ornament_idfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
e.item_unique_id = "";
return e;
}
@@ -190,7 +190,7 @@ public:
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
e.item_unique_id = row[15] ? row[15] : "";
return e;
}
@@ -239,7 +239,7 @@ public:
v.push_back(columns[12] + " = " + std::to_string(e.ornament_icon));
v.push_back(columns[13] + " = " + std::to_string(e.ornament_idfile));
v.push_back(columns[14] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[15] + " = " + std::to_string(e.guid));
v.push_back(columns[15] + " = '" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -276,7 +276,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -321,7 +321,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -370,7 +370,7 @@ public:
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
e.item_unique_id = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -410,7 +410,7 @@ public:
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
e.item_unique_id = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -500,7 +500,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -538,7 +538,7 @@ public:
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
+106 -106
View File
@@ -19,24 +19,24 @@
class BaseTraderRepository {
public:
struct Trader {
uint64_t id;
uint32_t char_id;
uint32_t item_id;
uint32_t aug_slot_1;
uint32_t aug_slot_2;
uint32_t aug_slot_3;
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
uint32_t item_sn;
int32_t item_charges;
uint32_t item_cost;
uint8_t slot_id;
uint32_t char_entity_id;
uint32_t char_zone_id;
int32_t char_zone_instance_id;
uint8_t active_transaction;
time_t listing_date;
uint64_t id;
uint32_t character_id;
uint32_t item_id;
std::string item_unique_id;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
uint32_t augment_six;
int32_t item_charges;
uint32_t item_cost;
uint8_t slot_id;
uint32_t char_entity_id;
uint32_t char_zone_id;
int32_t char_zone_instance_id;
uint8_t active_transaction;
time_t listing_date;
};
static std::string PrimaryKey()
@@ -48,15 +48,15 @@ public:
{
return {
"id",
"char_id",
"character_id",
"item_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_sn",
"item_unique_id",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"item_charges",
"item_cost",
"slot_id",
@@ -72,15 +72,15 @@ public:
{
return {
"id",
"char_id",
"character_id",
"item_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_sn",
"item_unique_id",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"item_charges",
"item_cost",
"slot_id",
@@ -130,15 +130,15 @@ public:
Trader e{};
e.id = 0;
e.char_id = 0;
e.character_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_unique_id = "";
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
@@ -184,15 +184,15 @@ public:
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_unique_id = row[3] ? row[3] : "";
e.augment_one = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_two = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_three = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_four = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_five = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_six = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
@@ -234,15 +234,15 @@ public:
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
v.push_back(columns[1] + " = " + std::to_string(e.character_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.aug_slot_1));
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_2));
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_3));
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[9] + " = " + std::to_string(e.item_sn));
v.push_back(columns[3] + " = '" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.augment_one));
v.push_back(columns[5] + " = " + std::to_string(e.augment_two));
v.push_back(columns[6] + " = " + std::to_string(e.augment_three));
v.push_back(columns[7] + " = " + std::to_string(e.augment_four));
v.push_back(columns[8] + " = " + std::to_string(e.augment_five));
v.push_back(columns[9] + " = " + std::to_string(e.augment_six));
v.push_back(columns[10] + " = " + std::to_string(e.item_charges));
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
@@ -273,15 +273,15 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
@@ -320,15 +320,15 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
@@ -371,15 +371,15 @@ public:
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_unique_id = row[3] ? row[3] : "";
e.augment_one = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_two = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_three = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_four = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_five = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_six = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
@@ -413,15 +413,15 @@ public:
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_unique_id = row[3] ? row[3] : "";
e.augment_one = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_two = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_three = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_four = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_five = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_six = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
@@ -505,15 +505,15 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
@@ -545,15 +545,15 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
+27 -2
View File
@@ -106,8 +106,13 @@ public:
return false;
}
auto buy_lines =
BaseBuyerBuyLinesRepository::GetWhere(db, fmt::format("`buyer_id` = {}", buyer.front().id));
auto buy_lines = BaseBuyerBuyLinesRepository::GetWhere(
db,
fmt::format("`buyer_id` = '{}'", buyer.front().id)
);
if (buy_lines.empty()) {
return false;
}
std::vector<std::string> buy_line_ids{};
for (auto const &bl: buy_lines) {
@@ -175,4 +180,24 @@ public:
return true;
}
static bool UpdateBuyerEntityID(Database &db, uint32 char_id, uint32 old_entity_id, uint32 new_entity_id)
{
if (!char_id || !old_entity_id || !new_entity_id) {
return false;
}
auto results = GetWhere(db, fmt::format("`char_id` = {} AND `char_entity_id` = {} LIMIT 1;", char_id, old_entity_id));
if (results.empty()) {
return false;
}
for (auto &e: results) {
e.char_entity_id = new_entity_id;
}
ReplaceMany(db, results);
return true;
}
};
@@ -0,0 +1,53 @@
#ifndef EQEMU_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
#define EQEMU_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_character_offline_transactions_repository.h"
class CharacterOfflineTransactionsRepository: public BaseCharacterOfflineTransactionsRepository {
public:
#define TRADER_TRANSACTION 1
#define BUYER_TRANSACTION 2
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* CharacterOfflineTransactionsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* CharacterOfflineTransactionsRepository::GetWhereNeverExpires()
* CharacterOfflineTransactionsRepository::GetWhereXAndY()
* CharacterOfflineTransactionsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_CHARACTER_OFFLINE_TRANSACTIONS_REPOSITORY_H
@@ -1,8 +1,8 @@
#pragma once
#include "common/repositories/base/base_inventory_snapshots_repository.h"
#include "common/database.h"
#include "common/repositories/base/base_inventory_snapshots_repository.h"
#include "common/repositories/inventory_repository.h"
#include "common/strings.h"
class InventorySnapshotsRepository: public BaseInventorySnapshotsRepository {
@@ -46,16 +46,15 @@ public:
// Custom extended repository methods here
static int64 CountInventorySnapshots(Database& db)
{
const std::string& query = "SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a GROUP BY `charid`, `time_index`) b";
const std::string &query =
"SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a GROUP BY `character_id`, `time_index`) b";
auto results = db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return -1;
}
auto row = results.begin();
auto row = results.begin();
const int64 count = Strings::ToBigInt(row[0]);
if (count > std::numeric_limits<int>::max()) {
@@ -68,4 +67,254 @@ public:
return count;
}
static int64 CountCharacterInvSnapshots(Database& db, uint32 character_id)
{
const std::string &query = fmt::format(
"SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a WHERE "
"`character_id` = {} GROUP BY `time_index`) b",
character_id
);
auto results = db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return -1;
}
auto &row = results.begin();
const int64 count = Strings::ToBigInt(row[0]);
if (count > std::numeric_limits<int>::max()) {
return -2;
}
if (count < 0) {
return -3;
}
return count;
}
static void ClearCharacterInvSnapshots(Database &db, uint32 character_id, bool from_now)
{
uint32 del_time = time(nullptr);
if (!from_now) {
del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400;
}
DeleteWhere(db, fmt::format("`character_id` = {} AND `time_index` <= {}", character_id, del_time));
}
static void ListCharacterInvSnapshots(Database &db, uint32 character_id, std::list<std::pair<uint32, int>> &is_list)
{
const std::string &query = fmt::format(
"SELECT `time_index`, COUNT(*) FROM `inventory_snapshots` WHERE "
"`character_id` = {} GROUP BY `time_index` ORDER BY `time_index` DESC",
character_id
);
auto results = db.QueryDatabase(query);
if (!results.Success())
return;
for (auto row: results) {
is_list.emplace_back(std::pair<uint32, int>(Strings::ToUnsignedInt(row[0]), Strings::ToInt(row[1])));
}
}
static bool ValidateCharacterInvSnapshotTimestamp(Database &db, uint32 character_id, uint32 timestamp)
{
if (!character_id || !timestamp) {
return false;
}
const std::string &query = fmt::format(
"SELECT * FROM `inventory_snapshots` WHERE `character_id` = {} "
"AND `time_index` = {} LIMIT 1",
character_id,
timestamp
);
auto results = db.QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0) {
return false;
}
return true;
}
static void ParseCharacterInvSnapshot(
Database &db,
uint32 character_id,
uint32 timestamp,
std::list<std::pair<int16, uint32>> &parse_list)
{
const std::string &query = fmt::format(
"SELECT `slot_id`, `item_id` FROM `inventory_snapshots` "
"WHERE `character_id` = {} AND `time_index` = {} ORDER BY `slot_id`",
character_id,
timestamp
);
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return;
}
for (auto row: results) {
parse_list.emplace_back(std::pair<int16, uint32>(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1])));
}
}
static void DivergeCharacterInvSnapshotFromInventory(
Database &db,
uint32 character_id,
uint32 timestamp,
std::list<std::pair<int16, uint32>> &compare_list)
{
const std::string &query = fmt::format(
"SELECT slot_id, item_id FROM `inventory_snapshots` "
"WHERE `time_index` = {0} AND `character_id` = {1} AND `slot_id` NOT IN ("
"SELECT a.`slot_id` FROM `inventory_snapshots` a JOIN `inventory` b USING (`slot_id`, `item_id`) "
"WHERE a.`time_index` = {0} AND a.`character_id` = {1} AND b.`character_id` = {1})",
timestamp,
character_id
);
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return;
}
for (auto row: results) {
compare_list.emplace_back(std::pair<int16, uint32>(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1])));
}
}
static void DivergeCharacterInventoryFromInvSnapshot(
Database &db, uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list)
{
const std::string &query = fmt::format(
"SELECT `slot_id`, `item_id` FROM `inventory` WHERE "
"`character_id` = {0} AND `slot_id` NOT IN ("
"SELECT a.`slot_id` FROM `inventory` a JOIN `inventory_snapshots` b USING (`slot_id`, `item_id`) "
"WHERE b.`time_index` = {1} AND b.`character_id` = {0} AND a.`character_id` = {0})",
character_id,
timestamp
);
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return;
}
for (auto row: results) {
compare_list.emplace_back(std::pair<int16, uint32>(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1])));
}
}
static bool SaveCharacterInvSnapshot(Database &db, uint32 character_id)
{
uint32 time_index = time(nullptr);
std::vector<InventorySnapshots> queue{};
auto inventory = InventoryRepository::GetWhere(db, fmt::format("`character_id` = {}", character_id));
if (inventory.empty()) {
LogError("Character ID [{}] inventory is empty. Snapshot not created", character_id);
return false;
}
for (auto const &i: inventory) {
auto s = NewEntity();
s.character_id = i.character_id;
s.item_id = i.item_id;
s.item_unique_id = i.item_unique_id;
s.augment_one = i.augment_one;
s.augment_two = i.augment_two;
s.augment_three = i.augment_three;
s.augment_four = i.augment_four;
s.augment_five = i.augment_five;
s.augment_six = i.augment_six;
s.charges = i.charges;
s.color = i.color;
s.custom_data = i.custom_data;
s.instnodrop = i.instnodrop;
s.ornament_hero_model = i.ornament_hero_model;
s.ornament_icon = i.ornament_icon;
s.ornament_idfile = i.ornament_idfile;
s.slot_id = i.slot_id;
s.time_index = time_index;
s.item_unique_id = i.item_unique_id;
queue.push_back(s);
}
if (queue.empty()) {
LogError("Character ID [{}] inventory is empty. Snapshot not created", character_id);
return false;
}
if (!InsertMany(db, queue)) {
LogError("Failed to created inventory snapshot for [{}]", character_id);
return false;
}
LogInventory("Created inventory snapshot for [{}] with ([{}]) items", character_id, queue.size());
return true;
}
static bool RestoreCharacterInvSnapshot(Database &db, uint32 character_id, uint32 timestamp)
{
auto snapshot = GetWhere(db, fmt::format("`character_id` = {} AND `time_index` = {}", character_id, timestamp));
if (snapshot.empty()) {
LogError("The snapshot requested could not be found. Restore failed for character id [{}] @ [{}] failed",
character_id,
timestamp
);
return false;
}
std::vector<InventoryRepository::Inventory> queue{};
for (auto const &i: snapshot) {
auto e = InventoryRepository::NewEntity();
e.character_id = i.character_id;
e.item_id = i.item_id;
e.item_unique_id = i.item_unique_id;
e.augment_one = i.augment_one;
e.augment_two = i.augment_two;
e.augment_three = i.augment_three;
e.augment_four = i.augment_four;
e.augment_five = i.augment_five;
e.augment_six = i.augment_six;
e.charges = i.charges;
e.color = i.color;
e.custom_data = i.custom_data;
e.instnodrop = i.instnodrop;
e.ornament_hero_model = i.ornament_hero_model;
e.ornament_icon = i.ornament_icon;
e.ornament_idfile = i.ornament_idfile;
e.slot_id = i.slot_id;
e.item_unique_id = i.item_unique_id;
queue.push_back(e);
}
if (queue.empty()) {
LogError("The snapshot is empty. Restore failed for character id [{}] @ [{}] failed", character_id, timestamp);
return false;
}
InventoryRepository::DeleteWhere(db, fmt::format("`character_id` = {}", character_id));
if (!InventoryRepository::InsertMany(db, queue)) {
LogError("A database error occurred. Restore failed for character id [{}] @ [{}] failed", character_id, timestamp);
return false;
}
LogInventory(
"Restore complete for character id [{}] with snapshot @ [{}] with [{}] entries",
character_id,
timestamp,
queue.size()
);
return true;
}
};
@@ -0,0 +1,68 @@
#pragma once
#include "common/database.h"
#include "common/strings.h"
#include "common/item_instance.h"
class ItemUniqueIdReservationsRepository {
public:
static bool Reserve(Database &db, const std::string &item_unique_id)
{
if (item_unique_id.empty()) {
return false;
}
auto results = db.QueryDatabase(
fmt::format(
"INSERT IGNORE INTO item_unique_id_reservations (item_unique_id, reserved_at) VALUES ('{}', NOW())",
Strings::Escape(item_unique_id)
)
);
return results.Success();
}
static std::string ReserveNew(Database &db, uint32 max_attempts = 64)
{
for (uint32 attempt = 0; attempt < max_attempts; ++attempt) {
auto candidate = EQ::UniqueHashGenerator::generate();
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO item_unique_id_reservations (item_unique_id, reserved_at) VALUES ('{}', NOW())",
Strings::Escape(candidate)
)
);
if (results.Success()) {
return candidate;
}
if (results.ErrorNumber() != 1062) {
LogError(
"Failed reserving item_unique_id [{}] (attempt {}): ({}) {}",
candidate,
attempt + 1,
results.ErrorNumber(),
results.ErrorMessage()
);
break;
}
}
return {};
}
static bool PopulateFromTable(Database &db, const std::string &table_name, const std::string &column_name)
{
auto results = db.QueryDatabase(
fmt::format(
"INSERT IGNORE INTO item_unique_id_reservations (item_unique_id, reserved_at) "
"SELECT DISTINCT {1}, NOW() FROM {0} WHERE {1} IS NOT NULL AND {1} <> ''",
table_name,
column_name
)
);
return results.Success();
}
};
+2 -2
View File
@@ -47,7 +47,7 @@ public:
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
Database& db,
const std::vector<std::string> &search_ids,
const std::unordered_set<std::string> &search_ids,
const std::string &name,
const std::string &field_criteria_items,
const std::string &where_criteria_items,
@@ -57,7 +57,7 @@ public:
auto query = fmt::format(
"SELECT id, name, stackable, icon, {} "
"FROM items "
"WHERE `name` LIKE '%%{}%%' AND {} AND id IN({}) "
"WHERE `name` LIKE '%{}%' AND {} AND id IN({}) "
"ORDER BY id ASC",
field_criteria_items,
Strings::Escape(name),
@@ -0,0 +1,98 @@
#pragma once
#include "common/database.h"
#include "common/strings.h"
class OfflineCharacterSessionsRepository {
public:
struct OfflineCharacterSession {
uint64_t id{0};
uint32_t account_id{0};
uint32_t character_id{0};
std::string mode{};
uint32_t zone_id{0};
int32_t instance_id{0};
uint32_t entity_id{0};
time_t started_at{0};
};
static OfflineCharacterSession GetByAccountId(Database &db, uint32 account_id)
{
OfflineCharacterSession session{};
auto results = db.QueryDatabase(
fmt::format(
"SELECT id, account_id, character_id, mode, zone_id, instance_id, entity_id, UNIX_TIMESTAMP(started_at) "
"FROM offline_character_sessions WHERE account_id = {} LIMIT 1",
account_id
)
);
if (!results.Success() || results.RowCount() == 0) {
return session;
}
auto row = results.begin();
session.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
session.account_id = row[1] ? Strings::ToUnsignedInt(row[1]) : 0;
session.character_id = row[2] ? Strings::ToUnsignedInt(row[2]) : 0;
session.mode = row[3] ? row[3] : "";
session.zone_id = row[4] ? Strings::ToUnsignedInt(row[4]) : 0;
session.instance_id = row[5] ? Strings::ToInt(row[5]) : 0;
session.entity_id = row[6] ? Strings::ToUnsignedInt(row[6]) : 0;
session.started_at = row[7] ? Strings::ToUnsignedBigInt(row[7]) : 0;
return session;
}
static bool ExistsByAccountId(Database &db, uint32 account_id)
{
return GetByAccountId(db, account_id).id != 0;
}
static bool Upsert(
Database &db,
uint32 account_id,
uint32 character_id,
const std::string &mode,
uint32 zone_id,
int32 instance_id,
uint32 entity_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO offline_character_sessions (account_id, character_id, mode, zone_id, instance_id, entity_id, started_at) "
"VALUES ({}, {}, '{}', {}, {}, {}, NOW()) "
"ON DUPLICATE KEY UPDATE character_id = VALUES(character_id), mode = VALUES(mode), zone_id = VALUES(zone_id), "
"instance_id = VALUES(instance_id), entity_id = VALUES(entity_id), started_at = VALUES(started_at)",
account_id,
character_id,
Strings::Escape(mode),
zone_id,
instance_id,
entity_id
)
);
return results.Success();
}
static bool DeleteByAccountId(Database &db, uint32 account_id)
{
return db.QueryDatabase(
fmt::format("DELETE FROM offline_character_sessions WHERE account_id = {}", account_id)
).Success();
}
static bool DeleteByCharacterId(Database &db, uint32 character_id)
{
return db.QueryDatabase(
fmt::format("DELETE FROM offline_character_sessions WHERE character_id = {}", character_id)
).Success();
}
static bool Truncate(Database &db)
{
return db.QueryDatabase("TRUNCATE TABLE offline_character_sessions").Success();
}
};
+166 -54
View File
@@ -30,8 +30,12 @@ public:
};
struct BazaarTraderSearch_Struct {
Trader trader;
Trader trader;
std::string trader_name;
std::string name;
bool stackable;
uint32 icon;
uint32 stats;
};
struct WelcomeData_Struct {
@@ -59,9 +63,9 @@ public:
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
results = db.QueryDatabase(fmt::format(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"SELECT DISTINCT(t.character_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON t.char_id = c.id "
"JOIN character_data AS c ON t.character_id = c.id "
"WHERE t.char_zone_instance_id = {} "
"ORDER BY t.char_zone_instance_id ASC "
"LIMIT {}",
@@ -70,13 +74,14 @@ public:
);
}
else {
results = db.QueryDatabase(fmt::format(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON t.char_id = c.id "
"ORDER BY t.char_zone_instance_id ASC "
"LIMIT {}",
max_results)
results = db.QueryDatabase(
fmt::format(
"SELECT DISTINCT(t.character_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON t.character_id = c.id "
"ORDER BY t.char_zone_instance_id ASC "
"LIMIT {}",
max_results)
);
}
@@ -102,7 +107,7 @@ public:
{
WelcomeData_Struct e{};
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader;");
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT character_id), count(character_id) FROM trader;");
if (!results.RowCount()) {
return e;
@@ -114,15 +119,15 @@ public:
return e;
}
static int UpdateItem(Database &db, uint32 char_id, uint32 new_price, uint32 item_id, uint32 item_charges)
static int UpdateItem(Database &db, uint32 character_id, uint32 new_price, uint32 item_id, uint32 item_charges)
{
std::vector<BaseTraderRepository::Trader> items{};
if (item_charges == 0) {
items = GetWhere(
db,
fmt::format(
"char_id = '{}' AND item_id = '{}'",
char_id,
"character_id = {} AND item_id = {}",
character_id,
item_id
)
);
@@ -131,8 +136,8 @@ public:
items = GetWhere(
db,
fmt::format(
"char_id = '{}' AND item_id = '{}' AND item_charges = '{}'",
char_id,
"character_id = {} AND item_id = {} AND item_charges = {}",
character_id,
item_id,
item_charges
)
@@ -156,7 +161,7 @@ public:
Trader item{};
auto query = fmt::format(
"SELECT t.char_id, t.item_id, t.serialnumber, t.charges, t.item_cost, t.slot_id, t.entity_id FROM trader AS t "
"SELECT t.character_id, t.item_id, t.item_unique.id, t.charges, t.item_cost, t.slot_id, t.entity_id FROM trader AS t "
"WHERE t.entity_id = {} AND t.item_id = {} AND t.item_cost = {} "
"LIMIT 1;",
trader_id,
@@ -169,41 +174,103 @@ public:
return item;
}
auto row = results.begin();
item.char_id = Strings::ToInt(row[0]);
item.item_id = Strings::ToInt(row[1]);
item.item_sn = Strings::ToInt(row[2]);
item.item_charges = Strings::ToInt(row[3]);
item.item_cost = Strings::ToInt(row[4]);
item.slot_id = Strings::ToInt(row[5]);
auto row = results.begin();
item.character_id = Strings::ToInt(row[0]);
item.item_id = Strings::ToInt(row[1]);
item.item_unique_id = row[2] ? row[2] : "";
item.item_charges = Strings::ToInt(row[3]);
item.item_cost = Strings::ToInt(row[4]);
item.slot_id = Strings::ToInt(row[5]);
return item;
}
static int UpdateQuantity(Database &db, uint32 char_id, uint32 serial_number, int16 quantity)
static int UpdateQuantity(Database &db, const std::string &item_unique_id, int16 quantity)
{
const auto trader_item = GetWhere(
db,
fmt::format("char_id = '{}' AND item_sn = '{}' ", char_id, serial_number)
fmt::format("`item_unique_id` = '{}' ", item_unique_id)
);
if (trader_item.empty() || trader_item.size() > 1) {
return 0;
}
auto m = trader_item[0];
auto m = trader_item[0];
m.item_charges = quantity;
m.listing_date = time(nullptr);
return UpdateOne(db, m);
}
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number, uint32 trader_id)
static std::vector<Trader> UpdatePrice(Database &db, const std::string &item_unique_id, uint32 price)
{
std::vector<Trader> all_entries{};
auto target_listing = GetWhere(
db,
fmt::format("`item_unique_id` = '{}' LIMIT 1", item_unique_id)
);
if (target_listing.empty()) {
return all_entries;
}
auto target = target_listing.front();
const auto query = fmt::format(
"UPDATE trader SET `item_cost` = {}, `listing_date` = FROM_UNIXTIME({}) WHERE `character_id` = {} AND "
"`item_unique_id` = '{}'",
price,
time(nullptr),
target.character_id,
item_unique_id
);
auto results = db.QueryDatabase(query);
if (results.RowsAffected() == 0) {
return all_entries;
}
all_entries = GetWhere(
db,
fmt::format(
"`character_id` = {} AND `item_unique_id` = '{}'",
target.character_id,
item_unique_id
)
);
return all_entries;
}
static bool UpdateEntityId(Database &db, uint32 character_id, uint32 old_entity_id, uint32 new_entity_id)
{
if (!character_id || !old_entity_id || !new_entity_id) {
return false;
}
auto results = GetWhere(
db,
fmt::format("`character_id` = {} AND `char_entity_id` = {}", character_id, old_entity_id)
);
if (results.empty()) {
return false;
}
for (auto &entry : results) {
entry.char_entity_id = new_entity_id;
}
return ReplaceMany(db, results);
}
static Trader GetItemByItemUniqueNumber(Database &db, std::string &item_unique_id)
{
Trader e{};
const auto trader_item = GetWhere(
db,
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, serial_number)
fmt::format("`item_unique_id` = '{}' LIMIT 1", item_unique_id)
);
if (trader_item.empty()) {
@@ -213,13 +280,12 @@ public:
return trader_item.at(0);
}
static Trader GetItemBySerialNumber(Database &db, std::string serial_number, uint32 trader_id)
static Trader GetItemByItemUniqueNumber(Database &db, const char* item_unique_id)
{
Trader e{};
auto sn = Strings::ToUnsignedBigInt(serial_number);
const auto trader_item = GetWhere(
db,
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, sn)
fmt::format("`item_unique_id` = '{}' LIMIT 1", item_unique_id)
);
if (trader_item.empty()) {
@@ -257,21 +323,16 @@ public:
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
}
static DistinctTraders_Struct GetTraderByInstanceAndSerialnumber(
Database &db,
uint32 instance_id,
const char *serial_number
)
static DistinctTraders_Struct GetTraderByItemUniqueNumber(Database &db, std::string &item_unique_id)
{
DistinctTraders_Struct trader{};
auto query = fmt::format(
"SELECT t.id, t.char_id, c.name "
"SELECT t.id, t.character_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON c.id = t.char_id "
"WHERE t.char_zone_id = 151 AND t.char_zone_instance_id = {} AND t.item_sn = {} LIMIT 1",
instance_id,
serial_number
"JOIN character_data AS c ON c.id = t.character_id "
"WHERE t.item_unique_id = '{}' LIMIT 1",
item_unique_id
);
auto results = db.QueryDatabase(query);
@@ -281,7 +342,6 @@ public:
}
auto row = results.begin();
std::string name = row[2];
trader.trader_id = Strings::ToUnsignedInt(row[1]);
trader.trader_name = row[2] ? row[2] : "";
@@ -290,14 +350,23 @@ public:
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
Database &db,
std::string &search_criteria_trader
const std::string &search_criteria_trader,
const std::string &name,
const std::string &field_criteria_items,
const std::string &where_criteria_items,
uint32 max_results
)
{
std::vector<BazaarTraderSearch_Struct> all_entries{};
auto query = fmt::format(
"SELECT trader.*, c.`name` FROM `trader` INNER JOIN character_data AS c ON trader.char_id = c.id "
"WHERE {} ORDER BY trader.char_id ASC",
"SELECT trader.id, trader.character_id, trader.item_id, trader.item_unique_id, trader.augment_one, "
"trader.augment_two, trader.augment_three, trader.augment_four, trader.augment_five, trader.augment_six, "
"trader.item_charges, trader.item_cost, trader.slot_id, trader.char_entity_id, trader.char_zone_id, "
"trader.char_zone_instance_id, trader.active_transaction, c.`name` FROM `trader` "
"INNER JOIN character_data AS c ON trader.character_id = c.id "
"WHERE {} "
"ORDER BY trader.character_id ASC",
search_criteria_trader
);
@@ -312,15 +381,15 @@ public:
BazaarTraderSearch_Struct e{};
e.trader.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.trader.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.trader.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.trader.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.trader.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.trader.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.trader.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.trader.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.trader.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.trader.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.trader.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.trader.item_unique_id = row[3] ? row[3] : std::string("");
e.trader.augment_one = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.trader.augment_two = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.trader.augment_three = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.trader.augment_four = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.trader.augment_five = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.trader.augment_six = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.trader.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.trader.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.trader.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
@@ -335,4 +404,47 @@ public:
return all_entries;
}
static Trader GetAccountZoneIdAndInstanceIdByAccountId(Database &db, uint32 account_id)
{
auto trader_query = fmt::format(
"SELECT t.id, t.character_id, t.char_zone_id, t.char_zone_instance_id "
"FROM trader AS t "
"WHERE t.character_id IN(SELECT c.id FROM character_data AS c WHERE c.account_id = {}) "
"LIMIT 1;",
account_id
);
auto buyer_query = fmt::format(
"SELECT t.id, t.char_id, t.char_zone_id, t.char_zone_instance_id "
"FROM buyer AS t "
"WHERE t.char_id IN(SELECT c.id FROM character_data AS c WHERE c.account_id = {}) "
"LIMIT 1;",
account_id
);
Trader e{};
auto trader_results = db.QueryDatabase(trader_query);
auto buyer_results = db.QueryDatabase(buyer_query);
if (trader_results.RowCount() == 0 && buyer_results.RowCount() == 0) {
return e;
}
MySQLRequestRow row;
if (trader_results.RowCount() > 0) {
row = trader_results.begin();
}
if (buyer_results.RowCount() > 0) {
row = buyer_results.begin();
}
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char_zone_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char_zone_instance_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
return e;
}
};
+34 -11
View File
@@ -229,10 +229,12 @@
#define ServerOP_LSPlayerJoinWorld 0x3007
#define ServerOP_LSPlayerZoneChange 0x3008
#define ServerOP_UsertoWorldReqLeg 0xAB00
#define ServerOP_UsertoWorldRespLeg 0xAB01
#define ServerOP_UsertoWorldReq 0xAB02
#define ServerOP_UsertoWorldResp 0xAB03
#define ServerOP_UsertoWorldReqLeg 0xAB00
#define ServerOP_UsertoWorldRespLeg 0xAB01
#define ServerOP_UsertoWorldReq 0xAB02
#define ServerOP_UsertoWorldResp 0xAB03
#define ServerOP_UsertoWorldCancelOfflineRequest 0xAB04
#define ServerOP_UsertoWorldCancelOfflineResponse 0xAB05
#define ServerOP_LauncherConnectInfo 0x3000
#define ServerOP_LauncherZoneRequest 0x3001
@@ -360,14 +362,24 @@ enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_
enum {
UserToWorldStatusWorldUnavail = 0,
UserToWorldStatusSuccess = 1,
UserToWorldStatusSuspended = -1,
UserToWorldStatusBanned = -2,
UserToWorldStatusWorldAtCapacity = -3,
UserToWorldStatusAlreadyOnline = -4
UserToWorldStatusWorldUnavail = 0,
UserToWorldStatusSuccess = 1,
UserToWorldStatusSuspended = -1,
UserToWorldStatusBanned = -2,
UserToWorldStatusWorldAtCapacity = -3,
UserToWorldStatusAlreadyOnline = -4,
UserToWorldStatusOffilineTraderBuyer = -5
};
enum {
BazaarPurchaseFailed = 0,
BazaarPurchaseSuccess = 1,
BazaarPurchaseBuyerCompleteSendToSeller = 2,
BazaarPurchaseSellerCompleteSendToBuyer = 3,
BazaarPurchaseBuyerFailed = 4,
BazaarPurchaseBuyerSuccess = 5,
BazaarPurchaseTraderFailed = 6
};
/************ PACKET RELATED STRUCT ************/
class ServerPacket
{
@@ -559,6 +571,9 @@ struct ServerClientList_Struct {
uint8 LFGToLevel;
bool LFGMatchFilter;
char LFGComments[64];
bool trader;
bool buyer;
bool offline;
};
struct ServerClientListKeepAlive_Struct {
@@ -1022,6 +1037,7 @@ struct ServerGuildMemberUpdate_Struct {
char member_name[64];
uint32 zone_id;
uint32 last_seen;
uint32 offline_mode;
};
struct ServerGuildPermissionUpdate_Struct {
@@ -1776,8 +1792,15 @@ struct BazaarPurchaseMessaging_Struct {
uint32 item_aug_5;
uint32 item_aug_6;
uint32 buyer_id;
uint32 item_quantity_available;
uint32 item_quantity;
int16 item_charges;
uint32 id;
uint32 trader_zone_id;
uint32 trader_zone_instance_id;
uint32 buyer_zone_id;
uint32 buyer_zone_instance_id;
uint32 transaction_status;
bool offline_purchase;
};
#pragma pack(pop)
+31 -15
View File
@@ -275,7 +275,12 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance*
e.ornament_icon = inst->GetOrnamentationIcon();
e.ornament_idfile = inst->GetOrnamentationIDFile();
e.ornament_hero_model = inst->GetOrnamentHeroModel();
e.guid = inst->GetSerialNumber();
e.item_unique_id = inst->GetUniqueID();
if (!EnsureItemUniqueId(e.item_unique_id)) {
return false;
}
const_cast<EQ::ItemInstance *>(inst)->SetUniqueID(e.item_unique_id);
const int replaced = InventoryRepository::ReplaceOne(*this, e);
@@ -325,7 +330,12 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const EQ::ItemInstance
e.ornament_icon = inst->GetOrnamentationIcon();
e.ornament_idfile = inst->GetOrnamentationIDFile();
e.ornament_hero_model = inst->GetOrnamentHeroModel();
e.guid = inst->GetSerialNumber();
e.item_unique_id = inst->GetUniqueID();
if (!EnsureItemUniqueId(e.item_unique_id)) {
return false;
}
const_cast<EQ::ItemInstance *>(inst)->SetUniqueID(e.item_unique_id);
const int replaced = SharedbankRepository::ReplaceOne(*this, e);
@@ -630,12 +640,6 @@ bool SharedDatabase::GetInventory(Client *c)
return false;
}
for (auto const& row: results) {
if (row.guid != 0) {
EQ::ItemInstance::AddGUIDToMap(row.guid);
}
}
const auto timestamps = GetItemRecastTimestamps(char_id);
auto cv_conflict = false;
const auto pmask = inv.GetLookup()->PossessionsBitmask;
@@ -713,6 +717,21 @@ bool SharedDatabase::GetInventory(Client *c)
inst->SetOrnamentationIDFile(ornament_idfile);
inst->SetOrnamentHeroModel(item->HerosForgeModel);
//Mass conversion handled by world
//This remains as a backup. Should not be required.
if (row.item_unique_id.empty()) {
if (!EnsureItemUniqueId(row.item_unique_id)) {
continue;
}
inst->SetUniqueID(row.item_unique_id);
queue.push_back(row);
}
else {
ReserveItemUniqueId(row.item_unique_id);
inst->SetUniqueID(row.item_unique_id);
}
if (
instnodrop ||
(
@@ -727,7 +746,7 @@ bool SharedDatabase::GetInventory(Client *c)
inst->SetColor(color);
}
if (charges == std::numeric_limits<int16>::max()) {
if (charges > std::numeric_limits<int16>::max()) {
inst->SetCharges(-1);
} else if (charges == 0 && inst->IsStackable()) {
// Stackable items need a minimum charge of 1 remain moveable.
@@ -808,8 +827,7 @@ bool SharedDatabase::GetInventory(Client *c)
put_slot_id = inv.PutItem(slot_id, *inst);
}
row.guid = inst->GetSerialNumber();
queue.push_back(row);
//queue.push_back(row);
safe_delete(inst);
@@ -839,8 +857,6 @@ bool SharedDatabase::GetInventory(Client *c)
InventoryRepository::ReplaceMany(*this, queue);
}
EQ::ItemInstance::ClearGUIDMap();
// Retrieve shared inventory
return GetSharedBank(char_id, &inv, true);
}
@@ -1401,7 +1417,7 @@ EQ::ItemInstance* SharedDatabase::CreateItem(
return inst;
}
EQ::ItemInstance* SharedDatabase::CreateBaseItem(const EQ::ItemData* item, int16 charges) {
EQ::ItemInstance* SharedDatabase::CreateBaseItem(const EQ::ItemData* item, int16 charges, const std::string &item_unique_id) {
EQ::ItemInstance* inst = nullptr;
if (item) {
// if maxcharges is -1 that means it is an unlimited use item.
@@ -1415,7 +1431,7 @@ EQ::ItemInstance* SharedDatabase::CreateBaseItem(const EQ::ItemData* item, int16
charges = 1;
}
inst = new EQ::ItemInstance(item, charges);
inst = new EQ::ItemInstance(item, item_unique_id, charges);
if (!inst) {
LogError("Error: valid item data returned a null reference for EQ::ItemInstance creation in SharedDatabase::CreateBaseItem()");
+1 -1
View File
@@ -154,7 +154,7 @@ public:
uint32 ornamentidfile = 0,
uint32 ornament_hero_model = 0
);
EQ::ItemInstance *CreateBaseItem(const EQ::ItemData *item, int16 charges = 0);
EQ::ItemInstance *CreateBaseItem(const EQ::ItemData *item, int16 charges = 0, const std::string &item_unique_id = "");
void GetItemsCount(int32& item_count, uint32& max_id);
void LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id);
+19
View File
@@ -960,3 +960,22 @@ bool Strings::IsValidJson(const std::string &json)
return result;
}
std::string Strings::Implode(const std::string& glue, std::unordered_set<std::string> src)
{
if (src.empty()) {
return {};
}
std::ostringstream output;
std::unordered_set<std::string>::iterator src_iter;
for (src_iter = src.begin(); src_iter != src.end(); src_iter++) {
output << *src_iter << glue;
}
std::string final_output = output.str();
final_output.resize(output.str().size() - glue.size());
return final_output;
}
+2
View File
@@ -45,6 +45,7 @@
#include <string>
#include <type_traits>
#include <vector>
#include <unordered_set>
class Strings {
public:
@@ -76,6 +77,7 @@ public:
static std::string Escape(const std::string &s);
static std::string GetBetween(const std::string &s, std::string start_delim, std::string stop_delim);
static std::string Implode(const std::string& glue, std::vector<std::string> src);
static std::string Implode(const std::string& glue, std::unordered_set<std::string> src);
static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
static std::string MillisecondsToTime(int duration);
+1 -1
View File
@@ -41,6 +41,6 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9330
#define CURRENT_BINARY_DATABASE_VERSION 9340
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
#define CUSTOM_BINARY_DATABASE_VERSION 0