mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-13 06:48:20 +00:00
Implement bazaar item identity and offline trading rework
This commit is contained in:
@@ -191,6 +191,7 @@ set(repositories
|
|||||||
repositories/base/base_character_leadership_abilities_repository.h
|
repositories/base/base_character_leadership_abilities_repository.h
|
||||||
repositories/base/base_character_material_repository.h
|
repositories/base/base_character_material_repository.h
|
||||||
repositories/base/base_character_memmed_spells_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_containers_repository.h
|
||||||
repositories/base/base_character_parcels_repository.h
|
repositories/base/base_character_parcels_repository.h
|
||||||
repositories/base/base_character_peqzone_flags_repository.h
|
repositories/base/base_character_peqzone_flags_repository.h
|
||||||
@@ -389,6 +390,7 @@ set(repositories
|
|||||||
repositories/character_leadership_abilities_repository.h
|
repositories/character_leadership_abilities_repository.h
|
||||||
repositories/character_material_repository.h
|
repositories/character_material_repository.h
|
||||||
repositories/character_memmed_spells_repository.h
|
repositories/character_memmed_spells_repository.h
|
||||||
|
repositories/character_offline_transactions_repository.h
|
||||||
repositories/character_parcels_containers_repository.h
|
repositories/character_parcels_containers_repository.h
|
||||||
repositories/character_parcels_repository.h
|
repositories/character_parcels_repository.h
|
||||||
repositories/character_peqzone_flags_repository.h
|
repositories/character_peqzone_flags_repository.h
|
||||||
|
|||||||
+42
-39
@@ -188,11 +188,11 @@ Bazaar::GetSearchResults(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
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 {
|
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<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()) {
|
if (trader_results.empty()) {
|
||||||
LogTradingDetail("Bazaar - No traders found in bazaar search.");
|
LogTradingDetail("Bazaar - No traders found in bazaar search.");
|
||||||
return all_entries;
|
return all_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const &i: trader_results) {
|
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(
|
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
|
||||||
@@ -291,43 +299,38 @@ Bazaar::GetSearchResults(
|
|||||||
|
|
||||||
all_entries.reserve(trader_results.size());
|
all_entries.reserve(trader_results.size());
|
||||||
|
|
||||||
for (auto const& t:trader_results) {
|
for (auto const& t:trader_results) {
|
||||||
if (!item_results.contains(t.trader.item_id)) {
|
if (!item_results.contains(t.trader.item_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BazaarSearchResultsFromDB_Struct r{};
|
BazaarSearchResultsFromDB_Struct r{};
|
||||||
r.count = 1;
|
r.count = 1;
|
||||||
r.trader_id = t.trader.char_id;
|
r.trader_id = t.trader.character_id;
|
||||||
r.serial_number = t.trader.item_sn;
|
r.item_unique_id = t.trader.item_unique_id;
|
||||||
r.cost = t.trader.item_cost;
|
r.cost = t.trader.item_cost;
|
||||||
r.slot_id = t.trader.slot_id;
|
r.slot_id = t.trader.slot_id;
|
||||||
r.charges = t.trader.item_charges;
|
r.charges = t.trader.item_charges;
|
||||||
r.stackable = item_results.at(t.trader.item_id).stackable;
|
r.stackable = item_results.at(t.trader.item_id).stackable;
|
||||||
r.icon_id = item_results.at(t.trader.item_id).icon;
|
r.icon_id = item_results.at(t.trader.item_id).icon;
|
||||||
r.trader_zone_id = t.trader.char_zone_id;
|
r.trader_zone_id = t.trader.char_zone_id;
|
||||||
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
|
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
|
||||||
r.trader_entity_id = t.trader.char_entity_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.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.trader_name = fmt::format("{:.63}\0", t.trader_name);
|
r.item_stat = item_results.at(t.trader.item_id).stats;
|
||||||
r.item_stat = item_results.at(t.trader.item_id).stats;
|
|
||||||
|
|
||||||
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
||||||
if (convert ||
|
if (convert ||
|
||||||
char_zone_id != Zones::BAZAAR ||
|
char_zone_id != Zones::BAZAAR ||
|
||||||
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
|
(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;
|
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
all_entries.push_back(r);
|
all_entries.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all_entries.size() > search.max_results) {
|
|
||||||
all_entries.resize(search.max_results);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogTrading("Returning [{}] items from search results", all_entries.size());
|
LogTrading("Returning [{}] items from search results", all_entries.size());
|
||||||
|
|
||||||
|
|||||||
+541
-3
@@ -33,6 +33,7 @@
|
|||||||
#include "common/repositories/character_data_repository.h"
|
#include "common/repositories/character_data_repository.h"
|
||||||
#include "common/repositories/character_languages_repository.h"
|
#include "common/repositories/character_languages_repository.h"
|
||||||
#include "common/repositories/character_leadership_abilities_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_parcels_repository.h"
|
||||||
#include "common/repositories/character_pet_name_repository.h"
|
#include "common/repositories/character_pet_name_repository.h"
|
||||||
#include "common/repositories/character_skills_repository.h"
|
#include "common/repositories/character_skills_repository.h"
|
||||||
@@ -49,6 +50,8 @@
|
|||||||
#include "common/repositories/raid_details_repository.h"
|
#include "common/repositories/raid_details_repository.h"
|
||||||
#include "common/repositories/raid_members_repository.h"
|
#include "common/repositories/raid_members_repository.h"
|
||||||
#include "common/repositories/reports_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/trader_repository.h"
|
||||||
#include "common/repositories/variables_repository.h"
|
#include "common/repositories/variables_repository.h"
|
||||||
#include "common/repositories/zone_repository.h"
|
#include "common/repositories/zone_repository.h"
|
||||||
@@ -56,8 +59,10 @@
|
|||||||
#include "common/strings.h"
|
#include "common/strings.h"
|
||||||
#include "common/zone_store.h"
|
#include "common/zone_store.h"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "common/repositories/sharedbank_repository.h"
|
||||||
|
|
||||||
extern Client client;
|
extern Client client;
|
||||||
|
|
||||||
@@ -187,7 +192,7 @@ void Database::LoginIP(uint32 account_id, const std::string& login_ip)
|
|||||||
QueryDatabase(query);
|
QueryDatabase(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 Database::GetAccountStatus(uint32 account_id)
|
AccountStatus::StatusRecord Database::GetAccountStatus(uint32 account_id)
|
||||||
{
|
{
|
||||||
auto e = AccountRepository::FindOne(*this, account_id);
|
auto e = AccountRepository::FindOne(*this, account_id);
|
||||||
|
|
||||||
@@ -199,7 +204,11 @@ int16 Database::GetAccountStatus(uint32 account_id)
|
|||||||
AccountRepository::UpdateOne(*this, e);
|
AccountRepository::UpdateOne(*this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.status;
|
AccountStatus::StatusRecord result{};
|
||||||
|
result.status = e.status;
|
||||||
|
result.offline = e.offline;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Database::CreateAccount(
|
uint32 Database::CreateAccount(
|
||||||
@@ -2242,6 +2251,7 @@ void Database::ClearGuildOnlineStatus()
|
|||||||
void Database::ClearTraderDetails()
|
void Database::ClearTraderDetails()
|
||||||
{
|
{
|
||||||
TraderRepository::Truncate(*this);
|
TraderRepository::Truncate(*this);
|
||||||
|
AccountRepository::ClearAllOfflineStatus(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::ClearBuyerDetails()
|
void Database::ClearBuyerDetails()
|
||||||
@@ -2265,3 +2275,531 @@ uint64_t Database::GetNextTableId(const std::string &table_name)
|
|||||||
|
|
||||||
return 1;
|
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
@@ -158,8 +158,8 @@ public:
|
|||||||
const std::string GetLiveChar(uint32 account_id);
|
const std::string GetLiveChar(uint32 account_id);
|
||||||
bool SetAccountStatus(const std::string& account_name, int16 status);
|
bool SetAccountStatus(const std::string& account_name, int16 status);
|
||||||
bool SetLocalPassword(uint32 account_id, const std::string& password);
|
bool SetLocalPassword(uint32 account_id, const std::string& password);
|
||||||
|
AccountStatus::StatusRecord GetAccountStatus(uint32 account_id);
|
||||||
bool UpdateLiveChar(const std::string& name, 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);
|
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 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
|
||||||
uint32 CreateAccount(
|
uint32 CreateAccount(
|
||||||
@@ -264,6 +264,18 @@ public:
|
|||||||
void Decode(std::string &in);
|
void Decode(std::string &in);
|
||||||
|
|
||||||
uint64_t GetNextTableId(const std::string& table_name);
|
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:
|
private:
|
||||||
Mutex Mvarcache;
|
Mutex Mvarcache;
|
||||||
|
|||||||
@@ -7211,6 +7211,183 @@ ALTER TABLE `character_buffs`
|
|||||||
.sql = R"(
|
.sql = R"(
|
||||||
ALTER TABLE `character_pet_buffs`
|
ALTER TABLE `character_pet_buffs`
|
||||||
ADD COLUMN `suppressed` tinyint(1) unsigned NOT NULL DEFAULT 0 AFTER `instrument_mod`;
|
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
|
.content_schema_update = false
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ namespace DatabaseSchema {
|
|||||||
{"character_leadership_abilities", "id"},
|
{"character_leadership_abilities", "id"},
|
||||||
{"character_material", "id"},
|
{"character_material", "id"},
|
||||||
{"character_memmed_spells", "id"},
|
{"character_memmed_spells", "id"},
|
||||||
|
{"character_offline_transactions", "character_id"},
|
||||||
{"character_parcels", "char_id"},
|
{"character_parcels", "char_id"},
|
||||||
{"character_parcels_containers", "id"},
|
{"character_parcels_containers", "id"},
|
||||||
{"character_pet_buffs", "char_id"},
|
{"character_pet_buffs", "char_id"},
|
||||||
@@ -80,13 +81,13 @@ namespace DatabaseSchema {
|
|||||||
{"guilds", "id"},
|
{"guilds", "id"},
|
||||||
{"instance_list_player", "id"},
|
{"instance_list_player", "id"},
|
||||||
{"inventory", "character_id"},
|
{"inventory", "character_id"},
|
||||||
{"inventory_snapshots", "charid"},
|
{"inventory_snapshots", "character_id"},
|
||||||
{"keyring", "char_id"},
|
{"keyring", "char_id"},
|
||||||
{"mail", "charid"},
|
{"mail", "charid"},
|
||||||
{"player_titlesets", "char_id"},
|
{"player_titlesets", "char_id"},
|
||||||
{"quest_globals", "charid"},
|
{"quest_globals", "charid"},
|
||||||
{"timers", "char_id"},
|
{"timers", "char_id"},
|
||||||
{"trader", "char_id"},
|
{"trader", "character_id"},
|
||||||
{"zone_flags", "charID"}
|
{"zone_flags", "charID"}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -133,6 +134,7 @@ namespace DatabaseSchema {
|
|||||||
"character_leadership_abilities",
|
"character_leadership_abilities",
|
||||||
"character_material",
|
"character_material",
|
||||||
"character_memmed_spells",
|
"character_memmed_spells",
|
||||||
|
"character_offline_transactions",
|
||||||
"character_parcels",
|
"character_parcels",
|
||||||
"character_parcels_containers",
|
"character_parcels_containers",
|
||||||
"character_pet_buffs",
|
"character_pet_buffs",
|
||||||
@@ -162,8 +164,10 @@ namespace DatabaseSchema {
|
|||||||
"instance_list_player",
|
"instance_list_player",
|
||||||
"inventory",
|
"inventory",
|
||||||
"inventory_snapshots",
|
"inventory_snapshots",
|
||||||
|
"item_unique_id_reservations",
|
||||||
"keyring",
|
"keyring",
|
||||||
"mail",
|
"mail",
|
||||||
|
"offline_character_sessions",
|
||||||
"petitions",
|
"petitions",
|
||||||
"player_titlesets",
|
"player_titlesets",
|
||||||
"quest_globals",
|
"quest_globals",
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ namespace AccountStatus {
|
|||||||
constexpr uint8 Max = 255;
|
constexpr uint8 Max = 255;
|
||||||
|
|
||||||
std::string GetName(uint8 account_status);
|
std::string GetName(uint8 account_status);
|
||||||
|
|
||||||
|
struct StatusRecord {
|
||||||
|
int16 status;
|
||||||
|
uint32 offline;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<uint8, std::string> account_status_names = {
|
static std::map<uint8, std::string> account_status_names = {
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ N(OP_BuyerItems),
|
|||||||
N(OP_CameraEffect),
|
N(OP_CameraEffect),
|
||||||
N(OP_Camp),
|
N(OP_Camp),
|
||||||
N(OP_CancelSneakHide),
|
N(OP_CancelSneakHide),
|
||||||
|
N(OP_CancelOfflineTrader),
|
||||||
|
N(OP_CancelOfflineTraderResponse),
|
||||||
N(OP_CancelTask),
|
N(OP_CancelTask),
|
||||||
N(OP_CancelTrade),
|
N(OP_CancelTrade),
|
||||||
N(OP_CashReward),
|
N(OP_CashReward),
|
||||||
@@ -381,6 +383,7 @@ N(OP_MultiLineMsg),
|
|||||||
N(OP_NewSpawn),
|
N(OP_NewSpawn),
|
||||||
N(OP_NewTitlesAvailable),
|
N(OP_NewTitlesAvailable),
|
||||||
N(OP_NewZone),
|
N(OP_NewZone),
|
||||||
|
N(OP_Offline),
|
||||||
N(OP_OnLevelMessage),
|
N(OP_OnLevelMessage),
|
||||||
N(OP_OpenContainer),
|
N(OP_OpenContainer),
|
||||||
N(OP_OpenDiscordMerchant),
|
N(OP_OpenDiscordMerchant),
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
ClientUnknown::constants::EXPANSIONS_MASK,
|
ClientUnknown::constants::EXPANSIONS_MASK,
|
||||||
ClientUnknown::INULL,
|
ClientUnknown::INULL,
|
||||||
ClientUnknown::INULL,
|
ClientUnknown::INULL,
|
||||||
|
ClientUnknown::INULL,
|
||||||
ClientUnknown::INULL
|
ClientUnknown::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::Client62] =*/
|
/*[ClientVersion::Client62] =*/
|
||||||
@@ -57,6 +58,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
Client62::constants::EXPANSIONS_MASK,
|
Client62::constants::EXPANSIONS_MASK,
|
||||||
Client62::INULL,
|
Client62::INULL,
|
||||||
Client62::INULL,
|
Client62::INULL,
|
||||||
|
Client62::INULL,
|
||||||
Client62::INULL
|
Client62::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::Titanium] =*/
|
/*[ClientVersion::Titanium] =*/
|
||||||
@@ -66,6 +68,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
Titanium::constants::EXPANSIONS_MASK,
|
Titanium::constants::EXPANSIONS_MASK,
|
||||||
Titanium::constants::CHARACTER_CREATION_LIMIT,
|
Titanium::constants::CHARACTER_CREATION_LIMIT,
|
||||||
Titanium::constants::SAY_LINK_BODY_SIZE,
|
Titanium::constants::SAY_LINK_BODY_SIZE,
|
||||||
|
Titanium::INULL,
|
||||||
Titanium::INULL
|
Titanium::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::SoF] =*/
|
/*[ClientVersion::SoF] =*/
|
||||||
@@ -75,6 +78,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
SoF::constants::EXPANSIONS_MASK,
|
SoF::constants::EXPANSIONS_MASK,
|
||||||
SoF::constants::CHARACTER_CREATION_LIMIT,
|
SoF::constants::CHARACTER_CREATION_LIMIT,
|
||||||
SoF::constants::SAY_LINK_BODY_SIZE,
|
SoF::constants::SAY_LINK_BODY_SIZE,
|
||||||
|
SoF::INULL,
|
||||||
SoF::INULL
|
SoF::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::SoD] =*/
|
/*[ClientVersion::SoD] =*/
|
||||||
@@ -84,6 +88,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
SoD::constants::EXPANSIONS_MASK,
|
SoD::constants::EXPANSIONS_MASK,
|
||||||
SoD::constants::CHARACTER_CREATION_LIMIT,
|
SoD::constants::CHARACTER_CREATION_LIMIT,
|
||||||
SoD::constants::SAY_LINK_BODY_SIZE,
|
SoD::constants::SAY_LINK_BODY_SIZE,
|
||||||
|
SoD::INULL,
|
||||||
SoD::INULL
|
SoD::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::UF] =*/
|
/*[ClientVersion::UF] =*/
|
||||||
@@ -93,6 +98,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
UF::constants::EXPANSIONS_MASK,
|
UF::constants::EXPANSIONS_MASK,
|
||||||
UF::constants::CHARACTER_CREATION_LIMIT,
|
UF::constants::CHARACTER_CREATION_LIMIT,
|
||||||
UF::constants::SAY_LINK_BODY_SIZE,
|
UF::constants::SAY_LINK_BODY_SIZE,
|
||||||
|
UF::INULL,
|
||||||
UF::INULL
|
UF::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::RoF] =*/
|
/*[ClientVersion::RoF] =*/
|
||||||
@@ -102,6 +108,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
RoF::constants::EXPANSIONS_MASK,
|
RoF::constants::EXPANSIONS_MASK,
|
||||||
RoF::constants::CHARACTER_CREATION_LIMIT,
|
RoF::constants::CHARACTER_CREATION_LIMIT,
|
||||||
RoF::constants::SAY_LINK_BODY_SIZE,
|
RoF::constants::SAY_LINK_BODY_SIZE,
|
||||||
|
RoF::INULL,
|
||||||
RoF::INULL
|
RoF::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::RoF2] =*/
|
/*[ClientVersion::RoF2] =*/
|
||||||
@@ -111,7 +118,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
RoF2::constants::EXPANSIONS_MASK,
|
RoF2::constants::EXPANSIONS_MASK,
|
||||||
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
||||||
RoF2::constants::SAY_LINK_BODY_SIZE,
|
RoF2::constants::SAY_LINK_BODY_SIZE,
|
||||||
RoF2::constants::MAX_BAZAAR_TRADERS
|
RoF2::constants::MAX_BAZAAR_TRADERS,
|
||||||
|
RoF2::constants::MAX_BAZAAR_TRANSACTION
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -42,6 +42,7 @@ namespace EQ
|
|||||||
int16 CharacterCreationLimit;
|
int16 CharacterCreationLimit;
|
||||||
size_t SayLinkBodySize;
|
size_t SayLinkBodySize;
|
||||||
uint32 BazaarTraderLimit;
|
uint32 BazaarTraderLimit;
|
||||||
|
uint64 BazaarMaxTransaction;
|
||||||
|
|
||||||
LookupEntry(const LookupEntry *lookup_entry) { }
|
LookupEntry(const LookupEntry *lookup_entry) { }
|
||||||
LookupEntry(
|
LookupEntry(
|
||||||
@@ -50,14 +51,16 @@ namespace EQ
|
|||||||
uint32 ExpansionsMask,
|
uint32 ExpansionsMask,
|
||||||
int16 CharacterCreationLimit,
|
int16 CharacterCreationLimit,
|
||||||
size_t SayLinkBodySize,
|
size_t SayLinkBodySize,
|
||||||
uint32 BazaarTraderLimit
|
uint32 BazaarTraderLimit,
|
||||||
|
uint64 BazaarMaxTransaction
|
||||||
) :
|
) :
|
||||||
Expansion(Expansion),
|
Expansion(Expansion),
|
||||||
ExpansionBit(ExpansionBit),
|
ExpansionBit(ExpansionBit),
|
||||||
ExpansionsMask(ExpansionsMask),
|
ExpansionsMask(ExpansionsMask),
|
||||||
CharacterCreationLimit(CharacterCreationLimit),
|
CharacterCreationLimit(CharacterCreationLimit),
|
||||||
SayLinkBodySize(SayLinkBodySize),
|
SayLinkBodySize(SayLinkBodySize),
|
||||||
BazaarTraderLimit(BazaarTraderLimit)
|
BazaarTraderLimit(BazaarTraderLimit),
|
||||||
|
BazaarMaxTransaction(BazaarMaxTransaction)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+95
-18
@@ -327,6 +327,7 @@ union
|
|||||||
bool buyer;
|
bool buyer;
|
||||||
bool untargetable;
|
bool untargetable;
|
||||||
uint32 npc_tint_id;
|
uint32 npc_tint_id;
|
||||||
|
bool offline;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerState_Struct {
|
struct PlayerState_Struct {
|
||||||
@@ -3094,7 +3095,7 @@ struct BazaarSearchCriteria_Struct {
|
|||||||
struct BazaarInspect_Struct {
|
struct BazaarInspect_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
char player_name[64];
|
char player_name[64];
|
||||||
uint32 serial_number;
|
char item_unique_id[17];
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
};
|
};
|
||||||
@@ -3730,6 +3731,36 @@ struct Trader_Struct {
|
|||||||
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
|
/*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 {
|
struct ClickTrader_Struct {
|
||||||
/*000*/ uint32 action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 unknown_004;
|
/*004*/ uint32 unknown_004;
|
||||||
@@ -3743,6 +3774,52 @@ struct GetItems_Struct{
|
|||||||
int32 charges[EQ::invtype::BAZAAR_SIZE];
|
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 {
|
struct BecomeTrader_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
uint16 zone_id;
|
uint16 zone_id;
|
||||||
@@ -3775,7 +3852,7 @@ struct TraderBuy_Struct {
|
|||||||
/*084*/ char seller_name[64];
|
/*084*/ char seller_name[64];
|
||||||
/*148*/ char unknown_148[32];
|
/*148*/ char unknown_148[32];
|
||||||
/*180*/ char item_name[64];
|
/*180*/ char item_name[64];
|
||||||
/*244*/ char serial_number[17];
|
/*244*/ char item_unique_id[17];
|
||||||
/*261*/ char unknown_261[3];
|
/*261*/ char unknown_261[3];
|
||||||
/*264*/ uint32 item_id;
|
/*264*/ uint32 item_id;
|
||||||
/*268*/ uint32 price;
|
/*268*/ uint32 price;
|
||||||
@@ -3794,12 +3871,12 @@ struct TraderItemUpdate_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderPriceUpdate_Struct {
|
struct TraderPriceUpdate_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 SubAction;
|
/*002*/ uint32 sub_action;
|
||||||
/*008*/ int32 SerialNumber;
|
/*004*/ char item_unique_id[17];
|
||||||
/*012*/ uint32 Unknown012;
|
/*021*/ char unknown_021[3];
|
||||||
/*016*/ uint32 NewPrice;
|
/*024*/ uint32 unknown_024;
|
||||||
/*020*/ uint32 Unknown016;
|
/*028*/ uint32 new_price;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MoneyUpdate_Struct{
|
struct MoneyUpdate_Struct{
|
||||||
@@ -3814,6 +3891,7 @@ struct TraderDelItem_Struct{
|
|||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
uint32 unknown_012;
|
uint32 unknown_012;
|
||||||
|
char item_unique_id[17];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
@@ -3837,12 +3915,12 @@ struct SimpleMessage_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct GuildMemberUpdate_Struct {
|
struct GuildMemberUpdate_Struct {
|
||||||
/*00*/ uint32 GuildID;
|
/*00*/ uint32 GuildID;
|
||||||
/*04*/ char MemberName[64];
|
/*04*/ char MemberName[64];
|
||||||
/*68*/ uint16 ZoneID;
|
/*68*/ uint16 ZoneID;
|
||||||
/*70*/ uint16 InstanceID; //speculated
|
/*72*/ uint16 InstanceID; //speculated
|
||||||
/*72*/ uint32 LastSeen; //unix timestamp
|
/*76*/ uint32 LastSeen; //unix timestamp
|
||||||
/*76*/
|
/*80*/ uint32 offline_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GuildMemberLevelUpdate_Struct {
|
struct GuildMemberLevelUpdate_Struct {
|
||||||
@@ -3865,6 +3943,7 @@ struct Internal_GuildMemberEntry_Struct {
|
|||||||
uint16 zoneinstance; //network byte order
|
uint16 zoneinstance; //network byte order
|
||||||
uint16 zone_id; //network byte order
|
uint16 zone_id; //network byte order
|
||||||
uint32 online;
|
uint32 online;
|
||||||
|
uint32 offline_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Internal_GuildMembers_Struct { //just for display purposes, this is not actually used in the message encoding.
|
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 count;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
uint32 serial_number;
|
std::string item_unique_id;
|
||||||
uint32 charges;
|
uint32 charges;
|
||||||
uint32 cost;
|
uint32 cost;
|
||||||
uint32 slot_id;
|
uint32 slot_id;
|
||||||
@@ -6431,7 +6510,6 @@ struct BazaarSearchResultsFromDB_Struct {
|
|||||||
uint32 item_stat;
|
uint32 item_stat;
|
||||||
bool stackable;
|
bool stackable;
|
||||||
std::string item_name;
|
std::string item_name;
|
||||||
std::string serial_number_RoF;
|
|
||||||
std::string trader_name;
|
std::string trader_name;
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
@@ -6441,7 +6519,7 @@ struct BazaarSearchResultsFromDB_Struct {
|
|||||||
CEREAL_NVP(count),
|
CEREAL_NVP(count),
|
||||||
CEREAL_NVP(trader_id),
|
CEREAL_NVP(trader_id),
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
CEREAL_NVP(serial_number),
|
CEREAL_NVP(item_unique_id),
|
||||||
CEREAL_NVP(charges),
|
CEREAL_NVP(charges),
|
||||||
CEREAL_NVP(cost),
|
CEREAL_NVP(cost),
|
||||||
CEREAL_NVP(slot_id),
|
CEREAL_NVP(slot_id),
|
||||||
@@ -6453,7 +6531,6 @@ struct BazaarSearchResultsFromDB_Struct {
|
|||||||
CEREAL_NVP(item_stat),
|
CEREAL_NVP(item_stat),
|
||||||
CEREAL_NVP(stackable),
|
CEREAL_NVP(stackable),
|
||||||
CEREAL_NVP(item_name),
|
CEREAL_NVP(item_name),
|
||||||
CEREAL_NVP(serial_number_RoF),
|
|
||||||
CEREAL_NVP(trader_name)
|
CEREAL_NVP(trader_name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1099,6 +1099,7 @@ namespace PlayerEvent {
|
|||||||
int32 charges;
|
int32 charges;
|
||||||
uint64 total_cost;
|
uint64 total_cost;
|
||||||
uint64 player_money_balance;
|
uint64 player_money_balance;
|
||||||
|
bool offline_purchase;
|
||||||
|
|
||||||
// cereal
|
// cereal
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
@@ -1154,7 +1155,8 @@ namespace PlayerEvent {
|
|||||||
CEREAL_NVP(quantity),
|
CEREAL_NVP(quantity),
|
||||||
CEREAL_NVP(charges),
|
CEREAL_NVP(charges),
|
||||||
CEREAL_NVP(total_cost),
|
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;
|
int32 charges;
|
||||||
uint64 total_cost;
|
uint64 total_cost;
|
||||||
uint64 player_money_balance;
|
uint64 player_money_balance;
|
||||||
|
bool offline_purchase;
|
||||||
|
|
||||||
|
// cereal
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar)
|
void serialize(Archive& ar)
|
||||||
{
|
{
|
||||||
@@ -1229,7 +1233,8 @@ namespace PlayerEvent {
|
|||||||
CEREAL_NVP(quantity),
|
CEREAL_NVP(quantity),
|
||||||
CEREAL_NVP(charges),
|
CEREAL_NVP(charges),
|
||||||
CEREAL_NVP(total_cost),
|
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 {
|
struct ParcelRetrieve {
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
|
std::string item_unique_id;
|
||||||
uint32 augment_1_id;
|
uint32 augment_1_id;
|
||||||
uint32 augment_2_id;
|
uint32 augment_2_id;
|
||||||
uint32 augment_3_id;
|
uint32 augment_3_id;
|
||||||
@@ -1472,6 +1478,7 @@ namespace PlayerEvent {
|
|||||||
{
|
{
|
||||||
ar(
|
ar(
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_unique_id),
|
||||||
CEREAL_NVP(augment_1_id),
|
CEREAL_NVP(augment_1_id),
|
||||||
CEREAL_NVP(augment_2_id),
|
CEREAL_NVP(augment_2_id),
|
||||||
CEREAL_NVP(augment_3_id),
|
CEREAL_NVP(augment_3_id),
|
||||||
@@ -1487,6 +1494,7 @@ namespace PlayerEvent {
|
|||||||
|
|
||||||
struct ParcelSend {
|
struct ParcelSend {
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
|
std::string item_unique_id;
|
||||||
uint32 augment_1_id;
|
uint32 augment_1_id;
|
||||||
uint32 augment_2_id;
|
uint32 augment_2_id;
|
||||||
uint32 augment_3_id;
|
uint32 augment_3_id;
|
||||||
@@ -1536,6 +1544,7 @@ namespace PlayerEvent {
|
|||||||
{
|
{
|
||||||
ar(
|
ar(
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_unique_id),
|
||||||
CEREAL_NVP(augment_1_id),
|
CEREAL_NVP(augment_1_id),
|
||||||
CEREAL_NVP(augment_2_id),
|
CEREAL_NVP(augment_2_id),
|
||||||
CEREAL_NVP(augment_3_id),
|
CEREAL_NVP(augment_3_id),
|
||||||
@@ -1554,6 +1563,7 @@ namespace PlayerEvent {
|
|||||||
struct ParcelDelete {
|
struct ParcelDelete {
|
||||||
uint32 char_id;
|
uint32 char_id;
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
|
std::string item_unique_id;
|
||||||
uint32 augment_1_id;
|
uint32 augment_1_id;
|
||||||
uint32 augment_2_id;
|
uint32 augment_2_id;
|
||||||
uint32 augment_3_id;
|
uint32 augment_3_id;
|
||||||
@@ -1602,6 +1612,7 @@ namespace PlayerEvent {
|
|||||||
{
|
{
|
||||||
ar(
|
ar(
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_unique_id),
|
||||||
CEREAL_NVP(augment_1_id),
|
CEREAL_NVP(augment_1_id),
|
||||||
CEREAL_NVP(augment_2_id),
|
CEREAL_NVP(augment_2_id),
|
||||||
CEREAL_NVP(augment_3_id),
|
CEREAL_NVP(augment_3_id),
|
||||||
|
|||||||
@@ -842,8 +842,10 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg)
|
|||||||
#define GuildMemberBaseQuery \
|
#define GuildMemberBaseQuery \
|
||||||
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
|
"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.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
|
||||||
" g.`banker`, g.`public_note`, g.`alt`, g.`online` " \
|
" 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` "
|
" 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)
|
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into)
|
||||||
{
|
{
|
||||||
//fields from `characer_`
|
//fields from `characer_`
|
||||||
@@ -864,6 +866,7 @@ static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into)
|
|||||||
into.public_note = row[12] ? row[12] : "";
|
into.public_note = row[12] ? row[12] : "";
|
||||||
into.alt = row[13] ? (row[13][0] == '0' ? false : true) : false;
|
into.alt = row[13] ? (row[13][0] == '0' ? false : true) : false;
|
||||||
into.online = row[14] ? (row[14][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
|
//a little sanity checking/cleanup
|
||||||
if (into.guild_id == 0) {
|
if (into.guild_id == 0) {
|
||||||
|
|||||||
+11
-10
@@ -55,16 +55,17 @@ class CharGuildInfo
|
|||||||
uint32 time_last_on;
|
uint32 time_last_on;
|
||||||
uint32 zone_id;
|
uint32 zone_id;
|
||||||
|
|
||||||
//fields from `guild_members`
|
// fields from `guild_members`
|
||||||
uint32 guild_id;
|
uint32 guild_id;
|
||||||
uint8 rank;
|
uint8 rank;
|
||||||
bool tribute_enable;
|
bool tribute_enable;
|
||||||
uint32 total_tribute;
|
uint32 total_tribute;
|
||||||
uint32 last_tribute; //timestamp
|
uint32 last_tribute; // timestamp
|
||||||
bool banker;
|
bool banker;
|
||||||
bool alt;
|
bool alt;
|
||||||
std::string public_note;
|
std::string public_note;
|
||||||
bool online;
|
bool online;
|
||||||
|
bool offline_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
//this object holds guild functionality shared between world and zone.
|
//this object holds guild functionality shared between world and zone.
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int16 EQ::InventoryProfile::PushCursor(const ItemInstance &inst) {
|
int16 EQ::InventoryProfile::PushCursor(const ItemInstance &inst) {
|
||||||
|
if (inst.GetUniqueID().empty()) {
|
||||||
|
inst.CreateUniqueID();
|
||||||
|
}
|
||||||
|
|
||||||
m_cursor.push(inst.Clone());
|
m_cursor.push(inst.Clone());
|
||||||
return invslot::slotCursor;
|
return invslot::slotCursor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ static inline int32 GetNextItemInstSerialNumber()
|
|||||||
//
|
//
|
||||||
// class EQ::ItemInstance
|
// class EQ::ItemInstance
|
||||||
//
|
//
|
||||||
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges)
|
||||||
|
{
|
||||||
if (item) {
|
if (item) {
|
||||||
m_item = new ItemData(*item);
|
m_item = new ItemData(*item);
|
||||||
}
|
}
|
||||||
@@ -77,8 +77,31 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
|||||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
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);
|
m_item = db->GetItem(item_id);
|
||||||
|
|
||||||
if (m_item) {
|
if (m_item) {
|
||||||
@@ -142,9 +165,15 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
|||||||
m_custom_data[iter->first] = iter->second;
|
m_custom_data[iter->first] = iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_SerialNumber = copy.m_SerialNumber;
|
m_SerialNumber = copy.m_SerialNumber;
|
||||||
m_custom_data = copy.m_custom_data;
|
m_custom_data = copy.m_custom_data;
|
||||||
m_timers = copy.m_timers;
|
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_exp = copy.m_exp;
|
||||||
m_evolveLvl = copy.m_evolveLvl;
|
m_evolveLvl = copy.m_evolveLvl;
|
||||||
@@ -1995,3 +2024,11 @@ void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
|
|||||||
|
|
||||||
GetTimers().at("evolve").Disable();
|
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
@@ -23,6 +23,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "common/bodytypes.h"
|
#include "common/bodytypes.h"
|
||||||
#include "common/deity.h"
|
#include "common/deity.h"
|
||||||
#include "common/eq_constants.h"
|
#include "common/eq_constants.h"
|
||||||
@@ -37,7 +41,6 @@
|
|||||||
class ItemParse; // Parses item packets
|
class ItemParse; // Parses item packets
|
||||||
class EvolveInfo; // Stores information about an evolving item family
|
class EvolveInfo; // Stores information about an evolving item family
|
||||||
|
|
||||||
|
|
||||||
// Specifies usage type for item inside EQ::ItemInstance
|
// Specifies usage type for item inside EQ::ItemInstance
|
||||||
enum ItemInstTypes
|
enum ItemInstTypes
|
||||||
{
|
{
|
||||||
@@ -78,6 +81,8 @@ namespace EQ
|
|||||||
|
|
||||||
ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges = 0);
|
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(ItemInstTypes use_type);
|
||||||
|
|
||||||
ItemInstance(const ItemInstance& copy);
|
ItemInstance(const ItemInstance& copy);
|
||||||
@@ -161,6 +166,14 @@ namespace EQ
|
|||||||
|
|
||||||
int16 GetCharges() const { return m_charges; }
|
int16 GetCharges() const { return m_charges; }
|
||||||
void SetCharges(int16 charges) { m_charges = 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; }
|
uint32 GetPrice() const { return m_price; }
|
||||||
void SetPrice(uint32 price) { m_price = 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; }
|
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)); }
|
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; }
|
int32 GetSerialNumber() const { return m_SerialNumber; }
|
||||||
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
|
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; }
|
std::map<std::string, ::Timer>& GetTimers() const { return m_timers; }
|
||||||
void SetTimer(std::string name, uint32 time);
|
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 _cbegin() { return m_contents.cbegin(); }
|
||||||
std::map<uint8, ItemInstance*>::const_iterator _cend() { return m_contents.cend(); }
|
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
|
ItemInstTypes m_use_type{ ItemInstNormal }; // Usage type for item
|
||||||
const ItemData * m_item{nullptr}; // Ptr to item data
|
const ItemData *m_item{ nullptr }; // Ptr to item data
|
||||||
int16 m_charges{0}; // # of charges for chargeable items
|
int16 m_charges{ 0 }; // # of charges for chargeable items
|
||||||
uint32 m_price{0}; // Bazaar /trader price
|
uint32 m_price{ 0 }; // Bazaar /trader price
|
||||||
uint32 m_color{0};
|
uint32 m_color{ 0 };
|
||||||
uint32 m_merchantslot{0};
|
uint32 m_merchantslot{ 0 };
|
||||||
int16 m_currentslot{0};
|
int16 m_currentslot{ 0 };
|
||||||
bool m_attuned{false};
|
bool m_attuned{ false };
|
||||||
int32 m_merchantcount{1};//number avaliable on the merchant, -1=unlimited
|
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.
|
int32 m_SerialNumber{ 0 }; // Unique identifier for this instance of an item. Needed for Bazaar.
|
||||||
uint32 m_exp{0};
|
mutable std::string m_unique_id{}; // unique serial number across all zones/world TESTING March 2025
|
||||||
int8 m_evolveLvl{0};
|
uint32 m_exp{ 0 };
|
||||||
ItemData * m_scaledItem{nullptr};
|
int8 m_evolveLvl{ 0 };
|
||||||
bool m_scaling{false};
|
ItemData *m_scaledItem{ nullptr };
|
||||||
uint32 m_ornamenticon{0};
|
bool m_scaling{ false };
|
||||||
uint32 m_ornamentidfile{0};
|
uint32 m_ornamenticon{ 0 };
|
||||||
uint32 m_new_id_file{0};
|
uint32 m_ornamentidfile{ 0 };
|
||||||
uint32 m_ornament_hero_model{0};
|
uint32 m_new_id_file{ 0 };
|
||||||
uint32 m_recast_timestamp{0};
|
uint32 m_ornament_hero_model{ 0 };
|
||||||
int m_task_delivered_count{0};
|
uint32 m_recast_timestamp{ 0 };
|
||||||
|
int m_task_delivered_count{ 0 };
|
||||||
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{};
|
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{};
|
||||||
|
|
||||||
// Items inside of this item (augs or contents) {};
|
// Items inside of this item (augs or contents) {};
|
||||||
@@ -373,4 +391,48 @@ namespace EQ
|
|||||||
std::map<std::string, std::string> m_custom_data {};
|
std::map<std::string, std::string> m_custom_data {};
|
||||||
mutable std::map<std::string, ::Timer> m_timers {};
|
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
@@ -437,7 +437,6 @@ namespace RoF2
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTradingDetail("Unhandled action <red>[{}]", sub_action);
|
|
||||||
dest->FastQueuePacket(&in);
|
dest->FastQueuePacket(&in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,7 +477,7 @@ namespace RoF2
|
|||||||
|
|
||||||
for (auto i: results) {
|
for (auto i: results) {
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.trader_id); //trader ID
|
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.cost); //cost
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.stackable ? i.charges : i.count); //quantity
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.stackable ? i.charges : i.count); //quantity
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_id); //ID
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_id); //ID
|
||||||
@@ -531,7 +530,6 @@ namespace RoF2
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -620,10 +618,6 @@ namespace RoF2
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading(
|
|
||||||
"(RoF2) Unhandled action <red>[{}]",
|
|
||||||
in->action
|
|
||||||
);
|
|
||||||
dest->QueuePacket(inapp);
|
dest->QueuePacket(inapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -755,7 +749,7 @@ namespace RoF2
|
|||||||
ar(bl);
|
ar(bl);
|
||||||
|
|
||||||
//packet size
|
//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) {
|
for (auto const &b: bl.trade_items) {
|
||||||
packet_size += b.item_name.length() + 1;
|
packet_size += b.item_name.length() + 1;
|
||||||
packet_size += 12;
|
packet_size += 12;
|
||||||
@@ -1843,7 +1837,7 @@ namespace RoF2
|
|||||||
e->zoneinstance = 0;
|
e->zoneinstance = 0;
|
||||||
e->zone_id = htons(emu_e->zone_id);
|
e->zone_id = htons(emu_e->zone_id);
|
||||||
e->unknown_one2 = htonl(1);
|
e->unknown_one2 = htonl(1);
|
||||||
e->unknown04 = 0;
|
e->offline_mode = htonl(emu_e->offline_mode);
|
||||||
|
|
||||||
#undef SlideStructString
|
#undef SlideStructString
|
||||||
#undef PutFieldN
|
#undef PutFieldN
|
||||||
@@ -1860,14 +1854,12 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
SETUP_DIRECT_ENCODE(GuildMemberUpdate_Struct, structs::GuildMemberUpdate_Struct);
|
SETUP_DIRECT_ENCODE(GuildMemberUpdate_Struct, structs::GuildMemberUpdate_Struct);
|
||||||
|
|
||||||
OUT(GuildID);
|
eq->guild_id = emu->GuildID;
|
||||||
memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName));
|
eq->last_seen = emu->LastSeen;
|
||||||
//OUT(ZoneID);
|
eq->instance_id = emu->InstanceID;
|
||||||
//OUT(InstanceID);
|
eq->zone_id = emu->ZoneID;
|
||||||
eq->InstanceID = emu->InstanceID;
|
eq->offline_mode = emu->offline_mode;
|
||||||
eq->ZoneID = emu->ZoneID;
|
memcpy(eq->member_name, emu->MemberName, sizeof(eq->member_name));
|
||||||
OUT(LastSeen);
|
|
||||||
eq->Unknown76 = 0;
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@@ -4113,26 +4105,41 @@ namespace RoF2
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ListTraderItems: {
|
case ListTraderItems: {
|
||||||
ENCODE_LENGTH_EXACT(Trader_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(Trader_Struct, structs::ClickTrader_Struct);
|
|
||||||
LogTrading("(RoF2) action <green>[{}]", action);
|
LogTrading("(RoF2) action <green>[{}]", action);
|
||||||
|
|
||||||
eq->action = structs::RoF2BazaarTraderBuyerActions::ListTraderItems;
|
EQApplicationPacket *in = *p;
|
||||||
std::transform(
|
*p = nullptr;
|
||||||
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)
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
case TraderAck2: {
|
case TraderAck2: {
|
||||||
@@ -4145,7 +4152,7 @@ namespace RoF2
|
|||||||
}
|
}
|
||||||
case PriceUpdate: {
|
case PriceUpdate: {
|
||||||
SETUP_DIRECT_ENCODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
SETUP_DIRECT_ENCODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||||
switch (emu->SubAction) {
|
switch (emu->sub_action) {
|
||||||
case BazaarPriceChange_AddItem: {
|
case BazaarPriceChange_AddItem: {
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||||
OP_Trader,
|
OP_Trader,
|
||||||
@@ -4153,7 +4160,7 @@ namespace RoF2
|
|||||||
);
|
);
|
||||||
|
|
||||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
data->action = emu->Action;
|
data->action = emu->action;
|
||||||
data->sub_action = BazaarPriceChange_AddItem;
|
data->sub_action = BazaarPriceChange_AddItem;
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"(RoF2) PriceUpdate action <green>[{}] AddItem subaction <yellow>[{}]",
|
"(RoF2) PriceUpdate action <green>[{}] AddItem subaction <yellow>[{}]",
|
||||||
@@ -4171,7 +4178,7 @@ namespace RoF2
|
|||||||
);
|
);
|
||||||
|
|
||||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
data->action = emu->Action;
|
data->action = emu->action;
|
||||||
data->sub_action = BazaarPriceChange_RemoveItem;
|
data->sub_action = BazaarPriceChange_RemoveItem;
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"(RoF2) PriceUpdate action <green>[{}] RemoveItem subaction <yellow>[{}]",
|
"(RoF2) PriceUpdate action <green>[{}] RemoveItem subaction <yellow>[{}]",
|
||||||
@@ -4189,7 +4196,7 @@ namespace RoF2
|
|||||||
);
|
);
|
||||||
|
|
||||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
data->action = emu->Action;
|
data->action = emu->action;
|
||||||
data->sub_action = BazaarPriceChange_UpdatePrice;
|
data->sub_action = BazaarPriceChange_UpdatePrice;
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"(RoF2) PriceUpdate action <green>[{}] UpdatePrice subaction <yellow>[{}]",
|
"(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>[{}]",
|
"(RoF2) BuyTraderItem action <green>[{}] item_id <green>[{}] item_sn <green>[{}] buyer <green>[{}]",
|
||||||
action,
|
action,
|
||||||
eq->item_id,
|
eq->item_id,
|
||||||
eq->serial_number,
|
eq->item_unique_id,
|
||||||
eq->buyer_name
|
eq->buyer_name
|
||||||
);
|
);
|
||||||
dest->FastQueuePacket(&in);
|
dest->FastQueuePacket(&in);
|
||||||
@@ -4253,7 +4260,7 @@ namespace RoF2
|
|||||||
OUT_str(buyer_name);
|
OUT_str(buyer_name);
|
||||||
OUT_str(seller_name);
|
OUT_str(seller_name);
|
||||||
OUT_str(item_name);
|
OUT_str(item_name);
|
||||||
OUT_str(serial_number);
|
OUT_str(item_unique_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@@ -4263,15 +4270,13 @@ namespace RoF2
|
|||||||
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"(RoF2) trader_id <green>[{}] item_id <green>[{}]",
|
"(RoF2) trader_id <green>[{}] item_unique_id <green>[{}]",
|
||||||
emu->trader_id,
|
emu->trader_id,
|
||||||
emu->item_id
|
emu->item_unique_id
|
||||||
);
|
);
|
||||||
|
|
||||||
eq->TraderID = emu->trader_id;
|
eq->trader_id = emu->trader_id;
|
||||||
auto serial = fmt::format("{:016}\n", emu->item_id);
|
strn0cpy(eq->item_unique_id, emu->item_unique_id, sizeof(eq->item_unique_id));
|
||||||
strn0cpy(eq->SerialNumber, serial.c_str(), sizeof(eq->SerialNumber));
|
|
||||||
LogTrading("(RoF2) TraderID <green>[{}], SerialNumber: <green>[{}]", emu->trader_id, emu->item_id);
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@@ -4318,13 +4323,12 @@ namespace RoF2
|
|||||||
OUT_str(buyer_name);
|
OUT_str(buyer_name);
|
||||||
OUT_str(seller_name);
|
OUT_str(seller_name);
|
||||||
OUT_str(item_name);
|
OUT_str(item_name);
|
||||||
OUT_str(serial_number);
|
OUT_str(item_unique_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
@@ -4460,6 +4464,7 @@ namespace RoF2
|
|||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
char *InBuffer = (char *)in->pBuffer;
|
char *InBuffer = (char *)in->pBuffer;
|
||||||
|
std::vector<uint32> p_ids { 0x430, 0x420 };
|
||||||
|
|
||||||
WhoAllReturnStruct *wars = (WhoAllReturnStruct*)InBuffer;
|
WhoAllReturnStruct *wars = (WhoAllReturnStruct*)InBuffer;
|
||||||
|
|
||||||
@@ -4485,8 +4490,9 @@ namespace RoF2
|
|||||||
x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x);
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x);
|
||||||
|
|
||||||
InBuffer += 4;
|
x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
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);
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0xffffffff);
|
||||||
|
|
||||||
char Name[64];
|
char Name[64];
|
||||||
@@ -4722,6 +4728,10 @@ namespace RoF2
|
|||||||
OtherData = OtherData | 0x01;
|
OtherData = OtherData | 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (emu->offline) {
|
||||||
|
OtherData = OtherData | 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||||
// float EmitterScalingRadius
|
// float EmitterScalingRadius
|
||||||
|
|
||||||
@@ -5092,7 +5102,6 @@ namespace RoF2
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
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) {
|
switch (action) {
|
||||||
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
||||||
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
|
||||||
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
|
|
||||||
|
|
||||||
emu->action = TraderOn;
|
unsigned char *eq_buffer = __packet->pBuffer;
|
||||||
std::copy_n(eq->item_cost, RoF2::invtype::BAZAAR_SIZE, emu->item_cost);
|
auto eq = (RoF2::structs::BeginTrader_Struct *) eq_buffer;
|
||||||
std::transform(
|
|
||||||
std::begin(eq->items),
|
ClickTraderNew_Struct out{};
|
||||||
std::end(eq->items),
|
out.action = TraderOn;
|
||||||
std::begin(emu->serial_number),
|
for (auto i = 0; i < RoF2::invtype::BAZAAR_SIZE; i++) {
|
||||||
[&](const structs::TraderItemSerial_Struct x) {
|
if (eq->item_cost[i] == 0) {
|
||||||
return Strings::ToUnsignedBigInt(x.serial_number,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;
|
break;
|
||||||
}
|
}
|
||||||
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
||||||
@@ -6187,18 +6210,14 @@ namespace RoF2
|
|||||||
SETUP_DIRECT_DECODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
SETUP_DIRECT_DECODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||||
LogTrading("(RoF2) PriceUpdate action <green>[{}]", action);
|
LogTrading("(RoF2) PriceUpdate action <green>[{}]", action);
|
||||||
|
|
||||||
emu->Action = PriceUpdate;
|
emu->action = PriceUpdate;
|
||||||
emu->SerialNumber = Strings::ToUnsignedBigInt(eq->serial_number, 0);
|
strn0cpy(emu->item_unique_id, eq->item_unique_id, sizeof(emu->item_unique_id));
|
||||||
if (emu->SerialNumber == 0) {
|
emu->new_price = eq->new_price;
|
||||||
LogTrading("(RoF2) Price change with invalid serial number <red>[{}]", eq->serial_number);
|
|
||||||
}
|
|
||||||
emu->NewPrice = eq->new_price;
|
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6282,21 +6301,12 @@ namespace RoF2
|
|||||||
IN(item_id);
|
IN(item_id);
|
||||||
IN(trader_id);
|
IN(trader_id);
|
||||||
emu->action = BazaarInspect;
|
emu->action = BazaarInspect;
|
||||||
emu->serial_number = Strings::ToUnsignedInt(eq->serial_number, 0);
|
strn0cpy(emu->item_unique_id, eq->item_unique_id, sizeof(emu->item_unique_id));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogTrading("(RoF2) BazaarInspect action <green>[{}] item_id <green>[{}] serial_number <green>[{}]",
|
LogTrading("(RoF2) BazaarInspect action <green>[{}] item_id <green>[{}] serial_number <green>[{}]",
|
||||||
action,
|
action,
|
||||||
eq->item_id,
|
eq->item_id,
|
||||||
eq->serial_number
|
eq->item_unique_id
|
||||||
);
|
);
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
@@ -6333,13 +6343,12 @@ namespace RoF2
|
|||||||
IN_str(buyer_name);
|
IN_str(buyer_name);
|
||||||
IN_str(seller_name);
|
IN_str(seller_name);
|
||||||
IN_str(item_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();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -6444,7 +6453,15 @@ namespace RoF2
|
|||||||
RoF2::structs::ItemSerializationHeader hdr;
|
RoF2::structs::ItemSerializationHeader hdr;
|
||||||
|
|
||||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
//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;
|
hdr.stacksize = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -306,6 +306,7 @@ namespace RoF2
|
|||||||
const size_t SAY_LINK_BODY_SIZE = 56;
|
const size_t SAY_LINK_BODY_SIZE = 56;
|
||||||
const uint32 MAX_GUILD_ID = 50000;
|
const uint32 MAX_GUILD_ID = 50000;
|
||||||
const uint32 MAX_BAZAAR_TRADERS = 600;
|
const uint32 MAX_BAZAAR_TRADERS = 600;
|
||||||
|
const uint64 MAX_BAZAAR_TRANSACTION = 3276700000000; //3276700000000
|
||||||
|
|
||||||
} /*constants*/
|
} /*constants*/
|
||||||
|
|
||||||
|
|||||||
@@ -3317,7 +3317,7 @@ struct BazaarInspect_Struct {
|
|||||||
uint32 action;
|
uint32 action;
|
||||||
uint32 unknown_004;
|
uint32 unknown_004;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
char serial_number[17];
|
char item_unique_id[17];
|
||||||
char unknown_029[3];
|
char unknown_029[3];
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
uint32 unknown_036;
|
uint32 unknown_036;
|
||||||
@@ -3560,19 +3560,21 @@ struct WhoAllPlayerPart4 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemSerial_Struct {
|
struct TraderItemSerial_Struct {
|
||||||
char serial_number[17];
|
char item_unique_id[17];
|
||||||
uint8 unknown_018;
|
uint8 unknown_018;
|
||||||
|
|
||||||
void operator=(uint32 a) {
|
TraderItemSerial_Struct& operator=(const char* a) {
|
||||||
auto _tmp = fmt::format("{:016}", a);
|
strn0cpy(this->item_unique_id, a, sizeof(this->item_unique_id));
|
||||||
strn0cpy(this->serial_number, _tmp.c_str(), sizeof(this->serial_number));
|
unknown_018 = 0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BeginTrader_Struct {
|
struct BeginTrader_Struct {
|
||||||
/*0000*/ uint32 action;
|
/*0000*/ uint32 action;
|
||||||
/*0004*/ TraderItemSerial_Struct items[200];
|
/*0004*/ TraderItemSerial_Struct item_unique_ids[RoF2::invtype::BAZAAR_SIZE];
|
||||||
/*3604*/ uint32 item_cost[200];
|
/*3604*/ uint32 item_cost[RoF2::invtype::BAZAAR_SIZE];
|
||||||
/*4404*/
|
/*4404*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3598,11 +3600,11 @@ struct BazaarWindowRemoveTrader_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderPriceUpdate_Struct {
|
struct TraderPriceUpdate_Struct {
|
||||||
uint32 action;
|
/*000*/ uint32 action;
|
||||||
char serial_number[17];
|
/*004*/ char item_unique_id[17];
|
||||||
char unknown_021[3];
|
/*021*/ char unknown_021[3];
|
||||||
uint32 unknown_024;
|
/*024*/ uint32 unknown_024;
|
||||||
uint32 new_price;
|
/*028*/ uint32 new_price;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct {
|
struct Trader_ShowItems_Struct {
|
||||||
@@ -3620,22 +3622,22 @@ struct TraderStatus_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 method;
|
/*004*/ uint32 method;
|
||||||
/*008*/ uint32 sub_action;
|
/*008*/ uint32 sub_action;
|
||||||
/*012*/ uint32 unknown_012;
|
/*012*/ uint32 unknown_012;
|
||||||
/*016*/ uint32 trader_id;
|
/*016*/ uint32 trader_id;
|
||||||
/*020*/ char buyer_name[64];
|
/*020*/ char buyer_name[64];
|
||||||
/*084*/ char seller_name[64];
|
/*084*/ char seller_name[64];
|
||||||
/*148*/ char unknown_148[32];
|
/*148*/ char unknown_148[32];
|
||||||
/*180*/ char item_name[64];
|
/*180*/ char item_name[64];
|
||||||
/*244*/ char serial_number[17];
|
/*244*/ char item_unique_id[17];
|
||||||
/*261*/ char unknown_261[3];
|
/*261*/ char unknown_261[3];
|
||||||
/*264*/ uint32 item_id;
|
/*264*/ uint32 item_id;
|
||||||
/*268*/ uint32 price;
|
/*268*/ uint32 price;
|
||||||
/*272*/ uint32 already_sold;
|
/*272*/ uint32 already_sold;
|
||||||
/*276*/ uint32 unknown_276;
|
/*276*/ uint32 unknown_276;
|
||||||
/*280*/ uint32 quantity;
|
/*280*/ uint32 quantity;
|
||||||
/*284*/
|
/*284*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3655,10 +3657,10 @@ struct MoneyUpdate_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderDelItem_Struct{
|
struct TraderDelItem_Struct{
|
||||||
/*000*/ uint32 Unknown000;
|
/*000*/ uint32 unknown_000;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 trader_id;
|
||||||
/*008*/ char SerialNumber[17];
|
/*008*/ char item_unique_id[17];
|
||||||
/*024*/ uint32 Unknown012;
|
/*025*/ uint32 unknown_025;
|
||||||
/*028*/
|
/*028*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3685,22 +3687,22 @@ struct SimpleMessage_Struct{
|
|||||||
// Size: 52 + strings
|
// Size: 52 + strings
|
||||||
// Other than the strings, all of this packet is network byte order (reverse from normal)
|
// Other than the strings, all of this packet is network byte order (reverse from normal)
|
||||||
struct GuildMemberEntry_Struct {
|
struct GuildMemberEntry_Struct {
|
||||||
char name[1]; // variable length
|
char name[1]; // variable length
|
||||||
uint32 level;
|
uint32 level;
|
||||||
uint32 banker; // 1=yes, 0=no
|
uint32 banker; // 1=yes, 0=no
|
||||||
uint32 class_;
|
uint32 class_;
|
||||||
uint32 rank;
|
uint32 rank;
|
||||||
uint32 time_last_on;
|
uint32 time_last_on;
|
||||||
uint32 tribute_enable;
|
uint32 tribute_enable;
|
||||||
uint32 unknown01; // Seen 0
|
uint32 unknown01; // Seen 0
|
||||||
uint32 total_tribute; // total guild tribute donated, network byte order
|
uint32 total_tribute; // total guild tribute donated, network byte order
|
||||||
uint32 last_tribute; // unix timestamp
|
uint32 last_tribute; // unix timestamp
|
||||||
uint32 unknown_one; // unknown, set to 1
|
uint32 unknown_one; // unknown, set to 1
|
||||||
char public_note[1]; // variable length.
|
char public_note[1]; // variable length.
|
||||||
uint16 zoneinstance; // Seen 0s or -1 in RoF2
|
uint16 zoneinstance; // Seen 0s or -1 in RoF2
|
||||||
uint16 zone_id; // Seen 0s or -1 in RoF2
|
uint16 zone_id; // Seen 0s or -1 in RoF2
|
||||||
uint32 unknown_one2; // unknown, set to 1
|
uint32 unknown_one2; // unknown, set to 1
|
||||||
uint32 unknown04; // Seen 0
|
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.
|
//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 {
|
struct GuildMemberUpdate_Struct {
|
||||||
/*00*/ uint32 GuildID;
|
/*00*/ uint32 guild_id;
|
||||||
/*04*/ char MemberName[64];
|
/*04*/ char member_name[64];
|
||||||
/*68*/ uint16 ZoneID;
|
/*68*/ uint16 zone_id;
|
||||||
/*70*/ uint16 InstanceID; //speculated
|
/*70*/ uint16 instance_id; //speculated
|
||||||
/*72*/ uint32 LastSeen; //unix timestamp
|
/*72*/ uint32 last_seen; //unix timestamp
|
||||||
/*76*/ uint32 Unknown76;
|
/*76*/ uint32 offline_mode;
|
||||||
/*80*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GuildMemberLevelUpdate_Struct {
|
struct GuildMemberLevelUpdate_Struct {
|
||||||
|
|||||||
@@ -226,7 +226,6 @@ namespace Titanium
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
||||||
bufptr += 4;
|
bufptr += 4;
|
||||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
|
||||||
bufptr += 4;
|
bufptr += 4;
|
||||||
if (row->stackable) {
|
if (row->stackable) {
|
||||||
strn0cpy(
|
strn0cpy(
|
||||||
@@ -2527,7 +2526,6 @@ namespace Titanium
|
|||||||
|
|
||||||
IN(action);
|
IN(action);
|
||||||
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||||
IN(serial_number);
|
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -335,7 +335,6 @@ namespace UF
|
|||||||
bufptr += 64;
|
bufptr += 64;
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
|
||||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
|
||||||
bufptr += 4;
|
bufptr += 4;
|
||||||
if (row->stackable) {
|
if (row->stackable) {
|
||||||
strn0cpy(
|
strn0cpy(
|
||||||
@@ -3615,7 +3614,6 @@ namespace UF
|
|||||||
|
|
||||||
IN(action);
|
IN(action);
|
||||||
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||||
IN(serial_number);
|
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -107,4 +107,43 @@ public:
|
|||||||
|
|
||||||
return AccountRepository::UpdateOne(db, e);
|
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;
|
uint8_t rulesflag;
|
||||||
time_t suspendeduntil;
|
time_t suspendeduntil;
|
||||||
uint32_t time_creation;
|
uint32_t time_creation;
|
||||||
|
uint8_t offline;
|
||||||
std::string ban_reason;
|
std::string ban_reason;
|
||||||
std::string suspend_reason;
|
std::string suspend_reason;
|
||||||
std::string crc_eqgame;
|
std::string crc_eqgame;
|
||||||
@@ -74,6 +75,7 @@ public:
|
|||||||
"rulesflag",
|
"rulesflag",
|
||||||
"suspendeduntil",
|
"suspendeduntil",
|
||||||
"time_creation",
|
"time_creation",
|
||||||
|
"offline",
|
||||||
"ban_reason",
|
"ban_reason",
|
||||||
"suspend_reason",
|
"suspend_reason",
|
||||||
"crc_eqgame",
|
"crc_eqgame",
|
||||||
@@ -105,6 +107,7 @@ public:
|
|||||||
"rulesflag",
|
"rulesflag",
|
||||||
"UNIX_TIMESTAMP(suspendeduntil)",
|
"UNIX_TIMESTAMP(suspendeduntil)",
|
||||||
"time_creation",
|
"time_creation",
|
||||||
|
"offline",
|
||||||
"ban_reason",
|
"ban_reason",
|
||||||
"suspend_reason",
|
"suspend_reason",
|
||||||
"crc_eqgame",
|
"crc_eqgame",
|
||||||
@@ -170,6 +173,7 @@ public:
|
|||||||
e.rulesflag = 0;
|
e.rulesflag = 0;
|
||||||
e.suspendeduntil = 0;
|
e.suspendeduntil = 0;
|
||||||
e.time_creation = 0;
|
e.time_creation = 0;
|
||||||
|
e.offline = 0;
|
||||||
e.ban_reason = "";
|
e.ban_reason = "";
|
||||||
e.suspend_reason = "";
|
e.suspend_reason = "";
|
||||||
e.crc_eqgame = "";
|
e.crc_eqgame = "";
|
||||||
@@ -231,11 +235,12 @@ public:
|
|||||||
e.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
|
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.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.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||||
e.ban_reason = row[20] ? row[20] : "";
|
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
e.suspend_reason = row[21] ? row[21] : "";
|
e.ban_reason = row[21] ? row[21] : "";
|
||||||
e.crc_eqgame = row[22] ? row[22] : "";
|
e.suspend_reason = row[22] ? row[22] : "";
|
||||||
e.crc_skillcaps = row[23] ? row[23] : "";
|
e.crc_eqgame = row[23] ? row[23] : "";
|
||||||
e.crc_basedata = row[24] ? row[24] : "";
|
e.crc_skillcaps = row[24] ? row[24] : "";
|
||||||
|
e.crc_basedata = row[25] ? row[25] : "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -288,11 +293,12 @@ public:
|
|||||||
v.push_back(columns[17] + " = " + std::to_string(e.rulesflag));
|
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[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[19] + " = " + std::to_string(e.time_creation));
|
||||||
v.push_back(columns[20] + " = '" + Strings::Escape(e.ban_reason) + "'");
|
v.push_back(columns[20] + " = " + std::to_string(e.offline));
|
||||||
v.push_back(columns[21] + " = '" + Strings::Escape(e.suspend_reason) + "'");
|
v.push_back(columns[21] + " = '" + Strings::Escape(e.ban_reason) + "'");
|
||||||
v.push_back(columns[22] + " = '" + Strings::Escape(e.crc_eqgame) + "'");
|
v.push_back(columns[22] + " = '" + Strings::Escape(e.suspend_reason) + "'");
|
||||||
v.push_back(columns[23] + " = '" + Strings::Escape(e.crc_skillcaps) + "'");
|
v.push_back(columns[23] + " = '" + Strings::Escape(e.crc_eqgame) + "'");
|
||||||
v.push_back(columns[24] + " = '" + Strings::Escape(e.crc_basedata) + "'");
|
v.push_back(columns[24] + " = '" + Strings::Escape(e.crc_skillcaps) + "'");
|
||||||
|
v.push_back(columns[25] + " = '" + Strings::Escape(e.crc_basedata) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -334,6 +340,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.rulesflag));
|
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("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.time_creation));
|
||||||
|
v.push_back(std::to_string(e.offline));
|
||||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
||||||
@@ -388,6 +395,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.rulesflag));
|
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("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.time_creation));
|
||||||
|
v.push_back(std::to_string(e.offline));
|
||||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
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.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||||
e.suspendeduntil = strtoll(row[18] ? row[18] : "-1", nullptr, 10);
|
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.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||||
e.ban_reason = row[20] ? row[20] : "";
|
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
e.suspend_reason = row[21] ? row[21] : "";
|
e.ban_reason = row[21] ? row[21] : "";
|
||||||
e.crc_eqgame = row[22] ? row[22] : "";
|
e.suspend_reason = row[22] ? row[22] : "";
|
||||||
e.crc_skillcaps = row[23] ? row[23] : "";
|
e.crc_eqgame = row[23] ? row[23] : "";
|
||||||
e.crc_basedata = row[24] ? row[24] : "";
|
e.crc_skillcaps = row[24] ? row[24] : "";
|
||||||
|
e.crc_basedata = row[25] ? row[25] : "";
|
||||||
|
|
||||||
all_entries.push_back(e);
|
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.rulesflag = row[17] ? static_cast<uint8_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||||
e.suspendeduntil = strtoll(row[18] ? row[18] : "-1", nullptr, 10);
|
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.time_creation = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||||
e.ban_reason = row[20] ? row[20] : "";
|
e.offline = row[20] ? static_cast<uint8_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
e.suspend_reason = row[21] ? row[21] : "";
|
e.ban_reason = row[21] ? row[21] : "";
|
||||||
e.crc_eqgame = row[22] ? row[22] : "";
|
e.suspend_reason = row[22] ? row[22] : "";
|
||||||
e.crc_skillcaps = row[23] ? row[23] : "";
|
e.crc_eqgame = row[23] ? row[23] : "";
|
||||||
e.crc_basedata = row[24] ? row[24] : "";
|
e.crc_skillcaps = row[24] ? row[24] : "";
|
||||||
|
e.crc_basedata = row[25] ? row[25] : "";
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -594,6 +604,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.rulesflag));
|
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("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.time_creation));
|
||||||
|
v.push_back(std::to_string(e.offline));
|
||||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
||||||
@@ -641,6 +652,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.rulesflag));
|
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("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.time_creation));
|
||||||
|
v.push_back(std::to_string(e.offline));
|
||||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
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 {
|
class BaseCharacterParcelsContainersRepository {
|
||||||
public:
|
public:
|
||||||
struct CharacterParcelsContainers {
|
struct CharacterParcelsContainers {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t parcels_id;
|
uint32_t parcels_id;
|
||||||
uint32_t slot_id;
|
uint32_t slot_id;
|
||||||
uint32_t item_id;
|
uint32_t item_id;
|
||||||
uint32_t aug_slot_1;
|
std::string item_unique_id;
|
||||||
uint32_t aug_slot_2;
|
uint32_t aug_slot_1;
|
||||||
uint32_t aug_slot_3;
|
uint32_t aug_slot_2;
|
||||||
uint32_t aug_slot_4;
|
uint32_t aug_slot_3;
|
||||||
uint32_t aug_slot_5;
|
uint32_t aug_slot_4;
|
||||||
uint32_t aug_slot_6;
|
uint32_t aug_slot_5;
|
||||||
uint32_t quantity;
|
uint32_t aug_slot_6;
|
||||||
uint32_t evolve_amount;
|
uint32_t quantity;
|
||||||
|
uint32_t evolve_amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -45,6 +46,7 @@ public:
|
|||||||
"parcels_id",
|
"parcels_id",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
|
"item_unique_id",
|
||||||
"aug_slot_1",
|
"aug_slot_1",
|
||||||
"aug_slot_2",
|
"aug_slot_2",
|
||||||
"aug_slot_3",
|
"aug_slot_3",
|
||||||
@@ -63,6 +65,7 @@ public:
|
|||||||
"parcels_id",
|
"parcels_id",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
|
"item_unique_id",
|
||||||
"aug_slot_1",
|
"aug_slot_1",
|
||||||
"aug_slot_2",
|
"aug_slot_2",
|
||||||
"aug_slot_3",
|
"aug_slot_3",
|
||||||
@@ -111,18 +114,19 @@ public:
|
|||||||
{
|
{
|
||||||
CharacterParcelsContainers e{};
|
CharacterParcelsContainers e{};
|
||||||
|
|
||||||
e.id = 0;
|
e.id = 0;
|
||||||
e.parcels_id = 0;
|
e.parcels_id = 0;
|
||||||
e.slot_id = 0;
|
e.slot_id = 0;
|
||||||
e.item_id = 0;
|
e.item_id = 0;
|
||||||
e.aug_slot_1 = 0;
|
e.item_unique_id = "";
|
||||||
e.aug_slot_2 = 0;
|
e.aug_slot_1 = 0;
|
||||||
e.aug_slot_3 = 0;
|
e.aug_slot_2 = 0;
|
||||||
e.aug_slot_4 = 0;
|
e.aug_slot_3 = 0;
|
||||||
e.aug_slot_5 = 0;
|
e.aug_slot_4 = 0;
|
||||||
e.aug_slot_6 = 0;
|
e.aug_slot_5 = 0;
|
||||||
e.quantity = 0;
|
e.aug_slot_6 = 0;
|
||||||
e.evolve_amount = 0;
|
e.quantity = 0;
|
||||||
|
e.evolve_amount = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -159,18 +163,19 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
CharacterParcelsContainers e{};
|
CharacterParcelsContainers e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], 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.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.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_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.item_unique_id = row[4] ? row[4] : "";
|
||||||
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_1 = 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_2 = 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_3 = 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_4 = 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.aug_slot_5 = 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.aug_slot_6 = 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.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;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -207,14 +212,15 @@ public:
|
|||||||
v.push_back(columns[1] + " = " + std::to_string(e.parcels_id));
|
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[2] + " = " + std::to_string(e.slot_id));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.item_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[4] + " = '" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_2));
|
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_1));
|
||||||
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_3));
|
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_2));
|
||||||
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_4));
|
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_3));
|
||||||
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5));
|
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_4));
|
||||||
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6));
|
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_5));
|
||||||
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
|
v.push_back(columns[10] + " = " + std::to_string(e.aug_slot_6));
|
||||||
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -240,6 +246,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.parcels_id));
|
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.slot_id));
|
||||||
v.push_back(std::to_string(e.item_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_1));
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
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_3));
|
||||||
@@ -281,6 +288,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.parcels_id));
|
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.slot_id));
|
||||||
v.push_back(std::to_string(e.item_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_1));
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
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_3));
|
||||||
@@ -322,18 +330,19 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
CharacterParcelsContainers e{};
|
CharacterParcelsContainers e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], 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.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.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_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.item_unique_id = row[4] ? row[4] : "";
|
||||||
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_1 = 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_2 = 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_3 = 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_4 = 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.aug_slot_5 = 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.aug_slot_6 = 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.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);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -358,18 +367,19 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
CharacterParcelsContainers e{};
|
CharacterParcelsContainers e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], 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.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.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_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.item_unique_id = row[4] ? row[4] : "";
|
||||||
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_1 = 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_2 = 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_3 = 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_4 = 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.aug_slot_5 = 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.aug_slot_6 = 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.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);
|
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.parcels_id));
|
||||||
v.push_back(std::to_string(e.slot_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.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_1));
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
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_3));
|
||||||
@@ -482,6 +493,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.parcels_id));
|
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.slot_id));
|
||||||
v.push_back(std::to_string(e.item_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_1));
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
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_3));
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
uint32_t aug_slot_4;
|
uint32_t aug_slot_4;
|
||||||
uint32_t aug_slot_5;
|
uint32_t aug_slot_5;
|
||||||
uint32_t aug_slot_6;
|
uint32_t aug_slot_6;
|
||||||
|
std::string item_unique_id;
|
||||||
uint32_t slot_id;
|
uint32_t slot_id;
|
||||||
uint32_t quantity;
|
uint32_t quantity;
|
||||||
uint32_t evolve_amount;
|
uint32_t evolve_amount;
|
||||||
@@ -53,6 +54,7 @@ public:
|
|||||||
"aug_slot_4",
|
"aug_slot_4",
|
||||||
"aug_slot_5",
|
"aug_slot_5",
|
||||||
"aug_slot_6",
|
"aug_slot_6",
|
||||||
|
"item_unique_id",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
"quantity",
|
"quantity",
|
||||||
"evolve_amount",
|
"evolve_amount",
|
||||||
@@ -74,6 +76,7 @@ public:
|
|||||||
"aug_slot_4",
|
"aug_slot_4",
|
||||||
"aug_slot_5",
|
"aug_slot_5",
|
||||||
"aug_slot_6",
|
"aug_slot_6",
|
||||||
|
"item_unique_id",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
"quantity",
|
"quantity",
|
||||||
"evolve_amount",
|
"evolve_amount",
|
||||||
@@ -129,6 +132,7 @@ public:
|
|||||||
e.aug_slot_4 = 0;
|
e.aug_slot_4 = 0;
|
||||||
e.aug_slot_5 = 0;
|
e.aug_slot_5 = 0;
|
||||||
e.aug_slot_6 = 0;
|
e.aug_slot_6 = 0;
|
||||||
|
e.item_unique_id = "";
|
||||||
e.slot_id = 0;
|
e.slot_id = 0;
|
||||||
e.quantity = 0;
|
e.quantity = 0;
|
||||||
e.evolve_amount = 0;
|
e.evolve_amount = 0;
|
||||||
@@ -171,21 +175,22 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
CharacterParcels e{};
|
CharacterParcels e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.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.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_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_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_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_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_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.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.item_unique_id = row[9] ? row[9] : "";
|
||||||
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
|
e.slot_id = 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.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.from_name = row[12] ? row[12] : "";
|
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.note = row[13] ? row[13] : "";
|
e.from_name = row[13] ? row[13] : "";
|
||||||
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
e.note = row[14] ? row[14] : "";
|
||||||
|
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -227,12 +232,13 @@ public:
|
|||||||
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
|
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[7] + " = " + std::to_string(e.aug_slot_5));
|
||||||
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
|
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[9] + " = '" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
|
v.push_back(columns[10] + " = " + std::to_string(e.slot_id));
|
||||||
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
|
v.push_back(columns[11] + " = " + std::to_string(e.quantity));
|
||||||
v.push_back(columns[12] + " = '" + Strings::Escape(e.from_name) + "'");
|
v.push_back(columns[12] + " = " + std::to_string(e.evolve_amount));
|
||||||
v.push_back(columns[13] + " = '" + Strings::Escape(e.note) + "'");
|
v.push_back(columns[13] + " = '" + Strings::Escape(e.from_name) + "'");
|
||||||
v.push_back(columns[14] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
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_4));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
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.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.slot_id));
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.quantity));
|
||||||
v.push_back(std::to_string(e.evolve_amount));
|
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_4));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
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.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.slot_id));
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.quantity));
|
||||||
v.push_back(std::to_string(e.evolve_amount));
|
v.push_back(std::to_string(e.evolve_amount));
|
||||||
@@ -346,21 +354,22 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
CharacterParcels e{};
|
CharacterParcels e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.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.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_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_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_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_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_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.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.item_unique_id = row[9] ? row[9] : "";
|
||||||
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
|
e.slot_id = 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.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.from_name = row[12] ? row[12] : "";
|
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.note = row[13] ? row[13] : "";
|
e.from_name = row[13] ? row[13] : "";
|
||||||
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
e.note = row[14] ? row[14] : "";
|
||||||
|
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -385,21 +394,22 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
CharacterParcels e{};
|
CharacterParcels e{};
|
||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.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.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_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_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_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_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_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.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.item_unique_id = row[9] ? row[9] : "";
|
||||||
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
|
e.slot_id = 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.quantity = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.from_name = row[12] ? row[12] : "";
|
e.evolve_amount = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.note = row[13] ? row[13] : "";
|
e.from_name = row[13] ? row[13] : "";
|
||||||
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
e.note = row[14] ? row[14] : "";
|
||||||
|
e.sent_date = strtoll(row[15] ? row[15] : "-1", nullptr, 10);
|
||||||
|
|
||||||
all_entries.push_back(e);
|
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_4));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
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.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.slot_id));
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.quantity));
|
||||||
v.push_back(std::to_string(e.evolve_amount));
|
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_4));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
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.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.slot_id));
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.quantity));
|
||||||
v.push_back(std::to_string(e.evolve_amount));
|
v.push_back(std::to_string(e.evolve_amount));
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
uint32_t ornament_icon;
|
uint32_t ornament_icon;
|
||||||
uint32_t ornament_idfile;
|
uint32_t ornament_idfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
uint64_t guid;
|
std::string item_unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
"ornament_icon",
|
"ornament_icon",
|
||||||
"ornament_idfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ public:
|
|||||||
"ornament_icon",
|
"ornament_icon",
|
||||||
"ornament_idfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ public:
|
|||||||
e.ornament_icon = 0;
|
e.ornament_icon = 0;
|
||||||
e.ornament_idfile = 0;
|
e.ornament_idfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
e.guid = 0;
|
e.item_unique_id = "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ public:
|
|||||||
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
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_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.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;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ public:
|
|||||||
v.push_back(columns[13] + " = " + std::to_string(e.ornament_icon));
|
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[14] + " = " + std::to_string(e.ornament_idfile));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -283,7 +283,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -329,7 +329,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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) + ")");
|
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_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_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.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);
|
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_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_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.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);
|
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_icon));
|
||||||
v.push_back(std::to_string(e.ornament_idfile));
|
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.ornament_hero_model));
|
||||||
v.push_back(std::to_string(e.guid));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -550,7 +550,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,23 +20,23 @@ class BaseInventorySnapshotsRepository {
|
|||||||
public:
|
public:
|
||||||
struct InventorySnapshots {
|
struct InventorySnapshots {
|
||||||
uint32_t time_index;
|
uint32_t time_index;
|
||||||
uint32_t charid;
|
uint32_t character_id;
|
||||||
uint32_t slotid;
|
uint32_t slot_id;
|
||||||
uint32_t itemid;
|
uint32_t item_id;
|
||||||
uint16_t charges;
|
uint16_t charges;
|
||||||
uint32_t color;
|
uint32_t color;
|
||||||
uint32_t augslot1;
|
uint32_t augment_one;
|
||||||
uint32_t augslot2;
|
uint32_t augment_two;
|
||||||
uint32_t augslot3;
|
uint32_t augment_three;
|
||||||
uint32_t augslot4;
|
uint32_t augment_four;
|
||||||
uint32_t augslot5;
|
uint32_t augment_five;
|
||||||
int32_t augslot6;
|
int32_t augment_six;
|
||||||
uint8_t instnodrop;
|
uint8_t instnodrop;
|
||||||
std::string custom_data;
|
std::string custom_data;
|
||||||
uint32_t ornamenticon;
|
uint32_t ornament_icon;
|
||||||
uint32_t ornamentidfile;
|
uint32_t ornament_idfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
uint64_t guid;
|
std::string item_unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -48,23 +48,23 @@ public:
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"time_index",
|
"time_index",
|
||||||
"charid",
|
"character_id",
|
||||||
"slotid",
|
"slot_id",
|
||||||
"itemid",
|
"item_id",
|
||||||
"charges",
|
"charges",
|
||||||
"color",
|
"color",
|
||||||
"augslot1",
|
"augment_one",
|
||||||
"augslot2",
|
"augment_two",
|
||||||
"augslot3",
|
"augment_three",
|
||||||
"augslot4",
|
"augment_four",
|
||||||
"augslot5",
|
"augment_five",
|
||||||
"augslot6",
|
"augment_six",
|
||||||
"instnodrop",
|
"instnodrop",
|
||||||
"custom_data",
|
"custom_data",
|
||||||
"ornamenticon",
|
"ornament_icon",
|
||||||
"ornamentidfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,23 +72,23 @@ public:
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"time_index",
|
"time_index",
|
||||||
"charid",
|
"character_id",
|
||||||
"slotid",
|
"slot_id",
|
||||||
"itemid",
|
"item_id",
|
||||||
"charges",
|
"charges",
|
||||||
"color",
|
"color",
|
||||||
"augslot1",
|
"augment_one",
|
||||||
"augslot2",
|
"augment_two",
|
||||||
"augslot3",
|
"augment_three",
|
||||||
"augslot4",
|
"augment_four",
|
||||||
"augslot5",
|
"augment_five",
|
||||||
"augslot6",
|
"augment_six",
|
||||||
"instnodrop",
|
"instnodrop",
|
||||||
"custom_data",
|
"custom_data",
|
||||||
"ornamenticon",
|
"ornament_icon",
|
||||||
"ornamentidfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,23 +130,23 @@ public:
|
|||||||
InventorySnapshots e{};
|
InventorySnapshots e{};
|
||||||
|
|
||||||
e.time_index = 0;
|
e.time_index = 0;
|
||||||
e.charid = 0;
|
e.character_id = 0;
|
||||||
e.slotid = 0;
|
e.slot_id = 0;
|
||||||
e.itemid = 0;
|
e.item_id = 0;
|
||||||
e.charges = 0;
|
e.charges = 0;
|
||||||
e.color = 0;
|
e.color = 0;
|
||||||
e.augslot1 = 0;
|
e.augment_one = 0;
|
||||||
e.augslot2 = 0;
|
e.augment_two = 0;
|
||||||
e.augslot3 = 0;
|
e.augment_three = 0;
|
||||||
e.augslot4 = 0;
|
e.augment_four = 0;
|
||||||
e.augslot5 = 0;
|
e.augment_five = 0;
|
||||||
e.augslot6 = 0;
|
e.augment_six = 0;
|
||||||
e.instnodrop = 0;
|
e.instnodrop = 0;
|
||||||
e.custom_data = "";
|
e.custom_data = "";
|
||||||
e.ornamenticon = 0;
|
e.ornament_icon = 0;
|
||||||
e.ornamentidfile = 0;
|
e.ornament_idfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
e.guid = 0;
|
e.item_unique_id = "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -184,23 +184,23 @@ public:
|
|||||||
InventorySnapshots e{};
|
InventorySnapshots e{};
|
||||||
|
|
||||||
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.character_id = 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.slot_id = 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.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.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.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.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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_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.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.custom_data = row[13] ? row[13] : "";
|
e.custom_data = row[13] ? row[13] : "";
|
||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornament_icon = 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_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.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;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -235,23 +235,23 @@ public:
|
|||||||
auto columns = Columns();
|
auto columns = Columns();
|
||||||
|
|
||||||
v.push_back(columns[0] + " = " + std::to_string(e.time_index));
|
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[1] + " = " + std::to_string(e.character_id));
|
||||||
v.push_back(columns[2] + " = " + std::to_string(e.slotid));
|
v.push_back(columns[2] + " = " + std::to_string(e.slot_id));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.itemid));
|
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[4] + " = " + std::to_string(e.charges));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.color));
|
v.push_back(columns[5] + " = " + std::to_string(e.color));
|
||||||
v.push_back(columns[6] + " = " + std::to_string(e.augslot1));
|
v.push_back(columns[6] + " = " + std::to_string(e.augment_one));
|
||||||
v.push_back(columns[7] + " = " + std::to_string(e.augslot2));
|
v.push_back(columns[7] + " = " + std::to_string(e.augment_two));
|
||||||
v.push_back(columns[8] + " = " + std::to_string(e.augslot3));
|
v.push_back(columns[8] + " = " + std::to_string(e.augment_three));
|
||||||
v.push_back(columns[9] + " = " + std::to_string(e.augslot4));
|
v.push_back(columns[9] + " = " + std::to_string(e.augment_four));
|
||||||
v.push_back(columns[10] + " = " + std::to_string(e.augslot5));
|
v.push_back(columns[10] + " = " + std::to_string(e.augment_five));
|
||||||
v.push_back(columns[11] + " = " + std::to_string(e.augslot6));
|
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[12] + " = " + std::to_string(e.instnodrop));
|
||||||
v.push_back(columns[13] + " = '" + Strings::Escape(e.custom_data) + "'");
|
v.push_back(columns[13] + " = '" + Strings::Escape(e.custom_data) + "'");
|
||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
v.push_back(columns[14] + " = " + std::to_string(e.ornament_icon));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
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[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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -274,23 +274,23 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.time_index));
|
v.push_back(std::to_string(e.time_index));
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.character_id));
|
||||||
v.push_back(std::to_string(e.slotid));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.charges));
|
||||||
v.push_back(std::to_string(e.color));
|
v.push_back(std::to_string(e.color));
|
||||||
v.push_back(std::to_string(e.augslot1));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.augslot2));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.augslot3));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.augslot4));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.augslot5));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.augslot6));
|
v.push_back(std::to_string(e.augment_six));
|
||||||
v.push_back(std::to_string(e.instnodrop));
|
v.push_back(std::to_string(e.instnodrop));
|
||||||
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornament_icon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
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.ornament_hero_model));
|
||||||
v.push_back(std::to_string(e.guid));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -321,23 +321,23 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.time_index));
|
v.push_back(std::to_string(e.time_index));
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.character_id));
|
||||||
v.push_back(std::to_string(e.slotid));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.charges));
|
||||||
v.push_back(std::to_string(e.color));
|
v.push_back(std::to_string(e.color));
|
||||||
v.push_back(std::to_string(e.augslot1));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.augslot2));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.augslot3));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.augslot4));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.augslot5));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.augslot6));
|
v.push_back(std::to_string(e.augment_six));
|
||||||
v.push_back(std::to_string(e.instnodrop));
|
v.push_back(std::to_string(e.instnodrop));
|
||||||
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornament_icon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
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.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) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@@ -372,23 +372,23 @@ public:
|
|||||||
InventorySnapshots e{};
|
InventorySnapshots e{};
|
||||||
|
|
||||||
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.character_id = 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.slot_id = 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.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.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.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.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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_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.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.custom_data = row[13] ? row[13] : "";
|
e.custom_data = row[13] ? row[13] : "";
|
||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornament_icon = 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_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.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);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -414,23 +414,23 @@ public:
|
|||||||
InventorySnapshots e{};
|
InventorySnapshots e{};
|
||||||
|
|
||||||
e.time_index = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
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.character_id = 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.slot_id = 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.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.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.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.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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_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.instnodrop = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.custom_data = row[13] ? row[13] : "";
|
e.custom_data = row[13] ? row[13] : "";
|
||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornament_icon = 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_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.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);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -506,23 +506,23 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.time_index));
|
v.push_back(std::to_string(e.time_index));
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.character_id));
|
||||||
v.push_back(std::to_string(e.slotid));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.charges));
|
||||||
v.push_back(std::to_string(e.color));
|
v.push_back(std::to_string(e.color));
|
||||||
v.push_back(std::to_string(e.augslot1));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.augslot2));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.augslot3));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.augslot4));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.augslot5));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.augslot6));
|
v.push_back(std::to_string(e.augment_six));
|
||||||
v.push_back(std::to_string(e.instnodrop));
|
v.push_back(std::to_string(e.instnodrop));
|
||||||
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornament_icon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
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.ornament_hero_model));
|
||||||
v.push_back(std::to_string(e.guid));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -546,23 +546,23 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.time_index));
|
v.push_back(std::to_string(e.time_index));
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.character_id));
|
||||||
v.push_back(std::to_string(e.slotid));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.charges));
|
||||||
v.push_back(std::to_string(e.color));
|
v.push_back(std::to_string(e.color));
|
||||||
v.push_back(std::to_string(e.augslot1));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.augslot2));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.augslot3));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.augslot4));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.augslot5));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.augslot6));
|
v.push_back(std::to_string(e.augment_six));
|
||||||
v.push_back(std::to_string(e.instnodrop));
|
v.push_back(std::to_string(e.instnodrop));
|
||||||
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
|
||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornament_icon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
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.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) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
uint32_t ornament_icon;
|
uint32_t ornament_icon;
|
||||||
uint32_t ornament_idfile;
|
uint32_t ornament_idfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
uint64_t guid;
|
std::string item_unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
"ornament_icon",
|
"ornament_icon",
|
||||||
"ornament_idfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ public:
|
|||||||
"ornament_icon",
|
"ornament_icon",
|
||||||
"ornament_idfile",
|
"ornament_idfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
"guid",
|
"item_unique_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ public:
|
|||||||
e.ornament_icon = 0;
|
e.ornament_icon = 0;
|
||||||
e.ornament_idfile = 0;
|
e.ornament_idfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
e.guid = 0;
|
e.item_unique_id = "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ public:
|
|||||||
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
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_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.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;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ public:
|
|||||||
v.push_back(columns[12] + " = " + std::to_string(e.ornament_icon));
|
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[13] + " = " + std::to_string(e.ornament_idfile));
|
||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornament_hero_model));
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -276,7 +276,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -321,7 +321,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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) + ")");
|
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_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_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.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);
|
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_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_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.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);
|
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_icon));
|
||||||
v.push_back(std::to_string(e.ornament_idfile));
|
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.ornament_hero_model));
|
||||||
v.push_back(std::to_string(e.guid));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -538,7 +538,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornament_icon));
|
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_idfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
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) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,24 +19,24 @@
|
|||||||
class BaseTraderRepository {
|
class BaseTraderRepository {
|
||||||
public:
|
public:
|
||||||
struct Trader {
|
struct Trader {
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
uint32_t char_id;
|
uint32_t character_id;
|
||||||
uint32_t item_id;
|
uint32_t item_id;
|
||||||
uint32_t aug_slot_1;
|
std::string item_unique_id;
|
||||||
uint32_t aug_slot_2;
|
uint32_t augment_one;
|
||||||
uint32_t aug_slot_3;
|
uint32_t augment_two;
|
||||||
uint32_t aug_slot_4;
|
uint32_t augment_three;
|
||||||
uint32_t aug_slot_5;
|
uint32_t augment_four;
|
||||||
uint32_t aug_slot_6;
|
uint32_t augment_five;
|
||||||
uint32_t item_sn;
|
uint32_t augment_six;
|
||||||
int32_t item_charges;
|
int32_t item_charges;
|
||||||
uint32_t item_cost;
|
uint32_t item_cost;
|
||||||
uint8_t slot_id;
|
uint8_t slot_id;
|
||||||
uint32_t char_entity_id;
|
uint32_t char_entity_id;
|
||||||
uint32_t char_zone_id;
|
uint32_t char_zone_id;
|
||||||
int32_t char_zone_instance_id;
|
int32_t char_zone_instance_id;
|
||||||
uint8_t active_transaction;
|
uint8_t active_transaction;
|
||||||
time_t listing_date;
|
time_t listing_date;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -48,15 +48,15 @@ public:
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"id",
|
"id",
|
||||||
"char_id",
|
"character_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
"aug_slot_1",
|
"item_unique_id",
|
||||||
"aug_slot_2",
|
"augment_one",
|
||||||
"aug_slot_3",
|
"augment_two",
|
||||||
"aug_slot_4",
|
"augment_three",
|
||||||
"aug_slot_5",
|
"augment_four",
|
||||||
"aug_slot_6",
|
"augment_five",
|
||||||
"item_sn",
|
"augment_six",
|
||||||
"item_charges",
|
"item_charges",
|
||||||
"item_cost",
|
"item_cost",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
@@ -72,15 +72,15 @@ public:
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"id",
|
"id",
|
||||||
"char_id",
|
"character_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
"aug_slot_1",
|
"item_unique_id",
|
||||||
"aug_slot_2",
|
"augment_one",
|
||||||
"aug_slot_3",
|
"augment_two",
|
||||||
"aug_slot_4",
|
"augment_three",
|
||||||
"aug_slot_5",
|
"augment_four",
|
||||||
"aug_slot_6",
|
"augment_five",
|
||||||
"item_sn",
|
"augment_six",
|
||||||
"item_charges",
|
"item_charges",
|
||||||
"item_cost",
|
"item_cost",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
@@ -130,15 +130,15 @@ public:
|
|||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = 0;
|
e.id = 0;
|
||||||
e.char_id = 0;
|
e.character_id = 0;
|
||||||
e.item_id = 0;
|
e.item_id = 0;
|
||||||
e.aug_slot_1 = 0;
|
e.item_unique_id = "";
|
||||||
e.aug_slot_2 = 0;
|
e.augment_one = 0;
|
||||||
e.aug_slot_3 = 0;
|
e.augment_two = 0;
|
||||||
e.aug_slot_4 = 0;
|
e.augment_three = 0;
|
||||||
e.aug_slot_5 = 0;
|
e.augment_four = 0;
|
||||||
e.aug_slot_6 = 0;
|
e.augment_five = 0;
|
||||||
e.item_sn = 0;
|
e.augment_six = 0;
|
||||||
e.item_charges = 0;
|
e.item_charges = 0;
|
||||||
e.item_cost = 0;
|
e.item_cost = 0;
|
||||||
e.slot_id = 0;
|
e.slot_id = 0;
|
||||||
@@ -184,15 +184,15 @@ public:
|
|||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
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.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.item_unique_id = row[3] ? row[3] : "";
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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.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_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.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;
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
@@ -234,15 +234,15 @@ public:
|
|||||||
|
|
||||||
auto columns = Columns();
|
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[2] + " = " + std::to_string(e.item_id));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.aug_slot_1));
|
v.push_back(columns[3] + " = '" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_2));
|
v.push_back(columns[4] + " = " + std::to_string(e.augment_one));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_3));
|
v.push_back(columns[5] + " = " + std::to_string(e.augment_two));
|
||||||
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
|
v.push_back(columns[6] + " = " + std::to_string(e.augment_three));
|
||||||
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
|
v.push_back(columns[7] + " = " + std::to_string(e.augment_four));
|
||||||
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
|
v.push_back(columns[8] + " = " + std::to_string(e.augment_five));
|
||||||
v.push_back(columns[9] + " = " + std::to_string(e.item_sn));
|
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[10] + " = " + std::to_string(e.item_charges));
|
||||||
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
|
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
|
||||||
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
||||||
@@ -273,15 +273,15 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
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.item_id));
|
||||||
v.push_back(std::to_string(e.aug_slot_1));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.aug_slot_3));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.aug_slot_4));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.aug_slot_6));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.item_sn));
|
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_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
@@ -320,15 +320,15 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
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.item_id));
|
||||||
v.push_back(std::to_string(e.aug_slot_1));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.aug_slot_3));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.aug_slot_4));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.aug_slot_6));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.item_sn));
|
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_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
@@ -371,15 +371,15 @@ public:
|
|||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
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.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.item_unique_id = row[3] ? row[3] : "";
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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.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_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.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;
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
@@ -413,15 +413,15 @@ public:
|
|||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
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.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.item_unique_id = row[3] ? row[3] : "";
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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.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_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.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;
|
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;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
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.item_id));
|
||||||
v.push_back(std::to_string(e.aug_slot_1));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.aug_slot_3));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.aug_slot_4));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.aug_slot_6));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.item_sn));
|
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_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
@@ -545,15 +545,15 @@ public:
|
|||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
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.item_id));
|
||||||
v.push_back(std::to_string(e.aug_slot_1));
|
v.push_back("'" + Strings::Escape(e.item_unique_id) + "'");
|
||||||
v.push_back(std::to_string(e.aug_slot_2));
|
v.push_back(std::to_string(e.augment_one));
|
||||||
v.push_back(std::to_string(e.aug_slot_3));
|
v.push_back(std::to_string(e.augment_two));
|
||||||
v.push_back(std::to_string(e.aug_slot_4));
|
v.push_back(std::to_string(e.augment_three));
|
||||||
v.push_back(std::to_string(e.aug_slot_5));
|
v.push_back(std::to_string(e.augment_four));
|
||||||
v.push_back(std::to_string(e.aug_slot_6));
|
v.push_back(std::to_string(e.augment_five));
|
||||||
v.push_back(std::to_string(e.item_sn));
|
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_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
|
|||||||
@@ -106,8 +106,13 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buy_lines =
|
auto buy_lines = BaseBuyerBuyLinesRepository::GetWhere(
|
||||||
BaseBuyerBuyLinesRepository::GetWhere(db, fmt::format("`buyer_id` = {}", buyer.front().id));
|
db,
|
||||||
|
fmt::format("`buyer_id` = '{}'", buyer.front().id)
|
||||||
|
);
|
||||||
|
if (buy_lines.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> buy_line_ids{};
|
std::vector<std::string> buy_line_ids{};
|
||||||
for (auto const &bl: buy_lines) {
|
for (auto const &bl: buy_lines) {
|
||||||
@@ -175,4 +180,24 @@ public:
|
|||||||
|
|
||||||
return true;
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "common/repositories/base/base_inventory_snapshots_repository.h"
|
|
||||||
|
|
||||||
#include "common/database.h"
|
#include "common/database.h"
|
||||||
|
#include "common/repositories/base/base_inventory_snapshots_repository.h"
|
||||||
|
#include "common/repositories/inventory_repository.h"
|
||||||
#include "common/strings.h"
|
#include "common/strings.h"
|
||||||
|
|
||||||
class InventorySnapshotsRepository: public BaseInventorySnapshotsRepository {
|
class InventorySnapshotsRepository: public BaseInventorySnapshotsRepository {
|
||||||
@@ -46,16 +46,15 @@ public:
|
|||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
static int64 CountInventorySnapshots(Database& db)
|
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);
|
auto results = db.QueryDatabase(query);
|
||||||
|
|
||||||
if (!results.Success() || !results.RowCount()) {
|
if (!results.Success() || !results.RowCount()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
const int64 count = Strings::ToBigInt(row[0]);
|
const int64 count = Strings::ToBigInt(row[0]);
|
||||||
|
|
||||||
if (count > std::numeric_limits<int>::max()) {
|
if (count > std::numeric_limits<int>::max()) {
|
||||||
@@ -68,4 +67,254 @@ public:
|
|||||||
|
|
||||||
return count;
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
|
|
||||||
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
|
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
|
||||||
Database& db,
|
Database& db,
|
||||||
const std::vector<std::string> &search_ids,
|
const std::unordered_set<std::string> &search_ids,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
const std::string &field_criteria_items,
|
const std::string &field_criteria_items,
|
||||||
const std::string &where_criteria_items,
|
const std::string &where_criteria_items,
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
auto query = fmt::format(
|
auto query = fmt::format(
|
||||||
"SELECT id, name, stackable, icon, {} "
|
"SELECT id, name, stackable, icon, {} "
|
||||||
"FROM items "
|
"FROM items "
|
||||||
"WHERE `name` LIKE '%%{}%%' AND {} AND id IN({}) "
|
"WHERE `name` LIKE '%{}%' AND {} AND id IN({}) "
|
||||||
"ORDER BY id ASC",
|
"ORDER BY id ASC",
|
||||||
field_criteria_items,
|
field_criteria_items,
|
||||||
Strings::Escape(name),
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,8 +30,12 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarTraderSearch_Struct {
|
struct BazaarTraderSearch_Struct {
|
||||||
Trader trader;
|
Trader trader;
|
||||||
std::string trader_name;
|
std::string trader_name;
|
||||||
|
std::string name;
|
||||||
|
bool stackable;
|
||||||
|
uint32 icon;
|
||||||
|
uint32 stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WelcomeData_Struct {
|
struct WelcomeData_Struct {
|
||||||
@@ -59,9 +63,9 @@ public:
|
|||||||
|
|
||||||
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
||||||
results = db.QueryDatabase(fmt::format(
|
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 "
|
"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 = {} "
|
"WHERE t.char_zone_instance_id = {} "
|
||||||
"ORDER BY t.char_zone_instance_id ASC "
|
"ORDER BY t.char_zone_instance_id ASC "
|
||||||
"LIMIT {}",
|
"LIMIT {}",
|
||||||
@@ -70,13 +74,14 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
results = db.QueryDatabase(fmt::format(
|
results = db.QueryDatabase(
|
||||||
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
|
fmt::format(
|
||||||
"FROM trader AS t "
|
"SELECT DISTINCT(t.character_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
|
||||||
"JOIN character_data AS c ON t.char_id = c.id "
|
"FROM trader AS t "
|
||||||
"ORDER BY t.char_zone_instance_id ASC "
|
"JOIN character_data AS c ON t.character_id = c.id "
|
||||||
"LIMIT {}",
|
"ORDER BY t.char_zone_instance_id ASC "
|
||||||
max_results)
|
"LIMIT {}",
|
||||||
|
max_results)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +107,7 @@ public:
|
|||||||
{
|
{
|
||||||
WelcomeData_Struct e{};
|
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()) {
|
if (!results.RowCount()) {
|
||||||
return e;
|
return e;
|
||||||
@@ -114,15 +119,15 @@ public:
|
|||||||
return e;
|
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{};
|
std::vector<BaseTraderRepository::Trader> items{};
|
||||||
if (item_charges == 0) {
|
if (item_charges == 0) {
|
||||||
items = GetWhere(
|
items = GetWhere(
|
||||||
db,
|
db,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"char_id = '{}' AND item_id = '{}'",
|
"character_id = {} AND item_id = {}",
|
||||||
char_id,
|
character_id,
|
||||||
item_id
|
item_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -131,8 +136,8 @@ public:
|
|||||||
items = GetWhere(
|
items = GetWhere(
|
||||||
db,
|
db,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"char_id = '{}' AND item_id = '{}' AND item_charges = '{}'",
|
"character_id = {} AND item_id = {} AND item_charges = {}",
|
||||||
char_id,
|
character_id,
|
||||||
item_id,
|
item_id,
|
||||||
item_charges
|
item_charges
|
||||||
)
|
)
|
||||||
@@ -156,7 +161,7 @@ public:
|
|||||||
Trader item{};
|
Trader item{};
|
||||||
|
|
||||||
auto query = fmt::format(
|
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 = {} "
|
"WHERE t.entity_id = {} AND t.item_id = {} AND t.item_cost = {} "
|
||||||
"LIMIT 1;",
|
"LIMIT 1;",
|
||||||
trader_id,
|
trader_id,
|
||||||
@@ -169,41 +174,103 @@ public:
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
item.char_id = Strings::ToInt(row[0]);
|
item.character_id = Strings::ToInt(row[0]);
|
||||||
item.item_id = Strings::ToInt(row[1]);
|
item.item_id = Strings::ToInt(row[1]);
|
||||||
item.item_sn = Strings::ToInt(row[2]);
|
item.item_unique_id = row[2] ? row[2] : "";
|
||||||
item.item_charges = Strings::ToInt(row[3]);
|
item.item_charges = Strings::ToInt(row[3]);
|
||||||
item.item_cost = Strings::ToInt(row[4]);
|
item.item_cost = Strings::ToInt(row[4]);
|
||||||
item.slot_id = Strings::ToInt(row[5]);
|
item.slot_id = Strings::ToInt(row[5]);
|
||||||
|
|
||||||
return item;
|
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(
|
const auto trader_item = GetWhere(
|
||||||
db,
|
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) {
|
if (trader_item.empty() || trader_item.size() > 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto m = trader_item[0];
|
auto m = trader_item[0];
|
||||||
m.item_charges = quantity;
|
m.item_charges = quantity;
|
||||||
m.listing_date = time(nullptr);
|
m.listing_date = time(nullptr);
|
||||||
|
|
||||||
return UpdateOne(db, m);
|
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{};
|
Trader e{};
|
||||||
const auto trader_item = GetWhere(
|
const auto trader_item = GetWhere(
|
||||||
db,
|
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()) {
|
if (trader_item.empty()) {
|
||||||
@@ -213,13 +280,12 @@ public:
|
|||||||
return trader_item.at(0);
|
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{};
|
Trader e{};
|
||||||
auto sn = Strings::ToUnsignedBigInt(serial_number);
|
|
||||||
const auto trader_item = GetWhere(
|
const auto trader_item = GetWhere(
|
||||||
db,
|
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()) {
|
if (trader_item.empty()) {
|
||||||
@@ -257,21 +323,16 @@ public:
|
|||||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static DistinctTraders_Struct GetTraderByInstanceAndSerialnumber(
|
static DistinctTraders_Struct GetTraderByItemUniqueNumber(Database &db, std::string &item_unique_id)
|
||||||
Database &db,
|
|
||||||
uint32 instance_id,
|
|
||||||
const char *serial_number
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
DistinctTraders_Struct trader{};
|
DistinctTraders_Struct trader{};
|
||||||
|
|
||||||
auto query = fmt::format(
|
auto query = fmt::format(
|
||||||
"SELECT t.id, t.char_id, c.name "
|
"SELECT t.id, t.character_id, c.name "
|
||||||
"FROM trader AS t "
|
"FROM trader AS t "
|
||||||
"JOIN character_data AS c ON c.id = t.char_id "
|
"JOIN character_data AS c ON c.id = t.character_id "
|
||||||
"WHERE t.char_zone_id = 151 AND t.char_zone_instance_id = {} AND t.item_sn = {} LIMIT 1",
|
"WHERE t.item_unique_id = '{}' LIMIT 1",
|
||||||
instance_id,
|
item_unique_id
|
||||||
serial_number
|
|
||||||
);
|
);
|
||||||
|
|
||||||
auto results = db.QueryDatabase(query);
|
auto results = db.QueryDatabase(query);
|
||||||
@@ -281,7 +342,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
std::string name = row[2];
|
|
||||||
trader.trader_id = Strings::ToUnsignedInt(row[1]);
|
trader.trader_id = Strings::ToUnsignedInt(row[1]);
|
||||||
trader.trader_name = row[2] ? row[2] : "";
|
trader.trader_name = row[2] ? row[2] : "";
|
||||||
|
|
||||||
@@ -290,14 +350,23 @@ public:
|
|||||||
|
|
||||||
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
|
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
|
||||||
Database &db,
|
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{};
|
std::vector<BazaarTraderSearch_Struct> all_entries{};
|
||||||
|
|
||||||
auto query = fmt::format(
|
auto query = fmt::format(
|
||||||
"SELECT trader.*, c.`name` FROM `trader` INNER JOIN character_data AS c ON trader.char_id = c.id "
|
"SELECT trader.id, trader.character_id, trader.item_id, trader.item_unique_id, trader.augment_one, "
|
||||||
"WHERE {} ORDER BY trader.char_id ASC",
|
"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
|
search_criteria_trader
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -312,15 +381,15 @@ public:
|
|||||||
BazaarTraderSearch_Struct e{};
|
BazaarTraderSearch_Struct e{};
|
||||||
|
|
||||||
e.trader.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
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.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.item_unique_id = row[3] ? row[3] : std::string("");
|
||||||
e.trader.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.trader.augment_one = 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.augment_two = 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.augment_three = 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.augment_four = 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.augment_five = 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.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_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.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;
|
e.trader.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
@@ -335,4 +404,47 @@ public:
|
|||||||
|
|
||||||
return all_entries;
|
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
@@ -229,10 +229,12 @@
|
|||||||
#define ServerOP_LSPlayerJoinWorld 0x3007
|
#define ServerOP_LSPlayerJoinWorld 0x3007
|
||||||
#define ServerOP_LSPlayerZoneChange 0x3008
|
#define ServerOP_LSPlayerZoneChange 0x3008
|
||||||
|
|
||||||
#define ServerOP_UsertoWorldReqLeg 0xAB00
|
#define ServerOP_UsertoWorldReqLeg 0xAB00
|
||||||
#define ServerOP_UsertoWorldRespLeg 0xAB01
|
#define ServerOP_UsertoWorldRespLeg 0xAB01
|
||||||
#define ServerOP_UsertoWorldReq 0xAB02
|
#define ServerOP_UsertoWorldReq 0xAB02
|
||||||
#define ServerOP_UsertoWorldResp 0xAB03
|
#define ServerOP_UsertoWorldResp 0xAB03
|
||||||
|
#define ServerOP_UsertoWorldCancelOfflineRequest 0xAB04
|
||||||
|
#define ServerOP_UsertoWorldCancelOfflineResponse 0xAB05
|
||||||
|
|
||||||
#define ServerOP_LauncherConnectInfo 0x3000
|
#define ServerOP_LauncherConnectInfo 0x3000
|
||||||
#define ServerOP_LauncherZoneRequest 0x3001
|
#define ServerOP_LauncherZoneRequest 0x3001
|
||||||
@@ -360,14 +362,24 @@ enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_
|
|||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
UserToWorldStatusWorldUnavail = 0,
|
UserToWorldStatusWorldUnavail = 0,
|
||||||
UserToWorldStatusSuccess = 1,
|
UserToWorldStatusSuccess = 1,
|
||||||
UserToWorldStatusSuspended = -1,
|
UserToWorldStatusSuspended = -1,
|
||||||
UserToWorldStatusBanned = -2,
|
UserToWorldStatusBanned = -2,
|
||||||
UserToWorldStatusWorldAtCapacity = -3,
|
UserToWorldStatusWorldAtCapacity = -3,
|
||||||
UserToWorldStatusAlreadyOnline = -4
|
UserToWorldStatusAlreadyOnline = -4,
|
||||||
|
UserToWorldStatusOffilineTraderBuyer = -5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BazaarPurchaseFailed = 0,
|
||||||
|
BazaarPurchaseSuccess = 1,
|
||||||
|
BazaarPurchaseBuyerCompleteSendToSeller = 2,
|
||||||
|
BazaarPurchaseSellerCompleteSendToBuyer = 3,
|
||||||
|
BazaarPurchaseBuyerFailed = 4,
|
||||||
|
BazaarPurchaseBuyerSuccess = 5,
|
||||||
|
BazaarPurchaseTraderFailed = 6
|
||||||
|
};
|
||||||
/************ PACKET RELATED STRUCT ************/
|
/************ PACKET RELATED STRUCT ************/
|
||||||
class ServerPacket
|
class ServerPacket
|
||||||
{
|
{
|
||||||
@@ -559,6 +571,9 @@ struct ServerClientList_Struct {
|
|||||||
uint8 LFGToLevel;
|
uint8 LFGToLevel;
|
||||||
bool LFGMatchFilter;
|
bool LFGMatchFilter;
|
||||||
char LFGComments[64];
|
char LFGComments[64];
|
||||||
|
bool trader;
|
||||||
|
bool buyer;
|
||||||
|
bool offline;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerClientListKeepAlive_Struct {
|
struct ServerClientListKeepAlive_Struct {
|
||||||
@@ -1022,6 +1037,7 @@ struct ServerGuildMemberUpdate_Struct {
|
|||||||
char member_name[64];
|
char member_name[64];
|
||||||
uint32 zone_id;
|
uint32 zone_id;
|
||||||
uint32 last_seen;
|
uint32 last_seen;
|
||||||
|
uint32 offline_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerGuildPermissionUpdate_Struct {
|
struct ServerGuildPermissionUpdate_Struct {
|
||||||
@@ -1776,8 +1792,15 @@ struct BazaarPurchaseMessaging_Struct {
|
|||||||
uint32 item_aug_5;
|
uint32 item_aug_5;
|
||||||
uint32 item_aug_6;
|
uint32 item_aug_6;
|
||||||
uint32 buyer_id;
|
uint32 buyer_id;
|
||||||
uint32 item_quantity_available;
|
uint32 item_quantity;
|
||||||
|
int16 item_charges;
|
||||||
uint32 id;
|
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)
|
#pragma pack(pop)
|
||||||
|
|||||||
+31
-15
@@ -275,7 +275,12 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance*
|
|||||||
e.ornament_icon = inst->GetOrnamentationIcon();
|
e.ornament_icon = inst->GetOrnamentationIcon();
|
||||||
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
||||||
e.ornament_hero_model = inst->GetOrnamentHeroModel();
|
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);
|
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_icon = inst->GetOrnamentationIcon();
|
||||||
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
||||||
e.ornament_hero_model = inst->GetOrnamentHeroModel();
|
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);
|
const int replaced = SharedbankRepository::ReplaceOne(*this, e);
|
||||||
|
|
||||||
@@ -630,12 +640,6 @@ bool SharedDatabase::GetInventory(Client *c)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& row: results) {
|
|
||||||
if (row.guid != 0) {
|
|
||||||
EQ::ItemInstance::AddGUIDToMap(row.guid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto timestamps = GetItemRecastTimestamps(char_id);
|
const auto timestamps = GetItemRecastTimestamps(char_id);
|
||||||
auto cv_conflict = false;
|
auto cv_conflict = false;
|
||||||
const auto pmask = inv.GetLookup()->PossessionsBitmask;
|
const auto pmask = inv.GetLookup()->PossessionsBitmask;
|
||||||
@@ -713,6 +717,21 @@ bool SharedDatabase::GetInventory(Client *c)
|
|||||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
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 (
|
if (
|
||||||
instnodrop ||
|
instnodrop ||
|
||||||
(
|
(
|
||||||
@@ -727,7 +746,7 @@ bool SharedDatabase::GetInventory(Client *c)
|
|||||||
inst->SetColor(color);
|
inst->SetColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (charges == std::numeric_limits<int16>::max()) {
|
if (charges > std::numeric_limits<int16>::max()) {
|
||||||
inst->SetCharges(-1);
|
inst->SetCharges(-1);
|
||||||
} else if (charges == 0 && inst->IsStackable()) {
|
} else if (charges == 0 && inst->IsStackable()) {
|
||||||
// Stackable items need a minimum charge of 1 remain moveable.
|
// 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);
|
put_slot_id = inv.PutItem(slot_id, *inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
row.guid = inst->GetSerialNumber();
|
//queue.push_back(row);
|
||||||
queue.push_back(row);
|
|
||||||
|
|
||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
|
|
||||||
@@ -839,8 +857,6 @@ bool SharedDatabase::GetInventory(Client *c)
|
|||||||
InventoryRepository::ReplaceMany(*this, queue);
|
InventoryRepository::ReplaceMany(*this, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::ItemInstance::ClearGUIDMap();
|
|
||||||
|
|
||||||
// Retrieve shared inventory
|
// Retrieve shared inventory
|
||||||
return GetSharedBank(char_id, &inv, true);
|
return GetSharedBank(char_id, &inv, true);
|
||||||
}
|
}
|
||||||
@@ -1401,7 +1417,7 @@ EQ::ItemInstance* SharedDatabase::CreateItem(
|
|||||||
return inst;
|
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;
|
EQ::ItemInstance* inst = nullptr;
|
||||||
if (item) {
|
if (item) {
|
||||||
// if maxcharges is -1 that means it is an unlimited use 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;
|
charges = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inst = new EQ::ItemInstance(item, charges);
|
inst = new EQ::ItemInstance(item, item_unique_id, charges);
|
||||||
|
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
LogError("Error: valid item data returned a null reference for EQ::ItemInstance creation in SharedDatabase::CreateBaseItem()");
|
LogError("Error: valid item data returned a null reference for EQ::ItemInstance creation in SharedDatabase::CreateBaseItem()");
|
||||||
|
|||||||
+1
-1
@@ -154,7 +154,7 @@ public:
|
|||||||
uint32 ornamentidfile = 0,
|
uint32 ornamentidfile = 0,
|
||||||
uint32 ornament_hero_model = 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 GetItemsCount(int32& item_count, uint32& max_id);
|
||||||
void LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id);
|
void LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id);
|
||||||
|
|||||||
@@ -960,3 +960,22 @@ bool Strings::IsValidJson(const std::string &json)
|
|||||||
|
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
class Strings {
|
class Strings {
|
||||||
public:
|
public:
|
||||||
@@ -76,6 +77,7 @@ public:
|
|||||||
static std::string Escape(const std::string &s);
|
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 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::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<std::string> &ar, const std::string &delim);
|
||||||
static std::string Join(const std::vector<uint32_t> &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);
|
static std::string MillisecondsToTime(int duration);
|
||||||
|
|||||||
+1
-1
@@ -41,6 +41,6 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* 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 CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
|
||||||
#define CUSTOM_BINARY_DATABASE_VERSION 0
|
#define CUSTOM_BINARY_DATABASE_VERSION 0
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# Bazaar Item Unique ID And Offline Trading Rollout
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
This rollout converts persisted item identity and offline trader or buyer session state to the new production-safe model. The migration is designed for a maintenance window and explicitly clears any in-flight trader, buyer, and offline sessions during cutover.
|
||||||
|
|
||||||
|
Do not reopen the server until every verification step passes.
|
||||||
|
|
||||||
|
## Preconditions
|
||||||
|
|
||||||
|
- Schedule a maintenance window.
|
||||||
|
- Stop new logins before beginning the migration.
|
||||||
|
- Ensure the `world` binary you are deploying includes this branch.
|
||||||
|
- Ensure operators have credentials to run schema updates and database dump commands.
|
||||||
|
|
||||||
|
## Mandatory Backup
|
||||||
|
|
||||||
|
Take a backup before any schema or migration command:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:dump --player-tables --login-tables --dump-path=backups --compress
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use a separate database backup process, complete it before continuing.
|
||||||
|
|
||||||
|
## Local Dev Validation
|
||||||
|
|
||||||
|
Run these commands against the local dev database before production:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:updates --skip-backup
|
||||||
|
world database:item-unique-ids --preflight --verbose
|
||||||
|
world database:item-unique-ids --migrate --verbose
|
||||||
|
world database:item-unique-ids --verify --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
Validate these gameplay scenarios after the migration:
|
||||||
|
|
||||||
|
- Two traders listing the same item at different prices.
|
||||||
|
- One trader changing a price without affecting another trader.
|
||||||
|
- Offline trader purchase.
|
||||||
|
- Offline buyer purchase.
|
||||||
|
- Parcel retrieval for rows that previously had missing `item_unique_id` values.
|
||||||
|
- Alternate bazaar shard search.
|
||||||
|
|
||||||
|
## Production Sequence
|
||||||
|
|
||||||
|
1. Bring the server into maintenance mode and stop new gameplay activity.
|
||||||
|
2. Take the mandatory backup.
|
||||||
|
3. Apply schema updates:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:updates
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Run the migration preflight:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:item-unique-ids --preflight --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
5. If preflight reports missing schema, duplicate live item IDs, or other unexpected errors, stop and resolve them before continuing.
|
||||||
|
6. Run the migration:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:item-unique-ids --migrate --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
This step clears active trader, buyer, and offline session state. Players must re-enter those modes after deploy.
|
||||||
|
|
||||||
|
7. Run final verification:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
world database:item-unique-ids --verify --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Reopen the server only after verification passes.
|
||||||
|
|
||||||
|
## What Preflight And Verify Must Show
|
||||||
|
|
||||||
|
The migration is not complete unless all of the following are true:
|
||||||
|
|
||||||
|
- `inventory`, `sharedbank`, and `trader` contain no null or blank `item_unique_id` values.
|
||||||
|
- `character_parcels`, `character_parcels_containers`, and `inventory_snapshots` contain no null or blank `item_unique_id` values.
|
||||||
|
- `inventory`, `sharedbank`, and `trader` contain no duplicate `item_unique_id` groups.
|
||||||
|
- There are no cross-table duplicate live `item_unique_id` values across `inventory`, `sharedbank`, and `trader`.
|
||||||
|
- `offline_character_sessions` is empty after migration.
|
||||||
|
- `account.offline` has no rows left set to `1`.
|
||||||
|
|
||||||
|
## Rollback Criteria
|
||||||
|
|
||||||
|
Rollback instead of reopening the server if any of the following occur:
|
||||||
|
|
||||||
|
- `world database:updates` fails.
|
||||||
|
- `world database:item-unique-ids --preflight` reports missing required schema.
|
||||||
|
- `world database:item-unique-ids --migrate` or `--verify` reports missing IDs, duplicate IDs, or stale offline session state.
|
||||||
|
- Bazaar listing, offline trader, offline buyer, or parcel retrieval smoke tests fail after migration.
|
||||||
|
|
||||||
|
## Rollback Actions
|
||||||
|
|
||||||
|
1. Keep the server in maintenance mode.
|
||||||
|
2. Restore the database backup taken before the rollout.
|
||||||
|
3. Redeploy the previous server build.
|
||||||
|
4. Confirm login, trader, buyer, and parcel behavior on the restored build before reopening the server.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `world database:item-unique-ids --keep-trading-state` exists for non-production diagnostics only. Do not use it during production cutover.
|
||||||
|
- The migration command expects schema updates to have been applied first. If required tables or columns are missing, the command fails and should not be bypassed.
|
||||||
@@ -71,6 +71,25 @@ bool Client::Process()
|
|||||||
SendPlayToWorld((const char *) app->pBuffer);
|
SendPlayToWorld((const char *) app->pBuffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_CancelOfflineTrader: {
|
||||||
|
if (app->Size() < sizeof(CancelOfflineTrader)) {
|
||||||
|
LogError("Play received but it is too small, discarding");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_delete_array(app->pBuffer);
|
||||||
|
auto buffer = new unsigned char[sizeof(PlayEverquestRequest)];
|
||||||
|
auto data = (PlayEverquestRequest *) buffer;
|
||||||
|
data->base_header.sequence = GetCurrentPlaySequence();
|
||||||
|
data->server_number = GetSelectedPlayServerID();
|
||||||
|
app->pBuffer = buffer;
|
||||||
|
app->size = sizeof(PlayEverquestRequest);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 1 - Hit CancelOfflineTrader Mode Packet for.");
|
||||||
|
SendCancelOfflineStatusToWorld((const char *) app->pBuffer);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete app;
|
delete app;
|
||||||
@@ -561,3 +580,27 @@ std::string Client::GetClientLoggingDescription()
|
|||||||
client_ip
|
client_ip
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::SendCancelOfflineStatusToWorld(const char *data)
|
||||||
|
{
|
||||||
|
if (m_client_status != cs_logged_in) {
|
||||||
|
LogError("Client sent a play request when they were not logged in, discarding");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto *play = (const PlayEverquestRequest *) data;
|
||||||
|
auto server_id_in = (unsigned int) play->server_number;
|
||||||
|
auto sequence_in = (unsigned int) play->base_header.sequence;
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 2 - Cancel Offline Status Request received from client [{}] server number [{}] sequence [{}]",
|
||||||
|
GetAccountName(),
|
||||||
|
server_id_in,
|
||||||
|
sequence_in
|
||||||
|
);
|
||||||
|
|
||||||
|
m_selected_play_server_id = (unsigned int) play->server_number;
|
||||||
|
m_play_sequence_id = sequence_in;
|
||||||
|
m_selected_play_server_id = server_id_in;
|
||||||
|
server.server_manager->SendUserToWorldCancelOfflineRequest(server_id_in, m_account_id, m_loginserver_name);
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
void SendPlayToWorld(const char *data);
|
void SendPlayToWorld(const char *data);
|
||||||
void SendServerListPacket(uint32 seq);
|
void SendServerListPacket(uint32 seq);
|
||||||
void SendPlayResponse(EQApplicationPacket *outapp);
|
void SendPlayResponse(EQApplicationPacket *outapp);
|
||||||
|
void SendCancelOfflineStatusToWorld(const char *data);
|
||||||
void GenerateRandomLoginKey();
|
void GenerateRandomLoginKey();
|
||||||
unsigned int GetAccountID() const { return m_account_id; }
|
unsigned int GetAccountID() const { return m_account_id; }
|
||||||
std::string GetLoginServerName() const { return m_loginserver_name; }
|
std::string GetLoginServerName() const { return m_loginserver_name; }
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ struct PlayEverquestResponse {
|
|||||||
uint32 server_number;
|
uint32 server_number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CancelOfflineTrader {
|
||||||
|
LoginBaseMessage base_header;
|
||||||
|
int16_t unk;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
enum LSClientVersion {
|
enum LSClientVersion {
|
||||||
@@ -158,11 +163,12 @@ namespace LS {
|
|||||||
constexpr static int ERROR_NONE = 101; // No Error
|
constexpr static int ERROR_NONE = 101; // No Error
|
||||||
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
|
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
|
||||||
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
|
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
|
||||||
|
constexpr static int ERROR_OFFLINE_TRADER = 114; // You have a character logged into a world server as an OFFLINE TRADER from this account. You may only have 1 character from a single account logged into a server at a time (even across different servers). Would you like to remove this character from the game so you may login?
|
||||||
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
|
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
|
||||||
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
|
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
|
||||||
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
|
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
|
||||||
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
|
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ OP_Poll=0x0029
|
|||||||
OP_LoginExpansionPacketData=0x0031
|
OP_LoginExpansionPacketData=0x0031
|
||||||
OP_EnterChat=0x000f
|
OP_EnterChat=0x000f
|
||||||
OP_PollResponse=0x0011
|
OP_PollResponse=0x0011
|
||||||
|
OP_CancelOfflineTrader=0x0016
|
||||||
|
OP_CancelOfflineTraderResponse=0x0030
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "loginserver/login_server.h"
|
#include "loginserver/login_server.h"
|
||||||
#include "loginserver/loginserver_command_handler.h"
|
#include "loginserver/loginserver_command_handler.h"
|
||||||
#include "loginserver/loginserver_webserver.h"
|
#include "loginserver/loginserver_webserver.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> wo
|
|||||||
ServerOP_LSAccountUpdate,
|
ServerOP_LSAccountUpdate,
|
||||||
std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)
|
std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
worldserver_connection->OnMessage(
|
||||||
|
ServerOP_UsertoWorldCancelOfflineResponse,
|
||||||
|
std::bind(
|
||||||
|
&WorldServer::ProcessUserToWorldCancelOfflineResponse, this, std::placeholders::_1, std::placeholders::_2)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldServer::~WorldServer() = default;
|
WorldServer::~WorldServer() = default;
|
||||||
@@ -299,6 +305,10 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
|
|||||||
case UserToWorldStatusAlreadyOnline:
|
case UserToWorldStatusAlreadyOnline:
|
||||||
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
|
||||||
break;
|
break;
|
||||||
|
case UserToWorldStatusOffilineTraderBuyer:
|
||||||
|
r->base_reply.success = false;
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_OFFLINE_TRADER;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
r->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
|
||||||
break;
|
break;
|
||||||
@@ -775,3 +785,113 @@ void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
|
|||||||
|
|
||||||
strn0cpy(name, server_long_name.c_str(), 201);
|
strn0cpy(name, server_long_name.c_str(), 201);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldServer::ProcessUserToWorldCancelOfflineResponse(uint16_t opcode, const EQ::Net::Packet &packet)
|
||||||
|
{
|
||||||
|
LogNetcode(
|
||||||
|
"Application packet received from server [{:#04x}] [Size: {}]\n{}",
|
||||||
|
opcode,
|
||||||
|
packet.Length(),
|
||||||
|
packet.ToString()
|
||||||
|
);
|
||||||
|
LogLoginserverDetail("Step 8 - back in Login Server from world.");
|
||||||
|
|
||||||
|
if (packet.Length() < sizeof(UsertoWorldResponse)) {
|
||||||
|
LogError(
|
||||||
|
"Received application packet from server that had opcode ServerOP_UsertoWorldCancelOfflineResp, "
|
||||||
|
"but was too small. Discarded to avoid buffer overrun"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = (UsertoWorldResponse *) packet.Data();
|
||||||
|
LogDebug("Trying to find client with user id of [{}]", res->lsaccountid);
|
||||||
|
|
||||||
|
Client *c = server.client_manager->GetClient(
|
||||||
|
res->lsaccountid,
|
||||||
|
res->login
|
||||||
|
);
|
||||||
|
|
||||||
|
if (c) {
|
||||||
|
LogDebug(
|
||||||
|
"Found client with user id of [{}] and account name of {}",
|
||||||
|
res->lsaccountid,
|
||||||
|
c->GetAccountName().c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
auto client_packet = EQApplicationPacket(OP_CancelOfflineTraderResponse, sizeof(PlayEverquestResponse));
|
||||||
|
auto client_packet_payload = reinterpret_cast<PlayEverquestResponse *>(client_packet.pBuffer);
|
||||||
|
|
||||||
|
client_packet_payload->base_header.sequence = c->GetCurrentPlaySequence();
|
||||||
|
client_packet_payload->server_number = c->GetSelectedPlayServerID();
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 9 - Send Play Response OPCODE 30 to remove the client message about having an offline Trader/Buyer"
|
||||||
|
);
|
||||||
|
c->SendPlayResponse(&client_packet);
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse));
|
||||||
|
auto r = reinterpret_cast<PlayEverquestResponse *>(outapp->pBuffer);
|
||||||
|
r->base_header.sequence = c->GetCurrentPlaySequence();
|
||||||
|
r->server_number = c->GetSelectedPlayServerID();
|
||||||
|
|
||||||
|
LogDebug(
|
||||||
|
"Found sequence and play of [{}] [{}]",
|
||||||
|
c->GetCurrentPlaySequence(),
|
||||||
|
c->GetSelectedPlayServerID()
|
||||||
|
);
|
||||||
|
|
||||||
|
//LogDebug("[Size: [{}]] {}", outapp->size, DumpPacketToString(outapp));
|
||||||
|
|
||||||
|
if (res->response > 0) {
|
||||||
|
r->base_reply.success = true;
|
||||||
|
SendClientAuthToWorld(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (res->response) {
|
||||||
|
case UserToWorldStatusSuccess:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_NONE;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusWorldUnavail:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusSuspended:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusBanned:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusWorldAtCapacity:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusAlreadyOnline:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
|
||||||
|
break;
|
||||||
|
case UserToWorldStatusOffilineTraderBuyer:
|
||||||
|
r->base_reply.success = false;
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_OFFLINE_TRADER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug(
|
||||||
|
"Sending play response with following data, allowed [{}], sequence {}, server number {}, message {}",
|
||||||
|
r->base_reply.success,
|
||||||
|
r->base_header.sequence,
|
||||||
|
r->server_number,
|
||||||
|
r->base_reply.error_str_id
|
||||||
|
);
|
||||||
|
LogLoginserverDetail("Step 10 - Send Play Response EnterWorld to client");
|
||||||
|
|
||||||
|
c->SendPlayResponse(outapp);
|
||||||
|
delete outapp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LogError(
|
||||||
|
"Received User-To-World Response for [{}] but could not find the client referenced!.",
|
||||||
|
res->lsaccountid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@ private:
|
|||||||
void ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Net::Packet &packet);
|
void ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||||
void ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet);
|
void ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||||
void ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet);
|
void ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||||
|
void ProcessUserToWorldCancelOfflineResponse(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||||
|
|
||||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> m_connection;
|
std::shared_ptr<EQ::Net::ServertalkServerConnection> m_connection;
|
||||||
|
|
||||||
|
|||||||
@@ -216,3 +216,35 @@ const std::list<std::unique_ptr<WorldServer>> &WorldServerManager::GetWorldServe
|
|||||||
{
|
{
|
||||||
return m_world_servers;
|
return m_world_servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldServerManager::SendUserToWorldCancelOfflineRequest(
|
||||||
|
unsigned int server_id,
|
||||||
|
unsigned int client_account_id,
|
||||||
|
const std::string &client_loginserver
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto iter = std::find_if(
|
||||||
|
m_world_servers.begin(), m_world_servers.end(),
|
||||||
|
[&](const std::unique_ptr<WorldServer> &server) {
|
||||||
|
return server->GetServerId() == server_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (iter != m_world_servers.end()) {
|
||||||
|
EQ::Net::DynamicPacket outapp;
|
||||||
|
outapp.Resize(sizeof(UsertoWorldRequest));
|
||||||
|
|
||||||
|
auto *r = reinterpret_cast<UsertoWorldRequest *>(outapp.Data());
|
||||||
|
r->worldid = server_id;
|
||||||
|
r->lsaccountid = client_account_id;
|
||||||
|
strncpy(r->login, client_loginserver.c_str(), 64);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 3 - Sending ServerOP_UsertoWorldCancelOfflineRequest to world for client account id {}", client_account_id);
|
||||||
|
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldCancelOfflineRequest, outapp);
|
||||||
|
|
||||||
|
LogNetcode("[UsertoWorldRequest] [Size: {}]\n{}", outapp.Length(), outapp.ToString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LogError("Client requested a user to world but supplied an invalid id of {}", server_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,11 @@ public:
|
|||||||
unsigned int client_account_id,
|
unsigned int client_account_id,
|
||||||
const std::string &client_loginserver
|
const std::string &client_loginserver
|
||||||
);
|
);
|
||||||
|
void SendUserToWorldCancelOfflineRequest(
|
||||||
|
unsigned int server_id,
|
||||||
|
unsigned int client_account_id,
|
||||||
|
const std::string &client_loginserver
|
||||||
|
);
|
||||||
std::unique_ptr<EQApplicationPacket> CreateServerListPacket(Client *client, uint32 sequence);
|
std::unique_ptr<EQApplicationPacket> CreateServerListPacket(Client *client, uint32 sequence);
|
||||||
bool DoesServerExist(const std::string &s, const std::string &server_short_name, WorldServer *ignore = nullptr);
|
bool DoesServerExist(const std::string &s, const std::string &server_short_name, WorldServer *ignore = nullptr);
|
||||||
void DestroyServerByName(std::string s, std::string server_short_name, WorldServer *ignore = nullptr);
|
void DestroyServerByName(std::string s, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||||
|
|||||||
@@ -749,3 +749,6 @@ OP_ChangePetName=0x5dab
|
|||||||
|
|
||||||
OP_InvokeNameChangeImmediate=0x4fe2
|
OP_InvokeNameChangeImmediate=0x4fe2
|
||||||
OP_InvokeNameChangeLazy=0x2f2e
|
OP_InvokeNameChangeLazy=0x2f2e
|
||||||
|
|
||||||
|
#Offline Trading Mode
|
||||||
|
OP_Offline=0x53d3
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ set(world_sources
|
|||||||
cli/cli_database_concurrency.cpp
|
cli/cli_database_concurrency.cpp
|
||||||
cli/cli_database_dump.cpp
|
cli/cli_database_dump.cpp
|
||||||
cli/cli_database_get_schema.cpp
|
cli/cli_database_get_schema.cpp
|
||||||
|
cli/cli_database_item_unique_ids.cpp
|
||||||
cli/cli_database_set_account_status.cpp
|
cli/cli_database_set_account_status.cpp
|
||||||
cli/cli_database_updates.cpp
|
cli/cli_database_updates.cpp
|
||||||
cli/cli_database_version.cpp
|
cli/cli_database_version.cpp
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include "world/world_server_cli.h"
|
||||||
|
|
||||||
|
#include "world/worlddb.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
void WorldserverCLI::DatabaseItemUniqueIds(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||||
|
{
|
||||||
|
description = "Runs item_unique_id preflight, migration, and verification tasks";
|
||||||
|
|
||||||
|
std::vector<std::string> arguments = {};
|
||||||
|
std::vector<std::string> options = {
|
||||||
|
"--preflight",
|
||||||
|
"--migrate",
|
||||||
|
"--verify",
|
||||||
|
"--verbose",
|
||||||
|
"--keep-trading-state",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd[{"-h", "--help"}]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||||
|
|
||||||
|
const bool verbose = cmd[{"-v", "--verbose"}];
|
||||||
|
const bool migrate = cmd[{"--migrate"}];
|
||||||
|
const bool verify = cmd[{"--verify"}];
|
||||||
|
const bool preflight = cmd[{"--preflight"}] || (!migrate && !verify);
|
||||||
|
const bool clear_trading_state = !cmd[{"--keep-trading-state"}];
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (preflight) {
|
||||||
|
success = database.PreflightItemUniqueIdMigration(verbose) && success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrate) {
|
||||||
|
if (!database.MigrateItemUniqueIdData(clear_trading_state, verbose)) {
|
||||||
|
LogError("Item unique id migration failed verification");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verify) {
|
||||||
|
if (!database.VerifyItemUniqueIdMigration(verbose)) {
|
||||||
|
LogError("Item unique id verification failed");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -2403,7 +2403,7 @@ bool Client::StoreCharacter(
|
|||||||
e.ornament_icon = inst->GetOrnamentationIcon();
|
e.ornament_icon = inst->GetOrnamentationIcon();
|
||||||
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
e.ornament_idfile = inst->GetOrnamentationIDFile();
|
||||||
e.ornament_hero_model = inst->GetOrnamentHeroModel();
|
e.ornament_hero_model = inst->GetOrnamentHeroModel();
|
||||||
e.guid = inst->GetSerialNumber();
|
e.item_unique_id = inst->GetUniqueID();
|
||||||
|
|
||||||
v.emplace_back(e);
|
v.emplace_back(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,9 @@ void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, CLE_
|
|||||||
m_lfg = scl->LFG;
|
m_lfg = scl->LFG;
|
||||||
m_gm = scl->gm;
|
m_gm = scl->gm;
|
||||||
m_client_version = scl->ClientVersion;
|
m_client_version = scl->ClientVersion;
|
||||||
|
m_trader = scl->trader;
|
||||||
|
m_buyer = scl->buyer;
|
||||||
|
m_offline = scl->offline;
|
||||||
|
|
||||||
// Fields from the LFG Window
|
// Fields from the LFG Window
|
||||||
if ((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
|
if ((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
|
||||||
@@ -219,6 +222,10 @@ void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
|
|||||||
if (iZS != 0 && iZS != m_zone_server) {
|
if (iZS != 0 && iZS != m_zone_server) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_trader = false;
|
||||||
|
m_buyer = false;
|
||||||
|
m_offline = false;
|
||||||
SetOnline(iOnline);
|
SetOnline(iOnline);
|
||||||
|
|
||||||
SharedTaskManager::Instance()->RemoveActiveInvitationByCharacterID(CharID());
|
SharedTaskManager::Instance()->RemoveActiveInvitationByCharacterID(CharID());
|
||||||
@@ -260,6 +267,10 @@ void ClientListEntry::ClearVars(bool iAll)
|
|||||||
m_lfg = 0;
|
m_lfg = 0;
|
||||||
m_gm = 0;
|
m_gm = 0;
|
||||||
m_client_version = 0;
|
m_client_version = 0;
|
||||||
|
m_trader = false;
|
||||||
|
m_buyer = false;
|
||||||
|
m_offline = false;
|
||||||
|
|
||||||
for (auto &elem: m_tell_queue) {
|
for (auto &elem: m_tell_queue) {
|
||||||
safe_delete_array(elem);
|
safe_delete_array(elem);
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-21
@@ -13,7 +13,8 @@ typedef enum {
|
|||||||
Online,
|
Online,
|
||||||
CharSelect,
|
CharSelect,
|
||||||
Zoning,
|
Zoning,
|
||||||
InZone
|
InZone,
|
||||||
|
OfflineMode
|
||||||
} CLE_Status;
|
} CLE_Status;
|
||||||
|
|
||||||
static const char *CLEStatusString[] = {
|
static const char *CLEStatusString[] = {
|
||||||
@@ -22,7 +23,8 @@ static const char *CLEStatusString[] = {
|
|||||||
"Online",
|
"Online",
|
||||||
"CharSelect",
|
"CharSelect",
|
||||||
"Zoning",
|
"Zoning",
|
||||||
"InZone"
|
"InZone",
|
||||||
|
"OfflineMode"
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZoneServer;
|
class ZoneServer;
|
||||||
@@ -102,6 +104,10 @@ public:
|
|||||||
inline bool GetLFGMatchFilter() const { return m_lfg_match_filter; }
|
inline bool GetLFGMatchFilter() const { return m_lfg_match_filter; }
|
||||||
inline const char *GetLFGComments() const { return m_lfg_comments; }
|
inline const char *GetLFGComments() const { return m_lfg_comments; }
|
||||||
inline uint8 GetClientVersion() { return m_client_version; }
|
inline uint8 GetClientVersion() { return m_client_version; }
|
||||||
|
bool GetTrader() const { return m_trader; }
|
||||||
|
bool GetBuyer() const { return m_buyer; }
|
||||||
|
bool GetOfflineMode() const { return m_offline; }
|
||||||
|
void SetOfflineMode(bool status) { m_offline = status; }
|
||||||
|
|
||||||
inline bool TellQueueFull() const { return m_tell_queue.size() >= RuleI(World, TellQueueSize); }
|
inline bool TellQueueFull() const { return m_tell_queue.size() >= RuleI(World, TellQueueSize); }
|
||||||
inline bool TellQueueEmpty() const { return m_tell_queue.empty(); }
|
inline bool TellQueueEmpty() const { return m_tell_queue.empty(); }
|
||||||
@@ -134,25 +140,28 @@ private:
|
|||||||
|
|
||||||
// Character info
|
// Character info
|
||||||
ZoneServer *m_zone_server{};
|
ZoneServer *m_zone_server{};
|
||||||
uint32 m_zone{};
|
uint32 m_zone{};
|
||||||
uint16 m_instance{};
|
uint16 m_instance{};
|
||||||
uint32 m_char_id{};
|
uint32 m_char_id{};
|
||||||
char m_char_name[64]{};
|
char m_char_name[64]{};
|
||||||
uint8 m_level{};
|
uint8 m_level{};
|
||||||
uint8 m_class_{};
|
uint8 m_class_{};
|
||||||
uint16 m_race{};
|
uint16 m_race{};
|
||||||
uint8 m_anon{};
|
uint8 m_anon{};
|
||||||
uint8 m_tells_off{};
|
uint8 m_tells_off{};
|
||||||
uint32 m_guild_id{};
|
uint32 m_guild_id{};
|
||||||
uint32 m_guild_rank;
|
uint32 m_guild_rank;
|
||||||
bool m_guild_tribute_opt_in{};
|
bool m_guild_tribute_opt_in{};
|
||||||
bool m_lfg{};
|
bool m_lfg{};
|
||||||
uint8 m_gm{};
|
uint8 m_gm{};
|
||||||
uint8 m_client_version{};
|
uint8 m_client_version{};
|
||||||
uint8 m_lfg_from_level{};
|
uint8 m_lfg_from_level{};
|
||||||
uint8 m_lfg_to_level{};
|
uint8 m_lfg_to_level{};
|
||||||
bool m_lfg_match_filter{};
|
bool m_lfg_match_filter{};
|
||||||
char m_lfg_comments[64]{};
|
char m_lfg_comments[64]{};
|
||||||
|
bool m_trader = false;
|
||||||
|
bool m_buyer = false;
|
||||||
|
bool m_offline = false;
|
||||||
|
|
||||||
// Tell Queue -- really a vector :D
|
// Tell Queue -- really a vector :D
|
||||||
std::vector<ServerChannelMessage_Struct *> m_tell_queue;
|
std::vector<ServerChannelMessage_Struct *> m_tell_queue;
|
||||||
|
|||||||
+59
-22
@@ -35,6 +35,7 @@
|
|||||||
#include "world/zoneserver.h"
|
#include "world/zoneserver.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include "../zone/string_ids.h"
|
||||||
|
|
||||||
uint32 numplayers = 0; //this really wants to be a member variable of ClientList...
|
uint32 numplayers = 0; //this really wants to be a member variable of ClientList...
|
||||||
|
|
||||||
@@ -427,7 +428,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
|
|||||||
while (iterator.MoreElements()) {
|
while (iterator.MoreElements()) {
|
||||||
if (iterator.GetData()->GetID() == scl->wid) {
|
if (iterator.GetData()->GetID() == scl->wid) {
|
||||||
cle = iterator.GetData();
|
cle = iterator.GetData();
|
||||||
if (scl->remove == 2) {
|
if (scl->remove == 3) {
|
||||||
|
cle->Update(zoneserver, scl, CLE_Status::OfflineMode);
|
||||||
|
}
|
||||||
|
else if (scl->remove == 2) {
|
||||||
cle->LeavingZone(zoneserver, CLE_Status::Offline);
|
cle->LeavingZone(zoneserver, CLE_Status::Offline);
|
||||||
}
|
}
|
||||||
else if (scl->remove == 1) {
|
else if (scl->remove == 1) {
|
||||||
@@ -441,7 +445,11 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
|
|||||||
}
|
}
|
||||||
iterator.Advance();
|
iterator.Advance();
|
||||||
}
|
}
|
||||||
if (scl->remove == 2) {
|
|
||||||
|
if (scl->remove == 3) {
|
||||||
|
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::OfflineMode);
|
||||||
|
}
|
||||||
|
else if (scl->remove == 2) {
|
||||||
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Online);
|
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Online);
|
||||||
}
|
}
|
||||||
else if (scl->remove == 1) {
|
else if (scl->remove == 1) {
|
||||||
@@ -479,7 +487,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
|
|||||||
" LFGFromLevel [{}]"
|
" LFGFromLevel [{}]"
|
||||||
" LFGToLevel [{}]"
|
" LFGToLevel [{}]"
|
||||||
" LFGMatchFilter [{}]"
|
" LFGMatchFilter [{}]"
|
||||||
" LFGComments [{}]",
|
" LFGComments [{}]"
|
||||||
|
" Trader [{}]"
|
||||||
|
" Buyer [{}]"
|
||||||
|
" Offline [{}]",
|
||||||
scl->remove,
|
scl->remove,
|
||||||
scl->wid,
|
scl->wid,
|
||||||
scl->IP,
|
scl->IP,
|
||||||
@@ -506,7 +517,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
|
|||||||
scl->LFGFromLevel,
|
scl->LFGFromLevel,
|
||||||
scl->LFGToLevel,
|
scl->LFGToLevel,
|
||||||
scl->LFGMatchFilter,
|
scl->LFGMatchFilter,
|
||||||
scl->LFGComments
|
scl->LFGComments,
|
||||||
|
scl->trader,
|
||||||
|
scl->buyer,
|
||||||
|
scl->offline
|
||||||
);
|
);
|
||||||
|
|
||||||
clientlist.Insert(cle);
|
clientlist.Insert(cle);
|
||||||
@@ -784,7 +798,14 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
|
|||||||
rankstring = 0;
|
rankstring = 0;
|
||||||
iterator.Advance();
|
iterator.Advance();
|
||||||
continue;
|
continue;
|
||||||
} else if (cle->GetGM()) {
|
}
|
||||||
|
else if (cle->GetTrader()) {
|
||||||
|
rankstring = TRADER;
|
||||||
|
}
|
||||||
|
else if (cle->GetBuyer()) {
|
||||||
|
rankstring = BUYER;
|
||||||
|
}
|
||||||
|
else if (cle->GetGM()) {
|
||||||
if (cle->Admin() >= AccountStatus::GMImpossible) {
|
if (cle->Admin() >= AccountStatus::GMImpossible) {
|
||||||
rankstring = 5021;
|
rankstring = 5021;
|
||||||
} else if (cle->Admin() >= AccountStatus::GMMgmt) {
|
} else if (cle->Admin() >= AccountStatus::GMMgmt) {
|
||||||
@@ -877,6 +898,18 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
|
|||||||
strcpy(placcount,cle->AccountName());
|
strcpy(placcount,cle->AccountName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cle->GetOfflineMode()) {
|
||||||
|
if (cle->GetTrader()) {
|
||||||
|
pidstring = 0x0430;
|
||||||
|
rankstring = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cle->GetBuyer()) {
|
||||||
|
pidstring = 0x0420;
|
||||||
|
rankstring = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(bufptr,&formatstring, sizeof(uint32));
|
memcpy(bufptr,&formatstring, sizeof(uint32));
|
||||||
bufptr+=sizeof(uint32);
|
bufptr+=sizeof(uint32);
|
||||||
memcpy(bufptr,&pidstring, sizeof(uint32));
|
memcpy(bufptr,&pidstring, sizeof(uint32));
|
||||||
@@ -1631,25 +1664,29 @@ void ClientList::OnTick(EQ::Timer *t)
|
|||||||
outclient["Server"] = Json::Value();
|
outclient["Server"] = Json::Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
outclient["CharID"] = cle->CharID();
|
outclient["CharID"] = cle->CharID();
|
||||||
outclient["name"] = cle->name();
|
outclient["name"] = cle->name();
|
||||||
outclient["zone"] = cle->zone();
|
outclient["zone"] = cle->zone();
|
||||||
outclient["instance"] = cle->instance();
|
outclient["instance"] = cle->instance();
|
||||||
outclient["level"] = cle->level();
|
outclient["level"] = cle->level();
|
||||||
outclient["class_"] = cle->class_();
|
outclient["class_"] = cle->class_();
|
||||||
outclient["race"] = cle->race();
|
outclient["race"] = cle->race();
|
||||||
outclient["Anon"] = cle->Anon();
|
outclient["Anon"] = cle->Anon();
|
||||||
|
|
||||||
outclient["TellsOff"] = cle->TellsOff();
|
outclient["TellsOff"] = cle->TellsOff();
|
||||||
outclient["GuildID"] = cle->GuildID();
|
outclient["GuildID"] = cle->GuildID();
|
||||||
outclient["LFG"] = cle->LFG();
|
outclient["LFG"] = cle->LFG();
|
||||||
outclient["GM"] = cle->GetGM();
|
outclient["GM"] = cle->GetGM();
|
||||||
outclient["LocalClient"] = cle->IsLocalClient();
|
outclient["LocalClient"] = cle->IsLocalClient();
|
||||||
outclient["LFGFromLevel"] = cle->GetLFGFromLevel();
|
outclient["LFGFromLevel"] = cle->GetLFGFromLevel();
|
||||||
outclient["LFGToLevel"] = cle->GetLFGToLevel();
|
outclient["LFGToLevel"] = cle->GetLFGToLevel();
|
||||||
outclient["LFGMatchFilter"] = cle->GetLFGMatchFilter();
|
outclient["LFGMatchFilter"] = cle->GetLFGMatchFilter();
|
||||||
outclient["LFGComments"] = cle->GetLFGComments();
|
outclient["LFGComments"] = cle->GetLFGComments();
|
||||||
outclient["ClientVersion"] = cle->GetClientVersion();
|
outclient["ClientVersion"] = cle->GetClientVersion();
|
||||||
|
outclient["Trader"] = cle->GetTrader();
|
||||||
|
outclient["Buyer"] = cle->GetBuyer();
|
||||||
|
outclient["OfflineMode"] = cle->GetOfflineMode();
|
||||||
|
|
||||||
out["data"].append(outclient);
|
out["data"].append(outclient);
|
||||||
|
|
||||||
Iterator.Advance();
|
Iterator.Advance();
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const
|
|||||||
const std::string& account_name = database.GetAccountName(ret.account_id);
|
const std::string& account_name = database.GetAccountName(ret.account_id);
|
||||||
|
|
||||||
ret.account_name = account_name;
|
ret.account_name = account_name;
|
||||||
ret.status = database.GetAccountStatus(ret.account_id);
|
ret.status = database.GetAccountStatus(ret.account_id).status;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+141
-11
@@ -4,6 +4,11 @@
|
|||||||
#include "common/eqemu_logsys.h"
|
#include "common/eqemu_logsys.h"
|
||||||
#include "common/misc_functions.h"
|
#include "common/misc_functions.h"
|
||||||
#include "common/packet_dump.h"
|
#include "common/packet_dump.h"
|
||||||
|
#include "common/repositories/account_repository.h"
|
||||||
|
#include "common/repositories/buyer_repository.h"
|
||||||
|
#include "common/repositories/character_data_repository.h"
|
||||||
|
#include "common/repositories/offline_character_sessions_repository.h"
|
||||||
|
#include "common/repositories/trader_repository.h"
|
||||||
#include "common/servertalk.h"
|
#include "common/servertalk.h"
|
||||||
#include "common/strings.h"
|
#include "common/strings.h"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
@@ -43,9 +48,9 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
const WorldConfig *Config = WorldConfig::get();
|
const WorldConfig *Config = WorldConfig::get();
|
||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
UsertoWorldRequestLegacy *utwr = (UsertoWorldRequestLegacy *) p.Data();
|
UsertoWorldRequestLegacy *utwr = (UsertoWorldRequestLegacy *) p.Data();
|
||||||
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
|
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
|
||||||
int16 status = database.GetAccountStatus(id);
|
int16 status = database.GetAccountStatus(id).status;
|
||||||
|
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
||||||
@@ -123,14 +128,19 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
const WorldConfig *Config = WorldConfig::get();
|
const WorldConfig *Config = WorldConfig::get();
|
||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
UsertoWorldRequest *utwr = (UsertoWorldRequest *) p.Data();
|
UsertoWorldRequest *utwr = (UsertoWorldRequest *) p.Data();
|
||||||
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
||||||
int16 status = database.GetAccountStatus(id);
|
auto status_record = database.GetAccountStatus(id);
|
||||||
|
auto client = ClientList::Instance()->FindCLEByAccountID(id);
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
client->SetOfflineMode(status_record.offline);
|
||||||
|
}
|
||||||
|
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
||||||
id,
|
id,
|
||||||
status,
|
status_record.status,
|
||||||
utwr->lsaccountid,
|
utwr->lsaccountid,
|
||||||
utwr->worldid,
|
utwr->worldid,
|
||||||
utwr->FromID,
|
utwr->FromID,
|
||||||
@@ -152,7 +162,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
utwrs->response = UserToWorldStatusSuccess;
|
utwrs->response = UserToWorldStatusSuccess;
|
||||||
|
|
||||||
if (Config->Locked == true) {
|
if (Config->Locked == true) {
|
||||||
if (status < (RuleI(GM, MinStatusToBypassLockedServer))) {
|
if (status_record.status < (RuleI(GM, MinStatusToBypassLockedServer))) {
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"Server locked and status is not high enough for account_id [{0}]",
|
"Server locked and status is not high enough for account_id [{0}]",
|
||||||
utwr->lsaccountid
|
utwr->lsaccountid
|
||||||
@@ -164,27 +174,34 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32 x = Config->MaxClients;
|
int32 x = Config->MaxClients;
|
||||||
if ((int32) numplayers >= x && x != -1 && x != 255 && status < (RuleI(GM, MinStatusToBypassLockedServer))) {
|
if ((int32) numplayers >= x && x != -1 && x != 255 && status_record.status < (RuleI(GM, MinStatusToBypassLockedServer))) {
|
||||||
LogDebug("World at capacity account_id [{0}]", utwr->lsaccountid);
|
LogDebug("World at capacity account_id [{0}]", utwr->lsaccountid);
|
||||||
utwrs->response = UserToWorldStatusWorldAtCapacity;
|
utwrs->response = UserToWorldStatusWorldAtCapacity;
|
||||||
SendPacket(&outpack);
|
SendPacket(&outpack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == -1) {
|
if (status_record.status == -1) {
|
||||||
LogDebug("User suspended account_id [{0}]", utwr->lsaccountid);
|
LogDebug("User suspended account_id [{0}]", utwr->lsaccountid);
|
||||||
utwrs->response = UserToWorldStatusSuspended;
|
utwrs->response = UserToWorldStatusSuspended;
|
||||||
SendPacket(&outpack);
|
SendPacket(&outpack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == -2) {
|
if (status_record.status == -2) {
|
||||||
LogDebug("User banned account_id [{0}]", utwr->lsaccountid);
|
LogDebug("User banned account_id [{0}]", utwr->lsaccountid);
|
||||||
utwrs->response = UserToWorldStatusBanned;
|
utwrs->response = UserToWorldStatusBanned;
|
||||||
SendPacket(&outpack);
|
SendPacket(&outpack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status_record.offline || OfflineCharacterSessionsRepository::ExistsByAccountId(database, id)) {
|
||||||
|
LogDebug("User has an offline character for account_id [{0}]", utwr->lsaccountid);
|
||||||
|
utwrs->response = UserToWorldStatusOffilineTraderBuyer;
|
||||||
|
SendPacket(&outpack);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (RuleB(World, EnforceCharacterLimitAtLogin)) {
|
if (RuleB(World, EnforceCharacterLimitAtLogin)) {
|
||||||
if (ClientList::Instance()->IsAccountInGame(utwr->lsaccountid)) {
|
if (ClientList::Instance()->IsAccountInGame(utwr->lsaccountid)) {
|
||||||
LogDebug("User already online account_id [{0}]", utwr->lsaccountid);
|
LogDebug("User already online account_id [{0}]", utwr->lsaccountid);
|
||||||
@@ -572,6 +589,14 @@ bool LoginServer::Connect()
|
|||||||
std::placeholders::_2
|
std::placeholders::_2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
m_client->OnMessage(
|
||||||
|
ServerOP_UsertoWorldCancelOfflineRequest,
|
||||||
|
std::bind(
|
||||||
|
&LoginServer::ProcessUserToWorldCancelOfflineRequest,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -687,3 +712,108 @@ void LoginServer::SendAccountUpdate(ServerPacket *pack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoginServer::ProcessUserToWorldCancelOfflineRequest(uint16_t opcode, EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
auto const Config = WorldConfig::get();
|
||||||
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
|
auto utwr = static_cast<UsertoWorldRequest *>(p.Data());
|
||||||
|
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
||||||
|
auto status_record = database.GetAccountStatus(id);
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 4 - World received CancelOfflineRequest for client login server account id {} offline mode {}",
|
||||||
|
id,
|
||||||
|
status_record.offline
|
||||||
|
);
|
||||||
|
LogDebug(
|
||||||
|
"id [{}] status [{}] account_id [{}] world_id [{}] ip [{}]",
|
||||||
|
id,
|
||||||
|
status_record.status,
|
||||||
|
utwr->lsaccountid,
|
||||||
|
utwr->worldid,
|
||||||
|
utwr->IPAddr
|
||||||
|
);
|
||||||
|
|
||||||
|
ServerPacket server_packet;
|
||||||
|
server_packet.size = sizeof(UsertoWorldResponse);
|
||||||
|
server_packet.pBuffer = new uchar[server_packet.size];
|
||||||
|
memset(server_packet.pBuffer, 0, server_packet.size);
|
||||||
|
|
||||||
|
auto utwrs = reinterpret_cast<UsertoWorldResponse *>(server_packet.pBuffer);
|
||||||
|
utwrs->lsaccountid = utwr->lsaccountid;
|
||||||
|
utwrs->ToID = utwr->FromID;
|
||||||
|
utwrs->worldid = utwr->worldid;
|
||||||
|
utwrs->response = UserToWorldStatusSuccess;
|
||||||
|
strn0cpy(utwrs->login, utwr->login, 64);
|
||||||
|
|
||||||
|
if (Config->Locked == true) {
|
||||||
|
if (status_record.status < RuleI(GM, MinStatusToBypassLockedServer)) {
|
||||||
|
LogDebug("Server locked and status is not high enough for account_id [{0}]", utwr->lsaccountid);
|
||||||
|
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
utwrs->response = UserToWorldStatusWorldUnavail;
|
||||||
|
SendPacket(&server_packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 x = Config->MaxClients;
|
||||||
|
if (static_cast<int32>(numplayers) >= x &&
|
||||||
|
x != -1 &&
|
||||||
|
x != 255 &&
|
||||||
|
status_record.status < RuleI(GM, MinStatusToBypassLockedServer)
|
||||||
|
) {
|
||||||
|
LogDebug("World at capacity account_id [{0}]", utwr->lsaccountid);
|
||||||
|
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
utwrs->response = UserToWorldStatusWorldAtCapacity;
|
||||||
|
SendPacket(&server_packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto session = OfflineCharacterSessionsRepository::GetByAccountId(database, id);
|
||||||
|
auto trader = TraderRepository::GetAccountZoneIdAndInstanceIdByAccountId(database, id);
|
||||||
|
uint32 zone_id = session.id ? session.zone_id : trader.char_zone_id;
|
||||||
|
int32 instance_id = session.id ? session.instance_id : trader.char_zone_instance_id;
|
||||||
|
uint32 character_id = session.id ? session.character_id : trader.character_id;
|
||||||
|
|
||||||
|
if ((session.id || trader.id) &&
|
||||||
|
ZSList::Instance()->IsZoneBootedByZoneIdAndInstanceId(zone_id, instance_id)) {
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 5a(1) - World Checked offline users zone/instance is booted. "
|
||||||
|
"Sending packet to zone id {} instance id {}",
|
||||||
|
zone_id,
|
||||||
|
instance_id);
|
||||||
|
|
||||||
|
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineRequest;
|
||||||
|
ZSList::Instance()->SendPacketToBootedZones(&server_packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 5b(1) - World determined offline users zone/instance is not booted. Ignoring zone.");
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 5b(2) - World clearing users offline status from account table.");
|
||||||
|
database.TransactionBegin();
|
||||||
|
AccountRepository::SetOfflineStatus(database, id, false);
|
||||||
|
OfflineCharacterSessionsRepository::DeleteByAccountId(database, id);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 5b(3) - World clearing trader and buyer tables.");
|
||||||
|
if (character_id) {
|
||||||
|
TraderRepository::DeleteWhere(database, fmt::format("`character_id` = '{}'", character_id));
|
||||||
|
BuyerRepository::DeleteBuyer(database, character_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto commit_result = database.TransactionCommit();
|
||||||
|
if (!commit_result.Success()) {
|
||||||
|
database.TransactionRollback();
|
||||||
|
LogError(
|
||||||
|
"Failed clearing offline session state for account [{}]: ({}) {}",
|
||||||
|
id,
|
||||||
|
commit_result.ErrorNumber(),
|
||||||
|
commit_result.ErrorMessage()
|
||||||
|
);
|
||||||
|
utwrs->response = UserToWorldStatusWorldUnavail;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
SendPacket(&server_packet);
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ private:
|
|||||||
void ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p);
|
void ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
void ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p);
|
void ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
void ProcessLSAccountUpdate(uint16_t opcode, EQ::Net::Packet &p);
|
void ProcessLSAccountUpdate(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
|
void ProcessUserToWorldCancelOfflineRequest(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
|
|
||||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||||
|
|
||||||
|
|||||||
@@ -634,4 +634,3 @@ void WorldBoot::SendDiscordMessage(int webhook_id, const std::string &message)
|
|||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ void WorldserverCLI::CommandHandler(int argc, char **argv)
|
|||||||
function_map["database:schema"] = &WorldserverCLI::DatabaseGetSchema;
|
function_map["database:schema"] = &WorldserverCLI::DatabaseGetSchema;
|
||||||
function_map["database:dump"] = &WorldserverCLI::DatabaseDump;
|
function_map["database:dump"] = &WorldserverCLI::DatabaseDump;
|
||||||
function_map["database:updates"] = &WorldserverCLI::DatabaseUpdates;
|
function_map["database:updates"] = &WorldserverCLI::DatabaseUpdates;
|
||||||
|
function_map["database:item-unique-ids"] = &WorldserverCLI::DatabaseItemUniqueIds;
|
||||||
function_map["test:test"] = &WorldserverCLI::TestCommand;
|
function_map["test:test"] = &WorldserverCLI::TestCommand;
|
||||||
function_map["test:colors"] = &WorldserverCLI::TestColors;
|
function_map["test:colors"] = &WorldserverCLI::TestColors;
|
||||||
function_map["test:expansion"] = &WorldserverCLI::ExpansionTestCommand;
|
function_map["test:expansion"] = &WorldserverCLI::ExpansionTestCommand;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public:
|
|||||||
static void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
static void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
static void DatabaseUpdates(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void DatabaseUpdates(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
|
static void DatabaseItemUniqueIds(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
static void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
static void TestColors(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void TestColors(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
static void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
|
static void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
|
|||||||
+1
-1
@@ -876,7 +876,7 @@ bool WorldDatabase::GetCharSelInventory(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::ItemInstance *inst = content_db.CreateBaseItem(item, e.charges);
|
EQ::ItemInstance *inst = content_db.CreateBaseItem(item, e.charges, e.item_unique_id);
|
||||||
|
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1019,3 +1019,15 @@ void ZSList::QueueServerReload(ServerReload::Type &type)
|
|||||||
m_queued_reloads.emplace_back(type);
|
m_queued_reloads.emplace_back(type);
|
||||||
m_queued_reloads_mutex.unlock();
|
m_queued_reloads_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZSList::IsZoneBootedByZoneIdAndInstanceId(uint32 zone_id, uint32 instance_id) const
|
||||||
|
{
|
||||||
|
for (auto const& z : zone_server_list) {
|
||||||
|
auto r = z.get();
|
||||||
|
if (r && r->GetZoneID() == zone_id && r->GetInstanceID() == instance_id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public:
|
|||||||
bool SendPacketToZonesWithGMs(ServerPacket *pack);
|
bool SendPacketToZonesWithGMs(ServerPacket *pack);
|
||||||
bool SendPacketToBootedZones(ServerPacket* pack);
|
bool SendPacketToBootedZones(ServerPacket* pack);
|
||||||
bool SetLockedZone(uint16 iZoneID, bool iLock);
|
bool SetLockedZone(uint16 iZoneID, bool iLock);
|
||||||
|
bool IsZoneBootedByZoneIdAndInstanceId(uint32 zone_id, uint32 instance_id) const;
|
||||||
|
|
||||||
EQTime worldclock;
|
EQTime worldclock;
|
||||||
|
|
||||||
|
|||||||
+43
-16
@@ -1675,21 +1675,23 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_BazaarPurchase: {
|
case ServerOP_BazaarPurchase: {
|
||||||
auto in = (BazaarPurchaseMessaging_Struct *)pack->pBuffer;
|
auto in = reinterpret_cast<BazaarPurchaseMessaging_Struct *>(pack->pBuffer);
|
||||||
if (in->trader_buy_struct.trader_id <= 0) {
|
switch (in->transaction_status) {
|
||||||
LogTrading(
|
case BazaarPurchaseBuyerCompleteSendToSeller: {
|
||||||
"World Message <red>[{}] received with invalid trader_id <red>[{}]",
|
ZSList::Instance()->SendPacket(in->trader_zone_id, in->trader_zone_instance_id, pack);
|
||||||
"ServerOP_BazaarPurchase",
|
break;
|
||||||
in->trader_buy_struct.trader_id
|
}
|
||||||
);
|
case BazaarPurchaseTraderFailed:
|
||||||
return;
|
case BazaarPurchaseSuccess: {
|
||||||
|
ZSList::Instance()->SendPacket(in->buyer_zone_id, in->buyer_zone_instance_id, pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogError(
|
||||||
|
"ServerOP_BazaarPurchase received with no corresponding action for [{}]",
|
||||||
|
in->transaction_status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto trader = ClientList::Instance()->FindCLEByCharacterID(in->trader_buy_struct.trader_id);
|
|
||||||
if (trader) {
|
|
||||||
ZSList::Instance()->SendPacket(trader->zone(), trader->instance(), pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_BuyerMessaging: {
|
case ServerOP_BuyerMessaging: {
|
||||||
@@ -1725,9 +1727,34 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_UsertoWorldCancelOfflineResponse: {
|
||||||
|
auto utwr = reinterpret_cast<UsertoWorldResponse *>(pack->pBuffer);
|
||||||
|
|
||||||
|
ServerPacket server_packet;
|
||||||
|
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
server_packet.size = sizeof(UsertoWorldResponse);
|
||||||
|
server_packet.pBuffer = new uchar[server_packet.size];
|
||||||
|
memset(server_packet.pBuffer, 0, server_packet.size);
|
||||||
|
|
||||||
|
auto utwrs = reinterpret_cast<UsertoWorldResponse *>(server_packet.pBuffer);
|
||||||
|
utwrs->lsaccountid = utwr->lsaccountid;
|
||||||
|
utwrs->ToID = utwr->FromID;
|
||||||
|
utwrs->worldid = utwr->worldid;
|
||||||
|
utwrs->response = UserToWorldStatusSuccess;
|
||||||
|
strn0cpy(utwrs->login, utwr->login, 64);
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 7a - World received ServerOP_UsertoWorldCancelOfflineResponse back to login with success."
|
||||||
|
);
|
||||||
|
|
||||||
|
LoginServerList::Instance()->SendPacket(&server_packet);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin(
|
|||||||
|
|
||||||
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
|
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
|
||||||
ret.logged_in = true;
|
ret.logged_in = true;
|
||||||
ret.status = database.GetAccountStatus(ret.account_id);
|
ret.status = database.GetAccountStatus(ret.account_id).status;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-27
@@ -498,10 +498,10 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
|||||||
client_data_loaded = false;
|
client_data_loaded = false;
|
||||||
berserk = false;
|
berserk = false;
|
||||||
dead = false;
|
dead = false;
|
||||||
eqs = ieqs;
|
eqs = ieqs ? ieqs : nullptr;
|
||||||
ip = eqs->GetRemoteIP();
|
ip = eqs ? eqs->GetRemoteIP() : 0;
|
||||||
port = ntohs(eqs->GetRemotePort());
|
port = eqs ? ntohs(eqs->GetRemotePort()) : 0;
|
||||||
client_state = CLIENT_CONNECTING;
|
client_state = eqs ? CLIENT_CONNECTING : CLIENT_CONNECTED;
|
||||||
SetTrader(false);
|
SetTrader(false);
|
||||||
Haste = 0;
|
Haste = 0;
|
||||||
SetCustomerID(0);
|
SetCustomerID(0);
|
||||||
@@ -688,6 +688,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
|||||||
m_parcels.clear();
|
m_parcels.clear();
|
||||||
|
|
||||||
m_buyer_id = 0;
|
m_buyer_id = 0;
|
||||||
|
m_offline = false;
|
||||||
|
|
||||||
SetBotPulling(false);
|
SetBotPulling(false);
|
||||||
SetBotPrecombat(false);
|
SetBotPrecombat(false);
|
||||||
@@ -716,10 +717,12 @@ Client::~Client() {
|
|||||||
zone->ClearEXPModifier(this);
|
zone->ClearEXPModifier(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsZoning()) {
|
if (!IsZoning() && IsInAGuild()) {
|
||||||
if(IsInAGuild()) {
|
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
if (IsOffline()) {
|
||||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), GetZoneID(), time(nullptr), 1);
|
||||||
|
} else {
|
||||||
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,11 +734,11 @@ Client::~Client() {
|
|||||||
if (merc)
|
if (merc)
|
||||||
merc->Depop();
|
merc->Depop();
|
||||||
|
|
||||||
if(IsTrader()) {
|
if(IsTrader() && !IsOffline()) {
|
||||||
TraderEndTrader();
|
TraderEndTrader();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsBuyer()) {
|
if(IsBuyer() && !IsOffline()) {
|
||||||
ToggleBuyerMode(false);
|
ToggleBuyerMode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,7 +770,9 @@ Client::~Client() {
|
|||||||
if(isgrouped && !bZoning && is_zone_loaded)
|
if(isgrouped && !bZoning && is_zone_loaded)
|
||||||
LeaveGroup();
|
LeaveGroup();
|
||||||
|
|
||||||
UpdateWho(2);
|
if (!IsOffline() && !IsTrader()) {
|
||||||
|
UpdateWho(2);
|
||||||
|
}
|
||||||
|
|
||||||
if(IsHoveringForRespawn())
|
if(IsHoveringForRespawn())
|
||||||
{
|
{
|
||||||
@@ -2143,6 +2148,9 @@ void Client::UpdateWho(uint8 remove)
|
|||||||
s->race = GetRace();
|
s->race = GetRace();
|
||||||
s->class_ = GetClass();
|
s->class_ = GetClass();
|
||||||
s->level = GetLevel();
|
s->level = GetLevel();
|
||||||
|
s->trader = IsTrader();
|
||||||
|
s->buyer = IsBuyer();
|
||||||
|
s->offline = IsOffline();
|
||||||
|
|
||||||
if (m_pp.anon == 0) {
|
if (m_pp.anon == 0) {
|
||||||
s->anon = 0;
|
s->anon = 0;
|
||||||
@@ -2211,7 +2219,7 @@ void Client::FriendsWho(char *FriendsString) {
|
|||||||
void Client::UpdateAdmin(bool from_database) {
|
void Client::UpdateAdmin(bool from_database) {
|
||||||
int16 tmp = admin;
|
int16 tmp = admin;
|
||||||
if (from_database) {
|
if (from_database) {
|
||||||
admin = database.GetAccountStatus(account_id);
|
admin = database.GetAccountStatus(account_id).status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp == admin && from_database) {
|
if (tmp == admin && from_database) {
|
||||||
@@ -2527,6 +2535,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.guildID = GuildID();
|
ns->spawn.guildID = GuildID();
|
||||||
ns->spawn.trader = IsTrader();
|
ns->spawn.trader = IsTrader();
|
||||||
ns->spawn.buyer = IsBuyer();
|
ns->spawn.buyer = IsBuyer();
|
||||||
|
ns->spawn.offline = IsOffline();
|
||||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||||
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
||||||
ns->spawn.show_name = true;
|
ns->spawn.show_name = true;
|
||||||
@@ -9043,11 +9052,11 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac
|
|||||||
|
|
||||||
void Client::CashReward(uint32 copper, uint32 silver, uint32 gold, uint32 platinum)
|
void Client::CashReward(uint32 copper, uint32 silver, uint32 gold, uint32 platinum)
|
||||||
{
|
{
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_CashReward, sizeof(CashReward_Struct));
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_CashReward, static_cast<uint32>(sizeof(CashReward_Struct)));
|
||||||
auto outbuf = reinterpret_cast<CashReward_Struct *>(outapp->pBuffer);
|
auto outbuf = reinterpret_cast<CashReward_Struct *>(outapp->pBuffer);
|
||||||
outbuf->copper = copper;
|
outbuf->copper = copper;
|
||||||
outbuf->silver = silver;
|
outbuf->silver = silver;
|
||||||
outbuf->gold = gold;
|
outbuf->gold = gold;
|
||||||
outbuf->platinum = platinum;
|
outbuf->platinum = platinum;
|
||||||
|
|
||||||
AddMoneyToPP(copper, silver, gold, platinum);
|
AddMoneyToPP(copper, silver, gold, platinum);
|
||||||
@@ -12689,13 +12698,11 @@ uint16 Client::GetSkill(EQ::skills::SkillType skill_id) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
|
bool Client::RemoveItemByItemUniqueId(const std::string &item_unique_id, uint32 quantity)
|
||||||
{
|
{
|
||||||
EQ::ItemInstance *item = nullptr;
|
EQ::ItemInstance *item = nullptr;
|
||||||
|
uint32 removed_count = 0;
|
||||||
uint32 removed_count = 0;
|
const auto &slot_ids = GetInventorySlots();
|
||||||
|
|
||||||
const auto& slot_ids = GetInventorySlots();
|
|
||||||
|
|
||||||
for (const int16& slot_id : slot_ids) {
|
for (const int16& slot_id : slot_ids) {
|
||||||
if (removed_count == quantity) {
|
if (removed_count == quantity) {
|
||||||
@@ -12703,21 +12710,27 @@ void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
|
|||||||
}
|
}
|
||||||
|
|
||||||
item = GetInv().GetItem(slot_id);
|
item = GetInv().GetItem(slot_id);
|
||||||
if (item && item->GetSerialNumber() == serial_number) {
|
if (item && item->GetUniqueID().compare(item_unique_id) == 0) {
|
||||||
uint32 charges = item->IsStackable() ? item->GetCharges() : 0;
|
uint32 charges = item->IsStackable() ? item->GetCharges() : 0;
|
||||||
uint32 stack_size = std::max(charges, static_cast<uint32>(1));
|
uint32 stack_size = std::max(charges, static_cast<uint32>(1));
|
||||||
if ((removed_count + stack_size) <= quantity) {
|
if (removed_count + stack_size <= quantity) {
|
||||||
removed_count += stack_size;
|
removed_count += stack_size;
|
||||||
DeleteItemInInventory(slot_id, charges, true);
|
if (DeleteItemInInventory(slot_id, charges, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32 amount_left = (quantity - removed_count);
|
uint32 amount_left = quantity - removed_count;
|
||||||
if (amount_left > 0 && stack_size >= amount_left) {
|
if (amount_left > 0 && stack_size >= amount_left) {
|
||||||
removed_count += amount_left;
|
removed_count += amount_left;
|
||||||
DeleteItemInInventory(slot_id, amount_left, true);
|
if (DeleteItemInInventory(slot_id, amount_left, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendTopLevelInventory()
|
void Client::SendTopLevelInventory()
|
||||||
|
|||||||
+98
-16
@@ -303,7 +303,7 @@ public:
|
|||||||
void Trader_CustomerBrowsing(Client *Customer);
|
void Trader_CustomerBrowsing(Client *Customer);
|
||||||
|
|
||||||
void TraderEndTrader();
|
void TraderEndTrader();
|
||||||
void TraderPriceUpdate(const EQApplicationPacket *app);
|
void TraderUpdateItem(const EQApplicationPacket *app);
|
||||||
void SendBazaarDone(uint32 trader_id);
|
void SendBazaarDone(uint32 trader_id);
|
||||||
void SendBulkBazaarTraders();
|
void SendBulkBazaarTraders();
|
||||||
void SendBulkBazaarBuyers();
|
void SendBulkBazaarBuyers();
|
||||||
@@ -340,7 +340,7 @@ public:
|
|||||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||||
void SendBuyerPacket(Client* Buyer);
|
void SendBuyerPacket(Client* Buyer);
|
||||||
void SendBuyerToBarterWindow(Client* buyer, uint32 action);
|
void SendBuyerToBarterWindow(Client* buyer, uint32 action);
|
||||||
GetItems_Struct* GetTraderItems();
|
GetBazaarItems_Struct* GetTraderItems();
|
||||||
void SendBazaarWelcome();
|
void SendBazaarWelcome();
|
||||||
void SendBarterWelcome();
|
void SendBarterWelcome();
|
||||||
void DyeArmor(EQ::TintProfile* dye);
|
void DyeArmor(EQ::TintProfile* dye);
|
||||||
@@ -361,15 +361,17 @@ public:
|
|||||||
void SendColoredText(uint32 color, std::string message);
|
void SendColoredText(uint32 color, std::string message);
|
||||||
void SendTraderItem(uint32 item_id,uint16 quantity, TraderRepository::Trader &trader);
|
void SendTraderItem(uint32 item_id,uint16 quantity, TraderRepository::Trader &trader);
|
||||||
void DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria);
|
void DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria);
|
||||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
uint16 FindTraderItem(std::string &SerialNumber,uint16 Quantity);
|
||||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
EQ::ItemInstance* FindTraderItemByUniqueID(std::string &unique_id);
|
||||||
EQ::ItemInstance* FindTraderItemBySerialNumber(int32 SerialNumber);
|
EQ::ItemInstance* FindTraderItemByUniqueID(const char* unique_id);
|
||||||
void FindAndNukeTraderItem(int32 serial_number, int16 quantity, Client* customer, uint16 trader_slot);
|
std::vector<EQ::ItemInstance *> FindTraderItemsByUniqueID(const char* unique_id);
|
||||||
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, int32 serial_number, int32 item_id = 0);
|
void FindAndNukeTraderItem(std::string &item_unique_id, int16 quantity, Client* customer, uint16 trader_slot);
|
||||||
|
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, const std::string &serial_number, int32 item_id = 0);
|
||||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||||
void BuyTraderItem(TraderBuy_Struct* tbs, Client* trader, const EQApplicationPacket* app);
|
void TradeRequestFailed(TraderBuy_Struct &in);
|
||||||
void BuyTraderItemOutsideBazaar(TraderBuy_Struct* tbs, const EQApplicationPacket* app);
|
void BuyTraderItem(const EQApplicationPacket* app);
|
||||||
|
void BuyTraderItemFromBazaarWindow(const EQApplicationPacket* app);
|
||||||
void FinishTrade(
|
void FinishTrade(
|
||||||
Mob *with,
|
Mob *with,
|
||||||
bool finalizer = false,
|
bool finalizer = false,
|
||||||
@@ -401,13 +403,22 @@ public:
|
|||||||
int32 FindNextFreeParcelSlot(uint32 char_id);
|
int32 FindNextFreeParcelSlot(uint32 char_id);
|
||||||
int32 FindNextFreeParcelSlotUsingMemory();
|
int32 FindNextFreeParcelSlotUsingMemory();
|
||||||
void SendParcelIconStatus();
|
void SendParcelIconStatus();
|
||||||
|
bool IsOffline() { return m_offline; }
|
||||||
|
void SetOffline(bool status) { m_offline = status; }
|
||||||
|
|
||||||
void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action);
|
void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action);
|
||||||
void SendBecomeTrader(BazaarTraderBarterActions action, uint32 trader_id);
|
void SendBecomeTrader(BazaarTraderBarterActions action, uint32 trader_id);
|
||||||
|
|
||||||
bool IsThereACustomer() const { return customer_id ? true : false; }
|
bool IsThereACustomer() const { return customer_id ? true : false; }
|
||||||
uint32 GetCustomerID() { return customer_id; }
|
uint32 GetCustomerID() { return customer_id; }
|
||||||
void SetCustomerID(uint32 id) { customer_id = id; }
|
void SetCustomerID(uint32 id) { customer_id = id; }
|
||||||
|
void ClearTraderMerchantList() { m_trader_merchant_list.clear(); }
|
||||||
|
void AddDataToMerchantList(int16 slot_id, uint32 item_id, int32 quantity, const std::string &item_unique_id);
|
||||||
|
int16 GetNextFreeSlotFromMerchantList();
|
||||||
|
std::tuple<uint32, int32, std::string> GetDataFromMerchantListByMerchantSlotId(int16 slot_id);
|
||||||
|
int16 GetSlotFromMerchantListByItemUniqueId(const std::string &unique_id);
|
||||||
|
std::pair<int16, std::tuple<uint32, int32, std::string>> GetDataFromMerchantListByItemUniqueId(const std::string &unique_id);
|
||||||
|
std::map<int16, std::tuple<uint32, int32, std::string>>* GetTraderMerchantList() { return &m_trader_merchant_list; }
|
||||||
|
|
||||||
void SetBuyerID(uint32 id) { m_buyer_id = id; }
|
void SetBuyerID(uint32 id) { m_buyer_id = id; }
|
||||||
uint32 GetBuyerID() { return m_buyer_id; }
|
uint32 GetBuyerID() { return m_buyer_id; }
|
||||||
@@ -486,7 +497,12 @@ public:
|
|||||||
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
||||||
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
||||||
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
|
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
|
||||||
inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; }
|
inline void Disconnect() {
|
||||||
|
if (eqs) {
|
||||||
|
eqs->Close();
|
||||||
|
client_state = DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
|
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
|
||||||
void Kick(const std::string &reason);
|
void Kick(const std::string &reason);
|
||||||
void WorldKick();
|
void WorldKick();
|
||||||
@@ -576,8 +592,8 @@ public:
|
|||||||
void DisableAreaRegens();
|
void DisableAreaRegens();
|
||||||
|
|
||||||
void ServerFilter(SetServerFilter_Struct* filter);
|
void ServerFilter(SetServerFilter_Struct* filter);
|
||||||
void BulkSendTraderInventory(uint32 char_id);
|
void BulkSendTraderInventory(uint32 character_id);
|
||||||
void SendSingleTraderItem(uint32 char_id, int serial_number);
|
void SendSingleTraderItem(uint32 char_id, const std::string &serial_number);
|
||||||
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
||||||
|
|
||||||
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
||||||
@@ -1134,13 +1150,13 @@ public:
|
|||||||
bool FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items);
|
bool FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items);
|
||||||
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
|
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
|
||||||
void SendCursorBuffer();
|
void SendCursorBuffer();
|
||||||
void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
|
bool DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
|
||||||
uint32 CountItem(uint32 item_id);
|
uint32 CountItem(uint32 item_id);
|
||||||
void ResetItemCooldown(uint32 item_id);
|
void ResetItemCooldown(uint32 item_id);
|
||||||
void SetItemCooldown(uint32 item_id, bool use_saved_timer = false, uint32 in_seconds = 1);
|
void SetItemCooldown(uint32 item_id, bool use_saved_timer = false, uint32 in_seconds = 1);
|
||||||
uint32 GetItemCooldown(uint32 item_id);
|
uint32 GetItemCooldown(uint32 item_id);
|
||||||
void RemoveItem(uint32 item_id, uint32 quantity = 1);
|
void RemoveItem(uint32 item_id, uint32 quantity = 1);
|
||||||
void RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity = 1);
|
bool RemoveItemByItemUniqueId(const std::string &item_unique_id, uint32 quantity = 1);
|
||||||
bool SwapItem(MoveItem_Struct* move_in);
|
bool SwapItem(MoveItem_Struct* move_in);
|
||||||
void SwapItemResync(MoveItem_Struct* move_slots);
|
void SwapItemResync(MoveItem_Struct* move_slots);
|
||||||
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, LootItem** bag_item_data = 0);
|
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, LootItem** bag_item_data = 0);
|
||||||
@@ -2093,7 +2109,9 @@ private:
|
|||||||
uint8 mercSlot; // selected merc slot
|
uint8 mercSlot; // selected merc slot
|
||||||
time_t m_trader_transaction_date;
|
time_t m_trader_transaction_date;
|
||||||
uint32 m_trader_count{};
|
uint32 m_trader_count{};
|
||||||
|
std::map<int16, std::tuple<uint32, int32, std::string>> m_trader_merchant_list{}; // itemid, qty, item_unique_id
|
||||||
uint32 m_buyer_id;
|
uint32 m_buyer_id;
|
||||||
|
bool m_offline;
|
||||||
uint32 m_barter_time;
|
uint32 m_barter_time;
|
||||||
int32 m_parcel_platinum;
|
int32 m_parcel_platinum;
|
||||||
int32 m_parcel_gold;
|
int32 m_parcel_gold;
|
||||||
@@ -2423,4 +2441,68 @@ public:
|
|||||||
bool IsFilteredAFKPacket(const EQApplicationPacket *p);
|
bool IsFilteredAFKPacket(const EQApplicationPacket *p);
|
||||||
void CheckAutoIdleAFK(PlayerPositionUpdateClient_Struct *p);
|
void CheckAutoIdleAFK(PlayerPositionUpdateClient_Struct *p);
|
||||||
void SyncWorldPositionsToClient(bool ignore_idle = false);
|
void SyncWorldPositionsToClient(bool ignore_idle = false);
|
||||||
|
|
||||||
|
|
||||||
|
Mob* GetMob() {
|
||||||
|
return Mob::GetMob();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clone(Client& in)
|
||||||
|
{
|
||||||
|
WID = in.WID;
|
||||||
|
admin = in.admin;
|
||||||
|
guild_id = in.guild_id;
|
||||||
|
guildrank = in.guildrank;
|
||||||
|
LFG = in.LFG;
|
||||||
|
m_is_afk = in.m_is_afk;
|
||||||
|
m_is_idle = in.m_is_idle;
|
||||||
|
m_is_manual_afk = in.m_is_manual_afk;
|
||||||
|
trader_id = in.trader_id;
|
||||||
|
m_buyer_id = in.m_buyer_id;
|
||||||
|
race = in.race;
|
||||||
|
class_ = in.class_;
|
||||||
|
size = in.size;
|
||||||
|
deity = in.deity;
|
||||||
|
texture = in.texture;
|
||||||
|
m_ClientVersion = in.m_ClientVersion;
|
||||||
|
m_ClientVersionBit = in.m_ClientVersionBit;
|
||||||
|
character_id = in.character_id;
|
||||||
|
account_id = in.account_id;
|
||||||
|
lsaccountid = in.lsaccountid;
|
||||||
|
|
||||||
|
m_pp.platinum = in.m_pp.platinum;
|
||||||
|
m_pp.gold = in.m_pp.gold;
|
||||||
|
m_pp.silver = in.m_pp.silver;
|
||||||
|
m_pp.copper = in.m_pp.copper;
|
||||||
|
m_pp.platinum_bank = in.m_pp.platinum_bank;
|
||||||
|
m_pp.gold_bank = in.m_pp.gold_bank;
|
||||||
|
m_pp.silver_bank = in.m_pp.silver_bank;
|
||||||
|
m_pp.copper_bank = in.m_pp.copper_bank;
|
||||||
|
m_pp.platinum_cursor = in.m_pp.platinum_cursor;
|
||||||
|
m_pp.gold_cursor = in.m_pp.gold_cursor;
|
||||||
|
m_pp.silver_cursor = in.m_pp.silver_cursor;
|
||||||
|
m_pp.copper_cursor = in.m_pp.copper_cursor;
|
||||||
|
m_pp.currentRadCrystals = in.m_pp.currentRadCrystals;
|
||||||
|
m_pp.careerRadCrystals = in.m_pp.careerRadCrystals;
|
||||||
|
m_pp.currentEbonCrystals = in.m_pp.currentEbonCrystals;
|
||||||
|
m_pp.careerEbonCrystals = in.m_pp.careerEbonCrystals;
|
||||||
|
m_pp.gm = in.m_pp.gm;
|
||||||
|
|
||||||
|
m_inv.SetInventoryVersion(in.m_ClientVersion);
|
||||||
|
SetBodyType(in.GetBodyType(), false);
|
||||||
|
|
||||||
|
for (auto [slot, item] : in.m_inv.GetPersonal()) {
|
||||||
|
if (item) {
|
||||||
|
m_inv.GetPersonal()[slot] = item->Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto [slot, item] : in.m_inv.GetWorn()) {
|
||||||
|
if (item) {
|
||||||
|
m_inv.GetWorn()[slot] = item->Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloneMob(*in.GetMob());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ bool Client::DoEvolveCheckProgression(EQ::ItemInstance &inst)
|
|||||||
|
|
||||||
PlayerEvent::EvolveItem e{};
|
PlayerEvent::EvolveItem e{};
|
||||||
|
|
||||||
RemoveItemBySerialNumber(inst.GetSerialNumber());
|
RemoveItemByItemUniqueId(inst.GetUniqueID());
|
||||||
EvolvingItemsManager::Instance()->LoadPlayerEvent(inst, e);
|
EvolvingItemsManager::Instance()->LoadPlayerEvent(inst, e);
|
||||||
e.status = "Evolved Item due to obtaining progression - Old Evolve Item removed from inventory.";
|
e.status = "Evolved Item due to obtaining progression - Old Evolve Item removed from inventory.";
|
||||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||||
@@ -508,7 +508,7 @@ void Client::DoEvolveTransferXP(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
PlayerEvent::EvolveItem e{};
|
PlayerEvent::EvolveItem e{};
|
||||||
|
|
||||||
RemoveItemBySerialNumber(inst_from->GetSerialNumber());
|
RemoveItemByItemUniqueId(inst_from->GetUniqueID());
|
||||||
EvolvingItemsManager::Instance()->LoadPlayerEvent(*inst_from, e);
|
EvolvingItemsManager::Instance()->LoadPlayerEvent(*inst_from, e);
|
||||||
e.status = "Transfer XP - Original FROM Evolve Item removed from inventory.";
|
e.status = "Transfer XP - Original FROM Evolve Item removed from inventory.";
|
||||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||||
@@ -518,7 +518,7 @@ void Client::DoEvolveTransferXP(const EQApplicationPacket *app)
|
|||||||
e.status = "Transfer XP - Updated FROM item placed in inventory.";
|
e.status = "Transfer XP - Updated FROM item placed in inventory.";
|
||||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||||
|
|
||||||
RemoveItemBySerialNumber(inst_to->GetSerialNumber());
|
RemoveItemByItemUniqueId(inst_to->GetUniqueID());
|
||||||
EvolvingItemsManager::Instance()->LoadPlayerEvent(*inst_to, e);
|
EvolvingItemsManager::Instance()->LoadPlayerEvent(*inst_to, e);
|
||||||
e.status = "Transfer XP - Original TO Evolve Item removed from inventory.";
|
e.status = "Transfer XP - Original TO Evolve Item removed from inventory.";
|
||||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||||
|
|||||||
+168
-41
@@ -25,6 +25,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "common/raid.h"
|
#include "common/raid.h"
|
||||||
#include "common/rdtsc.h"
|
#include "common/rdtsc.h"
|
||||||
#include "common/repositories/account_repository.h"
|
#include "common/repositories/account_repository.h"
|
||||||
|
#include "common/repositories/character_offline_transactions_repository.h"
|
||||||
|
#include "common/repositories/offline_character_sessions_repository.h"
|
||||||
#include "common/repositories/adventure_members_repository.h"
|
#include "common/repositories/adventure_members_repository.h"
|
||||||
#include "common/repositories/buyer_buy_lines_repository.h"
|
#include "common/repositories/buyer_buy_lines_repository.h"
|
||||||
#include "common/repositories/character_corpses_repository.h"
|
#include "common/repositories/character_corpses_repository.h"
|
||||||
@@ -309,6 +311,7 @@ void MapOpcodes()
|
|||||||
ConnectedOpcodes[OP_MoveCoin] = &Client::Handle_OP_MoveCoin;
|
ConnectedOpcodes[OP_MoveCoin] = &Client::Handle_OP_MoveCoin;
|
||||||
ConnectedOpcodes[OP_MoveItem] = &Client::Handle_OP_MoveItem;
|
ConnectedOpcodes[OP_MoveItem] = &Client::Handle_OP_MoveItem;
|
||||||
ConnectedOpcodes[OP_MoveMultipleItems] = &Client::Handle_OP_MoveMultipleItems;
|
ConnectedOpcodes[OP_MoveMultipleItems] = &Client::Handle_OP_MoveMultipleItems;
|
||||||
|
ConnectedOpcodes[OP_Offline] = &Client::Handle_OP_Offline;
|
||||||
ConnectedOpcodes[OP_OpenContainer] = &Client::Handle_OP_OpenContainer;
|
ConnectedOpcodes[OP_OpenContainer] = &Client::Handle_OP_OpenContainer;
|
||||||
ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster;
|
ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster;
|
||||||
ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory;
|
ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory;
|
||||||
@@ -738,7 +741,7 @@ void Client::CompleteConnect()
|
|||||||
|
|
||||||
if (is_first_login) {
|
if (is_first_login) {
|
||||||
e.first_login = time(nullptr);
|
e.first_login = time(nullptr);
|
||||||
TraderRepository::DeleteWhere(database, fmt::format("`char_id` = '{}'", CharacterID()));
|
TraderRepository::DeleteWhere(database, fmt::format("`character_id` = '{}'", CharacterID()));
|
||||||
BuyerRepository::DeleteBuyer(database, CharacterID());
|
BuyerRepository::DeleteBuyer(database, CharacterID());
|
||||||
LogTradingDetail(
|
LogTradingDetail(
|
||||||
"Removed trader abd buyer entries for Character ID {} on first logon to ensure table consistency.",
|
"Removed trader abd buyer entries for Character ID {} on first logon to ensure table consistency.",
|
||||||
@@ -762,6 +765,54 @@ void Client::CompleteConnect()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto offline_transactions_trader = CharacterOfflineTransactionsRepository::GetWhere(
|
||||||
|
database, fmt::format("`character_id` = {} AND `type` = {}", CharacterID(), TRADER_TRANSACTION)
|
||||||
|
);
|
||||||
|
if (offline_transactions_trader.size() > 0) {
|
||||||
|
Message(Chat::Yellow, "You sold the following items while in offline trader mode:");
|
||||||
|
|
||||||
|
for (auto const &t: offline_transactions_trader) {
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"You sold {} {}{} to {} for {}.",
|
||||||
|
t.quantity,
|
||||||
|
t.item_name,
|
||||||
|
t.quantity > 1 ? "s" : "",
|
||||||
|
t.buyer_name,
|
||||||
|
DetermineMoneyString(t.price))
|
||||||
|
.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterOfflineTransactionsRepository::DeleteWhere(
|
||||||
|
database, fmt::format("`character_id` = '{}' AND `type` = '{}'", CharacterID(), TRADER_TRANSACTION)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto offline_transactions_buyer = CharacterOfflineTransactionsRepository::GetWhere(
|
||||||
|
database, fmt::format("`character_id` = {} AND `type` = {}", CharacterID(), BUYER_TRANSACTION)
|
||||||
|
);
|
||||||
|
if (offline_transactions_buyer.size() > 0) {
|
||||||
|
Message(Chat::Yellow, "You bought the following items while in offline buyer mode:");
|
||||||
|
|
||||||
|
for (auto const &t: offline_transactions_buyer) {
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"You bought {} {}{} from {} for {}.",
|
||||||
|
t.quantity,
|
||||||
|
t.item_name,
|
||||||
|
t.quantity > 1 ? "s" : "",
|
||||||
|
t.buyer_name,
|
||||||
|
DetermineMoneyString(t.price))
|
||||||
|
.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterOfflineTransactionsRepository::DeleteWhere(
|
||||||
|
database, fmt::format("`character_id` = {} AND `type` = {}", CharacterID(), BUYER_TRANSACTION)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||||
SendParcelStatus();
|
SendParcelStatus();
|
||||||
}
|
}
|
||||||
@@ -805,7 +856,7 @@ void Client::CompleteConnect()
|
|||||||
SendGuildMembersList();
|
SendGuildMembersList();
|
||||||
}
|
}
|
||||||
|
|
||||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr));
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr), 0);
|
||||||
|
|
||||||
SendGuildList();
|
SendGuildList();
|
||||||
if (GetGuildListDirty()) {
|
if (GetGuildListDirty()) {
|
||||||
@@ -15341,10 +15392,10 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
TraderStartTrader(app);
|
TraderStartTrader(app);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PriceUpdate:
|
case ItemMove:
|
||||||
case ItemMove: {
|
case PriceUpdate:{
|
||||||
LogTrading("Trader Price Update");
|
LogTrading("Trader item updated - removed, added or price change");
|
||||||
TraderPriceUpdate(app);
|
TraderUpdateItem(app);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EndTransaction: {
|
case EndTransaction: {
|
||||||
@@ -15363,7 +15414,6 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogError("Unknown size for OP_Trader: [{}]\n", app->size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15374,28 +15424,12 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
//
|
//
|
||||||
// Client has elected to buy an item from a Trader
|
// Client has elected to buy an item from a Trader
|
||||||
//
|
//
|
||||||
auto in = (TraderBuy_Struct *) app->pBuffer;
|
|
||||||
|
|
||||||
if (RuleB(Bazaar, UseAlternateBazaarSearch) && in->trader_id >= TraderRepository::TRADER_CONVERT_ID) {
|
auto in = (TraderBuy_Struct *) app->pBuffer;
|
||||||
auto trader = TraderRepository::GetTraderByInstanceAndSerialnumber(
|
auto item_unique_id = std::string(in->item_unique_id);
|
||||||
database,
|
auto trader_details = TraderRepository::GetTraderByItemUniqueNumber(database, item_unique_id);
|
||||||
in->trader_id - TraderRepository::TRADER_CONVERT_ID,
|
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||||
in->serial_number
|
strn0cpy(in->seller_name, trader_details.trader_name.c_str(), sizeof(in->seller_name));
|
||||||
);
|
|
||||||
|
|
||||||
if (!trader.trader_id) {
|
|
||||||
LogTrading("Unable to convert trader id for {} and serial number {}. Trader Buy aborted.",
|
|
||||||
in->trader_id - TraderRepository::TRADER_CONVERT_ID,
|
|
||||||
in->serial_number
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
in->trader_id = trader.trader_id;
|
|
||||||
strn0cpy(in->seller_name, trader.trader_name.c_str(), sizeof(in->seller_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto trader = entity_list.GetClientByID(in->trader_id);
|
|
||||||
|
|
||||||
switch (in->method) {
|
switch (in->method) {
|
||||||
case BazaarByVendor: {
|
case BazaarByVendor: {
|
||||||
@@ -15405,9 +15439,9 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
in->trader_id,
|
in->trader_id,
|
||||||
in->item_id,
|
in->item_id,
|
||||||
in->quantity,
|
in->quantity,
|
||||||
in->serial_number
|
in->item_unique_id
|
||||||
);
|
);
|
||||||
BuyTraderItem(in, trader, app);
|
BuyTraderItem(app);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -15431,9 +15465,9 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
in->trader_id,
|
in->trader_id,
|
||||||
in->item_id,
|
in->item_id,
|
||||||
in->quantity,
|
in->quantity,
|
||||||
in->serial_number
|
in->item_unique_id
|
||||||
);
|
);
|
||||||
BuyTraderItemOutsideBazaar(in, app);
|
BuyTraderItemFromBazaarWindow(app);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BazaarByDirectToInventory: {
|
case BazaarByDirectToInventory: {
|
||||||
@@ -15456,7 +15490,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
in->trader_id,
|
in->trader_id,
|
||||||
in->item_id,
|
in->item_id,
|
||||||
in->quantity,
|
in->quantity,
|
||||||
in->serial_number
|
in->item_unique_id
|
||||||
);
|
);
|
||||||
Message(
|
Message(
|
||||||
Chat::Yellow,
|
Chat::Yellow,
|
||||||
@@ -15467,6 +15501,9 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
TradeRequestFailed(app);
|
TradeRequestFailed(app);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15557,17 +15594,18 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
|||||||
switch (in->Code) {
|
switch (in->Code) {
|
||||||
case ClickTrader: {
|
case ClickTrader: {
|
||||||
LogTrading("Handle_OP_TraderShop case ClickTrader [{}]", in->Code);
|
LogTrading("Handle_OP_TraderShop case ClickTrader [{}]", in->Code);
|
||||||
auto outapp =
|
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||||
std::make_unique<EQApplicationPacket>(OP_TraderShop, static_cast<uint32>(sizeof(TraderClick_Struct))
|
OP_TraderShop,
|
||||||
|
static_cast<uint32>(sizeof(TraderClick_Struct))
|
||||||
);
|
);
|
||||||
auto data = (TraderClick_Struct *) outapp->pBuffer;
|
auto data = (TraderClick_Struct *) outapp->pBuffer;
|
||||||
auto trader_client = entity_list.GetClientByID(in->TraderID);
|
auto trader = entity_list.GetClientByID(in->TraderID);
|
||||||
|
|
||||||
if (trader_client) {
|
if (trader) {
|
||||||
data->Approval = trader_client->WithCustomer(GetID());
|
data->Approval = trader->WithCustomer(GetID());
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]",
|
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]",
|
||||||
GetCleanName(),
|
GetCleanName(),
|
||||||
trader_client->GetCleanName(),
|
trader->GetCleanName(),
|
||||||
data->Approval
|
data->Approval
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -15575,6 +15613,9 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
|||||||
LogTrading("Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
LogTrading("Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||||
" returned a nullptr pointer"
|
" returned a nullptr pointer"
|
||||||
);
|
);
|
||||||
|
auto outapp = new EQApplicationPacket(OP_ShopEndConfirm);
|
||||||
|
QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15584,8 +15625,9 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
|||||||
QueuePacket(outapp.get());
|
QueuePacket(outapp.get());
|
||||||
|
|
||||||
if (data->Approval) {
|
if (data->Approval) {
|
||||||
BulkSendTraderInventory(trader_client->CharacterID());
|
ClearTraderMerchantList();
|
||||||
trader_client->Trader_CustomerBrowsing(this);
|
BulkSendTraderInventory(trader->CharacterID());
|
||||||
|
trader->Trader_CustomerBrowsing(this);
|
||||||
SetTraderID(in->TraderID);
|
SetTraderID(in->TraderID);
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent to [{}] from [{}]",
|
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent to [{}] from [{}]",
|
||||||
GetID(),
|
GetID(),
|
||||||
@@ -17275,3 +17317,88 @@ void Client::SyncWorldPositionsToClient(bool ignore_idle)
|
|||||||
m_is_idle = false;
|
m_is_idle = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Client::Handle_OP_Offline(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
|
if (IsThereACustomer()) {
|
||||||
|
auto customer = entity_list.GetClientByID(GetCustomerID());
|
||||||
|
if (customer) {
|
||||||
|
auto end_session = new EQApplicationPacket(OP_ShopEnd);
|
||||||
|
customer->FastQueuePacket(&end_session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EQStreamInterface *eqsi = nullptr;
|
||||||
|
auto offline_client = new Client(eqsi);
|
||||||
|
|
||||||
|
database.LoadCharacterData(CharacterID(), &offline_client->GetPP(), &offline_client->GetEPP());
|
||||||
|
offline_client->Clone(*this);
|
||||||
|
offline_client->GetInv().SetGMInventory(true);
|
||||||
|
offline_client->SetPosition(GetX(), GetY(), GetZ());
|
||||||
|
offline_client->SetHeading(GetHeading());
|
||||||
|
offline_client->SetSpawned();
|
||||||
|
offline_client->SetBecomeNPC(false);
|
||||||
|
offline_client->SetOffline(true);
|
||||||
|
entity_list.AddClient(offline_client);
|
||||||
|
|
||||||
|
bool session_ready = true;
|
||||||
|
const auto previous_entity_id = GetID();
|
||||||
|
const auto next_entity_id = offline_client->GetID();
|
||||||
|
const auto mode = IsBuyer() ? std::string("buyer") : std::string("trader");
|
||||||
|
|
||||||
|
database.TransactionBegin();
|
||||||
|
|
||||||
|
if (IsBuyer()) {
|
||||||
|
offline_client->SetBuyerID(offline_client->CharacterID());
|
||||||
|
session_ready = BuyerRepository::UpdateBuyerEntityID(database, CharacterID(), previous_entity_id, next_entity_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offline_client->SetTrader(true);
|
||||||
|
session_ready = TraderRepository::UpdateEntityId(database, CharacterID(), previous_entity_id, next_entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_ready) {
|
||||||
|
session_ready = OfflineCharacterSessionsRepository::Upsert(
|
||||||
|
database,
|
||||||
|
AccountID(),
|
||||||
|
CharacterID(),
|
||||||
|
mode,
|
||||||
|
GetZoneID(),
|
||||||
|
GetInstanceID(),
|
||||||
|
next_entity_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_ready) {
|
||||||
|
AccountRepository::SetOfflineStatus(database, AccountID(), true);
|
||||||
|
auto commit_result = database.TransactionCommit();
|
||||||
|
session_ready = commit_result.Success();
|
||||||
|
if (!session_ready) {
|
||||||
|
LogError(
|
||||||
|
"Failed committing offline {} activation for character [{}] account [{}]: ({}) {}",
|
||||||
|
mode,
|
||||||
|
CharacterID(),
|
||||||
|
AccountID(),
|
||||||
|
commit_result.ErrorNumber(),
|
||||||
|
commit_result.ErrorMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session_ready) {
|
||||||
|
database.TransactionRollback();
|
||||||
|
entity_list.RemoveMob(offline_client->CastToMob()->GetID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetOffline(true);
|
||||||
|
OnDisconnect(true);
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket();
|
||||||
|
offline_client->CreateSpawnPacket(outapp);
|
||||||
|
entity_list.QueueClients(nullptr, outapp, false);
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
offline_client->UpdateWho(3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -226,6 +226,7 @@
|
|||||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||||
void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app);
|
void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_Offline(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
if (IsInAGuild()) {
|
if (IsInAGuild()) {
|
||||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::Offline);
|
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::Offline);
|
||||||
@@ -197,7 +197,7 @@ bool Client::Process() {
|
|||||||
Save();
|
Save();
|
||||||
if (IsInAGuild()) {
|
if (IsInAGuild()) {
|
||||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetMerc())
|
if (GetMerc())
|
||||||
@@ -578,7 +578,7 @@ bool Client::Process() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_state != CLIENT_LINKDEAD && !eqs->CheckState(ESTABLISHED)) {
|
if (eqs && client_state != CLIENT_LINKDEAD && !eqs->CheckState(ESTABLISHED)) {
|
||||||
OnDisconnect(true);
|
OnDisconnect(true);
|
||||||
LogInfo("Client linkdead: {}", name);
|
LogInfo("Client linkdead: {}", name);
|
||||||
|
|
||||||
@@ -589,7 +589,7 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
if (IsInAGuild()) {
|
if (IsInAGuild()) {
|
||||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -607,7 +607,7 @@ bool Client::Process() {
|
|||||||
|
|
||||||
/************ Get all packets from packet manager out queue and process them ************/
|
/************ Get all packets from packet manager out queue and process them ************/
|
||||||
EQApplicationPacket *app = nullptr;
|
EQApplicationPacket *app = nullptr;
|
||||||
if (!eqs->CheckState(CLOSING))
|
if (eqs && !eqs->CheckState(CLOSING))
|
||||||
{
|
{
|
||||||
while (app = eqs->PopPacket()) {
|
while (app = eqs->PopPacket()) {
|
||||||
HandlePacket(app);
|
HandlePacket(app);
|
||||||
@@ -617,7 +617,7 @@ bool Client::Process() {
|
|||||||
|
|
||||||
ClientToNpcAggroProcess();
|
ClientToNpcAggroProcess();
|
||||||
|
|
||||||
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
|
if (eqs && client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
|
||||||
{
|
{
|
||||||
//client logged out or errored out
|
//client logged out or errored out
|
||||||
//ResetTrade();
|
//ResetTrade();
|
||||||
|
|||||||
+22
-6
@@ -4995,15 +4995,31 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
|
|||||||
strcpy(WAPP1->Name, ClientEntry->GetName());
|
strcpy(WAPP1->Name, ClientEntry->GetName());
|
||||||
Buffer += sizeof(WhoAllPlayerPart1) + strlen(WAPP1->Name);
|
Buffer += sizeof(WhoAllPlayerPart1) + strlen(WAPP1->Name);
|
||||||
WhoAllPlayerPart2* WAPP2 = (WhoAllPlayerPart2*)Buffer;
|
WhoAllPlayerPart2* WAPP2 = (WhoAllPlayerPart2*)Buffer;
|
||||||
|
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||||
|
|
||||||
if (ClientEntry->IsTrader())
|
if (ClientEntry->IsOffline()) {
|
||||||
WAPP2->RankMSGID = 12315;
|
if (ClientEntry->IsTrader()) {
|
||||||
else if (ClientEntry->IsBuyer())
|
WAPP1->PIDMSGID = 0x0430;
|
||||||
WAPP2->RankMSGID = 6056;
|
}
|
||||||
else if (ClientEntry->Admin() >= AccountStatus::Steward && ClientEntry->GetGM())
|
if (ClientEntry->IsBuyer()) {
|
||||||
|
WAPP1->PIDMSGID = 0x0420;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ClientEntry->IsTrader()) {
|
||||||
|
WAPP2->RankMSGID = 12315;
|
||||||
|
}
|
||||||
|
else if (ClientEntry->IsBuyer()) {
|
||||||
|
WAPP2->RankMSGID = 6056;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClientEntry->Admin() >= AccountStatus::Steward && ClientEntry->GetGM()) {
|
||||||
WAPP2->RankMSGID = 12312;
|
WAPP2->RankMSGID = 12312;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
WAPP2->RankMSGID = 0xFFFFFFFF;
|
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(WAPP2->Guild, GuildName.c_str());
|
strcpy(WAPP2->Guild, GuildName.c_str());
|
||||||
Buffer += sizeof(WhoAllPlayerPart2) + strlen(WAPP2->Guild);
|
Buffer += sizeof(WhoAllPlayerPart2) + strlen(WAPP2->Guild);
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
scope_bit & peekWorld ? EQ::invslot::WORLD_BEGIN + index_main : index_main,
|
scope_bit & peekWorld ? EQ::invslot::WORLD_BEGIN + index_main : index_main,
|
||||||
linker.GenerateLink(),
|
linker.GenerateLink(),
|
||||||
item_data->ID,
|
item_data->ID,
|
||||||
inst_main->GetSerialNumber(),
|
inst_main->GetUniqueID().c_str(),
|
||||||
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
" (Stack of {})",
|
" (Stack of {})",
|
||||||
@@ -254,7 +254,7 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
sub_index,
|
sub_index,
|
||||||
linker.GenerateLink(),
|
linker.GenerateLink(),
|
||||||
item_data->ID,
|
item_data->ID,
|
||||||
inst_sub->GetSerialNumber(),
|
inst_sub->GetUniqueID().c_str(),
|
||||||
(
|
(
|
||||||
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
|
|||||||
+23
-17
@@ -427,10 +427,11 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack)
|
|||||||
auto outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct));
|
auto outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct));
|
||||||
auto gmus = (GuildMemberUpdate_Struct *) outapp->pBuffer;
|
auto gmus = (GuildMemberUpdate_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
gmus->GuildID = sgmus->guild_id;
|
gmus->GuildID = sgmus->guild_id;
|
||||||
gmus->ZoneID = sgmus->zone_id;
|
gmus->ZoneID = sgmus->zone_id;
|
||||||
gmus->InstanceID = 0;
|
gmus->InstanceID = 0;
|
||||||
gmus->LastSeen = sgmus->last_seen;
|
gmus->LastSeen = sgmus->last_seen;
|
||||||
|
gmus->offline_mode = sgmus->offline_mode;
|
||||||
strn0cpy(gmus->MemberName, sgmus->member_name, sizeof(gmus->MemberName));
|
strn0cpy(gmus->MemberName, sgmus->member_name, sizeof(gmus->MemberName));
|
||||||
|
|
||||||
entity_list.QueueClientsGuild(outapp, sgmus->guild_id);
|
entity_list.QueueClientsGuild(outapp, sgmus->guild_id);
|
||||||
@@ -653,17 +654,24 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneGuildManager::SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen)
|
void ZoneGuildManager::SendGuildMemberUpdateToWorld(
|
||||||
|
const char *MemberName,
|
||||||
|
uint32 GuildID,
|
||||||
|
uint16 ZoneID,
|
||||||
|
uint32 LastSeen,
|
||||||
|
uint32 offline_mode
|
||||||
|
)
|
||||||
{
|
{
|
||||||
auto pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct));
|
auto pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct));
|
||||||
|
|
||||||
ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer;
|
auto sgmus = (ServerGuildMemberUpdate_Struct *) pack->pBuffer;
|
||||||
sgmus->guild_id = GuildID;
|
sgmus->guild_id = GuildID;
|
||||||
|
sgmus->zone_id = ZoneID;
|
||||||
|
sgmus->last_seen = LastSeen;
|
||||||
|
sgmus->offline_mode = offline_mode;
|
||||||
strn0cpy(sgmus->member_name, MemberName, sizeof(sgmus->member_name));
|
strn0cpy(sgmus->member_name, MemberName, sizeof(sgmus->member_name));
|
||||||
sgmus->zone_id = ZoneID;
|
|
||||||
sgmus->last_seen = LastSeen;
|
|
||||||
worldserver.SendPacket(pack);
|
|
||||||
|
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1518,14 +1526,12 @@ uint8* ZoneGuildManager::MakeGuildMembers(uint32 guild_id, const char* prefix_na
|
|||||||
PutField(total_tribute);
|
PutField(total_tribute);
|
||||||
PutField(last_tribute);
|
PutField(last_tribute);
|
||||||
SlideStructString(note_buf, ci->public_note);
|
SlideStructString(note_buf, ci->public_note);
|
||||||
//e->zoneinstance = 0;
|
e->zone_id = 0; //If zone_id is 0 and we rely on the current world routine, the notes/tribute tabs are not updated for online characters.
|
||||||
if (ci->online) {
|
e->offline_mode = 0;
|
||||||
e->zone_id = ci->zone_id; //This routine, if there is a zone_id, will update the entire guild window (roster, notes, tribute) for online characters.
|
if (ci->online || ci->offline_mode) {
|
||||||
|
e->zone_id = ci->zone_id; //This routine, if there is a zone_id, will update the entire guild window (roster, notes, tribute) for online characters.
|
||||||
|
e->offline_mode = ci->offline_mode;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
e->zone_id = 0; //If zone_id is 0 and we rely on the current world routine, the notes/tribute tabs are not updated for online characters.
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef SlideStructString
|
#undef SlideStructString
|
||||||
#undef PutFieldN
|
#undef PutFieldN
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -88,7 +88,7 @@ public:
|
|||||||
|
|
||||||
void RecordInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
void RecordInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
||||||
bool VerifyAndClearInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
bool VerifyAndClearInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
||||||
void SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen);
|
void SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen, uint32 offline_mode);
|
||||||
void RequestOnlineGuildMembers(uint32 FromID, uint32 GuildID);
|
void RequestOnlineGuildMembers(uint32 FromID, uint32 GuildID);
|
||||||
void UpdateRankPermission(uint32 gid, uint32 charid, uint32 fid, uint32 rank, uint32 value);
|
void UpdateRankPermission(uint32 gid, uint32 charid, uint32 fid, uint32 rank, uint32 value);
|
||||||
void SendPermissionUpdate(uint32 guild_id, uint32 rank, uint32 function_id, uint32 value);
|
void SendPermissionUpdate(uint32 guild_id, uint32 rank, uint32 function_id, uint32 value);
|
||||||
|
|||||||
+116
-12
@@ -650,8 +650,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
|
|||||||
|
|
||||||
// put item into inventory
|
// put item into inventory
|
||||||
if (to_slot == EQ::invslot::slotCursor) {
|
if (to_slot == EQ::invslot::slotCursor) {
|
||||||
PushItemOnCursor(*inst);
|
PushItemOnCursor(*inst, true);
|
||||||
SendItemPacket(EQ::invslot::slotCursor, inst, ItemPacketLimbo);
|
|
||||||
} else {
|
} else {
|
||||||
PutItemInInventory(to_slot, *inst, true);
|
PutItemInInventory(to_slot, *inst, true);
|
||||||
}
|
}
|
||||||
@@ -958,7 +957,7 @@ void Client::SendCursorBuffer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove item from inventory
|
// Remove item from inventory
|
||||||
void Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_update, bool update_db) {
|
bool Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_update, bool update_db) {
|
||||||
#if (EQDEBUG >= 5)
|
#if (EQDEBUG >= 5)
|
||||||
LogDebug("DeleteItemInInventory([{}], [{}], [{}])", slot_id, quantity, (client_update) ? "true":"false");
|
LogDebug("DeleteItemInInventory([{}], [{}], [{}])", slot_id, quantity, (client_update) ? "true":"false");
|
||||||
#endif
|
#endif
|
||||||
@@ -977,7 +976,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_up
|
|||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 evolve_id = m_inv[slot_id]->GetEvolveUniqueID();
|
uint64 evolve_id = m_inv[slot_id]->GetEvolveUniqueID();
|
||||||
@@ -1031,6 +1030,8 @@ void Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_up
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update)
|
bool Client::PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update)
|
||||||
@@ -1055,6 +1056,16 @@ bool Client::PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update)
|
|||||||
bool Client::PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, bool client_update) {
|
bool Client::PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, bool client_update) {
|
||||||
LogInventory("Putting item [{}] ([{}]) into slot [{}]", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
LogInventory("Putting item [{}] ([{}]) into slot [{}]", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||||
|
|
||||||
|
if (inst.GetUniqueID().empty()) {
|
||||||
|
auto item_unique_id = std::string(inst.GetUniqueID());
|
||||||
|
if (!database.EnsureItemUniqueId(item_unique_id)) {
|
||||||
|
LogError("Failed to reserve item_unique_id for item [{}] ([{}])", inst.GetItem()->Name, inst.GetItem()->ID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_cast<EQ::ItemInstance &>(inst).SetUniqueID(item_unique_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (slot_id == EQ::invslot::slotCursor) { // don't trust macros before conditional statements...
|
if (slot_id == EQ::invslot::slotCursor) { // don't trust macros before conditional statements...
|
||||||
return PushItemOnCursor(inst, client_update);
|
return PushItemOnCursor(inst, client_update);
|
||||||
}
|
}
|
||||||
@@ -4674,19 +4685,112 @@ bool Client::HasItemOnCorpse(uint32 item_id)
|
|||||||
bool Client::PutItemInInventoryWithStacking(EQ::ItemInstance *inst)
|
bool Client::PutItemInInventoryWithStacking(EQ::ItemInstance *inst)
|
||||||
{
|
{
|
||||||
auto free_id = GetInv().FindFirstFreeSlotThatFitsItem(inst->GetItem());
|
auto free_id = GetInv().FindFirstFreeSlotThatFitsItem(inst->GetItem());
|
||||||
if (inst->IsStackable()) {
|
|
||||||
if (TryStacking(inst, ItemPacketTrade, true, false)) {
|
if (!inst->IsStackable()) {
|
||||||
|
if (free_id != INVALID_INDEX &&
|
||||||
|
!EQ::ValueWithin(free_id, EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END)) {
|
||||||
|
return PutItemInInventory(free_id, *inst, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct temp {
|
||||||
|
int16 slot_id;
|
||||||
|
int32 quantity;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<temp> queue;
|
||||||
|
auto quantity = inst->GetCharges();
|
||||||
|
|
||||||
|
for (int i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||||
|
auto inv_inst = GetInv().GetItem(i);
|
||||||
|
if (!inv_inst) {
|
||||||
|
LogError("Found a slot {} in general inventory", i);
|
||||||
|
inst->SetCharges(quantity);
|
||||||
|
PutItemInInventory(i, *inst, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Protect equipment slots (0-22) from being overwritten
|
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||||
if (free_id != INVALID_INDEX && !EQ::ValueWithin(free_id, EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END)) {
|
uint8 bag_size = inv_inst->GetItem()->BagSlots;
|
||||||
if (PutItemInInventory(free_id, *inst, true)) {
|
|
||||||
return true;
|
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||||
|
if (quantity == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bag_inst = GetInv().GetItem(base_slot_id + bag_slot);
|
||||||
|
if (!bag_inst && inv_inst->GetItem()->BagSize >= inst->GetItem()->Size) {
|
||||||
|
LogError("Found a parent {} base_slot_id {} bag_slot {} in bag", i, base_slot_id, bag_slot);
|
||||||
|
inst->SetCharges(quantity);
|
||||||
|
PutItemInInventory(base_slot_id + bag_slot, *inst, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bag_inst && bag_inst->IsStackable() && bag_inst->GetID() == inst->GetID()) {
|
||||||
|
auto stack_size = bag_inst->GetItem()->StackSize;
|
||||||
|
auto bag_inst_quantity = bag_inst->GetCharges();
|
||||||
|
int16 temp_slot = base_slot_id + bag_slot;
|
||||||
|
if (stack_size - bag_inst_quantity >= quantity) {
|
||||||
|
temp tmp = {temp_slot, quantity};
|
||||||
|
queue.push_back(tmp);
|
||||||
|
quantity = 0;
|
||||||
|
LogError(
|
||||||
|
"Found an item parent {} base_slot_id {} bag_slot {} in bag with ENOUGH space",
|
||||||
|
i,
|
||||||
|
base_slot_id,
|
||||||
|
bag_slot
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_size - bag_inst_quantity > 0) {
|
||||||
|
temp tmp = {temp_slot, stack_size - bag_inst_quantity};
|
||||||
|
queue.push_back(tmp);
|
||||||
|
quantity -= stack_size - bag_inst_quantity;
|
||||||
|
LogError(
|
||||||
|
"Found an item parent {} base_slot_id {} bag_slot {} in bag with SOME space",
|
||||||
|
i,
|
||||||
|
base_slot_id,
|
||||||
|
bag_slot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!queue.empty()) {
|
||||||
|
database.TransactionBegin();
|
||||||
|
for (auto const &i: queue) {
|
||||||
|
auto bag_inst = GetInv().GetItem(i.slot_id);
|
||||||
|
if (!bag_inst) {
|
||||||
|
LogError("Client inventory error occurred. Character ID {} Slot_ID {}", CharacterID(), i.slot_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bag_inst->SetCharges(i.quantity + bag_inst->GetCharges());
|
||||||
|
PutItemInInventory(i.slot_id, *bag_inst, true);
|
||||||
|
LogError("Write out data. Item {} quantity {} slot {}", bag_inst->GetItem()->Name, i.quantity, i.slot_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
database.TransactionCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quantity == 0) {
|
||||||
|
LogError("Quantity was zero. All items placed in inventory.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->SetCharges(quantity);
|
||||||
|
if (free_id != INVALID_INDEX &&
|
||||||
|
!EQ::ValueWithin(free_id, EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END) &&
|
||||||
|
PutItemInInventory(free_id, *inst, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogError("Could not find enough room");
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
bool Client::FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items)
|
bool Client::FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items)
|
||||||
{
|
{
|
||||||
|
|||||||
+99
@@ -1954,4 +1954,103 @@ private:
|
|||||||
|
|
||||||
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
|
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
|
||||||
void HandleDoorOpen();
|
void HandleDoorOpen();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Mob* GetMob() { return this; }
|
||||||
|
|
||||||
|
void CloneMob(Mob& in) {
|
||||||
|
strn0cpy(name, in.name, 64);
|
||||||
|
strn0cpy(orig_name, in.orig_name, 64);
|
||||||
|
strn0cpy(lastname, in.lastname, 64);
|
||||||
|
current_hp = in.current_hp;
|
||||||
|
max_hp = in.max_hp;
|
||||||
|
base_hp = in.base_hp;
|
||||||
|
gender = in.gender;
|
||||||
|
race = in.race;
|
||||||
|
base_gender = in.base_gender;
|
||||||
|
base_race = in.race;
|
||||||
|
use_model = in.use_model;
|
||||||
|
class_ = in.class_;
|
||||||
|
bodytype = in.bodytype;
|
||||||
|
orig_bodytype = in.orig_bodytype;
|
||||||
|
deity = in.deity;
|
||||||
|
level = in.level;
|
||||||
|
orig_level = in.orig_level;
|
||||||
|
npctype_id = in.npctype_id;
|
||||||
|
size = in.size;
|
||||||
|
base_size = in.base_size;
|
||||||
|
runspeed = in.runspeed;
|
||||||
|
texture = in.texture;
|
||||||
|
helmtexture = in.helmtexture;
|
||||||
|
armtexture = in.armtexture;
|
||||||
|
bracertexture = in.bracertexture;
|
||||||
|
handtexture = in.handtexture;
|
||||||
|
legtexture = in.legtexture;
|
||||||
|
feettexture = in.feettexture;
|
||||||
|
multitexture = in.multitexture;
|
||||||
|
haircolor = in.haircolor;
|
||||||
|
beardcolor = in.beardcolor;
|
||||||
|
eyecolor1 = in.eyecolor1;
|
||||||
|
eyecolor2 = in.eyecolor2;
|
||||||
|
hairstyle = in.hairstyle;
|
||||||
|
luclinface = in.luclinface;
|
||||||
|
beard = in.beard;
|
||||||
|
drakkin_heritage = in.drakkin_heritage;
|
||||||
|
drakkin_tattoo = in.drakkin_tattoo;
|
||||||
|
drakkin_details = in.drakkin_details;
|
||||||
|
attack_speed = in.attack_speed;
|
||||||
|
attack_delay = in.attack_delay;
|
||||||
|
slow_mitigation = in.slow_mitigation;
|
||||||
|
findable = in.findable;
|
||||||
|
trackable = in.trackable;
|
||||||
|
has_shield_equipped = in.has_shield_equipped;
|
||||||
|
has_two_hand_blunt_equipped = in.has_two_hand_blunt_equipped;
|
||||||
|
has_two_hander_equipped = in.has_two_hander_equipped;
|
||||||
|
has_dual_weapons_equipped = in.has_dual_weapons_equipped;
|
||||||
|
can_facestab = in.can_facestab;
|
||||||
|
has_numhits = in.has_numhits;
|
||||||
|
has_MGB = in.has_MGB;
|
||||||
|
has_ProjectIllusion = in.has_ProjectIllusion;
|
||||||
|
SpellPowerDistanceMod = in.SpellPowerDistanceMod;
|
||||||
|
last_los_check = in.last_los_check;
|
||||||
|
aa_title = in.aa_title;
|
||||||
|
AC = in.AC;
|
||||||
|
ATK = in.ATK;
|
||||||
|
STR = in.STR;
|
||||||
|
STA = in.STA;
|
||||||
|
DEX = in.DEX;
|
||||||
|
AGI = in.AGI;
|
||||||
|
INT = in.INT;
|
||||||
|
WIS = in.WIS;
|
||||||
|
CHA = in.CHA;
|
||||||
|
MR = in.MR;
|
||||||
|
extra_haste = in.extra_haste;
|
||||||
|
bEnraged = in.bEnraged;
|
||||||
|
current_mana = in.current_mana;
|
||||||
|
max_mana = in.max_mana;
|
||||||
|
hp_regen = in.hp_regen;
|
||||||
|
hp_regen_per_second = in.hp_regen_per_second;
|
||||||
|
mana_regen = in.mana_regen;
|
||||||
|
ooc_regen = in.ooc_regen;
|
||||||
|
maxlevel = in.maxlevel;
|
||||||
|
scalerate = in.scalerate;
|
||||||
|
invisible = in.invisible;
|
||||||
|
invisible_undead = in.invisible_undead;
|
||||||
|
invisible_animals = in.invisible_animals;
|
||||||
|
sneaking = in.sneaking;
|
||||||
|
hidden = in.hidden;
|
||||||
|
improved_hidden = in.improved_hidden;
|
||||||
|
invulnerable = in.invulnerable;
|
||||||
|
qglobal = in.qglobal;
|
||||||
|
spawned = in.spawned;
|
||||||
|
rare_spawn = in.rare_spawn;
|
||||||
|
always_aggro = in.always_aggro;
|
||||||
|
heroic_strikethrough = in.heroic_strikethrough;
|
||||||
|
keeps_sold_items = in.keeps_sold_items;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_APPEARANCE_EFFECTS; i++) {
|
||||||
|
appearance_effects_id[i] = in.appearance_effects_id[i];
|
||||||
|
appearance_effects_slot[i] = in.appearance_effects_slot[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+21
-14
@@ -397,6 +397,7 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
parcel_out.sent_date = time(nullptr);
|
parcel_out.sent_date = time(nullptr);
|
||||||
parcel_out.quantity = quantity;
|
parcel_out.quantity = quantity;
|
||||||
parcel_out.item_id = inst->GetID();
|
parcel_out.item_id = inst->GetID();
|
||||||
|
parcel_out.item_unique_id = inst->GetUniqueID();
|
||||||
parcel_out.char_id = send_to_client.at(0).char_id;
|
parcel_out.char_id = send_to_client.at(0).char_id;
|
||||||
parcel_out.slot_id = next_slot;
|
parcel_out.slot_id = next_slot;
|
||||||
parcel_out.evolve_amount = inst->GetEvolveCurrentAmount();
|
parcel_out.evolve_amount = inst->GetEvolveCurrentAmount();
|
||||||
@@ -434,13 +435,14 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
|
|
||||||
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> all_entries{};
|
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> all_entries{};
|
||||||
if (inst->IsNoneEmptyContainer()) {
|
if (inst->IsNoneEmptyContainer()) {
|
||||||
for (auto const &kv: *inst->GetContents()) {
|
for (auto const &[slot, item]: *inst->GetContents()) {
|
||||||
CharacterParcelsContainersRepository::CharacterParcelsContainers cpc{};
|
CharacterParcelsContainersRepository::CharacterParcelsContainers cpc{};
|
||||||
cpc.parcels_id = result.id;
|
cpc.parcels_id = result.id;
|
||||||
cpc.slot_id = kv.first;
|
cpc.slot_id = slot;
|
||||||
cpc.item_id = kv.second->GetID();
|
cpc.item_id = item->GetID();
|
||||||
if (kv.second->IsAugmented()) {
|
cpc.item_unique_id = item->GetUniqueID();
|
||||||
auto augs = kv.second->GetAugmentIDs();
|
if (item->IsAugmented()) {
|
||||||
|
auto augs = item->GetAugmentIDs();
|
||||||
cpc.aug_slot_1 = augs.at(0);
|
cpc.aug_slot_1 = augs.at(0);
|
||||||
cpc.aug_slot_2 = augs.at(1);
|
cpc.aug_slot_2 = augs.at(1);
|
||||||
cpc.aug_slot_3 = augs.at(2);
|
cpc.aug_slot_3 = augs.at(2);
|
||||||
@@ -449,14 +451,15 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
cpc.aug_slot_6 = augs.at(5);
|
cpc.aug_slot_6 = augs.at(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpc.quantity = kv.second->GetCharges() >= 0 ? kv.second->GetCharges() : 1;
|
cpc.quantity = item->GetCharges() >= 0 ? item->GetCharges() : 1;
|
||||||
cpc.evolve_amount = kv.second->GetEvolveCurrentAmount();
|
cpc.evolve_amount = item->GetEvolveCurrentAmount();
|
||||||
|
cpc.quantity = item->GetCharges() >= 0 ? item->GetCharges() : 1;
|
||||||
all_entries.push_back(cpc);
|
all_entries.push_back(cpc);
|
||||||
}
|
}
|
||||||
CharacterParcelsContainersRepository::InsertMany(database, all_entries);
|
CharacterParcelsContainersRepository::InsertMany(database, all_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveItemBySerialNumber(inst->GetSerialNumber(), parcel_out.quantity == 0 ? 1 : parcel_out.quantity);
|
RemoveItemByItemUniqueId(inst->GetUniqueID(), parcel_out.quantity == 0 ? 1 : parcel_out.quantity);
|
||||||
std::unique_ptr<EQApplicationPacket> outapp(new EQApplicationPacket(OP_ShopSendParcel));
|
std::unique_ptr<EQApplicationPacket> outapp(new EQApplicationPacket(OP_ShopSendParcel));
|
||||||
QueuePacket(outapp.get());
|
QueuePacket(outapp.get());
|
||||||
|
|
||||||
@@ -478,6 +481,7 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
e.from_player_name = parcel_out.from_name;
|
e.from_player_name = parcel_out.from_name;
|
||||||
e.to_player_name = send_to_client.at(0).character_name;
|
e.to_player_name = send_to_client.at(0).character_name;
|
||||||
e.item_id = parcel_out.item_id;
|
e.item_id = parcel_out.item_id;
|
||||||
|
e.item_unique_id = parcel_out.item_unique_id;
|
||||||
e.augment_1_id = parcel_out.aug_slot_1;
|
e.augment_1_id = parcel_out.aug_slot_1;
|
||||||
e.augment_2_id = parcel_out.aug_slot_2;
|
e.augment_2_id = parcel_out.aug_slot_2;
|
||||||
e.augment_3_id = parcel_out.aug_slot_3;
|
e.augment_3_id = parcel_out.aug_slot_3;
|
||||||
@@ -494,6 +498,7 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
e.from_player_name = parcel_out.from_name;
|
e.from_player_name = parcel_out.from_name;
|
||||||
e.to_player_name = send_to_client.at(0).character_name;
|
e.to_player_name = send_to_client.at(0).character_name;
|
||||||
e.item_id = i.item_id;
|
e.item_id = i.item_id;
|
||||||
|
e.item_unique_id = i.item_unique_id;
|
||||||
e.augment_1_id = i.aug_slot_1;
|
e.augment_1_id = i.aug_slot_1;
|
||||||
e.augment_2_id = i.aug_slot_2;
|
e.augment_2_id = i.aug_slot_2;
|
||||||
e.augment_3_id = i.aug_slot_3;
|
e.augment_3_id = i.aug_slot_3;
|
||||||
@@ -656,8 +661,9 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (p != m_parcels.end()) {
|
if (p != m_parcels.end()) {
|
||||||
uint32 item_id = parcel_in.parcel_item_id;
|
uint32 item_id = parcel_in.parcel_item_id;
|
||||||
uint32 item_quantity = p->second.quantity;
|
uint32 item_quantity = p->second.quantity;
|
||||||
|
std::string item_unique_id = p->second.item_unique_id;
|
||||||
if (!item_id) {
|
if (!item_id) {
|
||||||
LogError(
|
LogError(
|
||||||
"Attempt to retrieve parcel with erroneous item id for client character id {}.",
|
"Attempt to retrieve parcel with erroneous item id for client character id {}.",
|
||||||
@@ -699,6 +705,7 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
inst->SetUniqueID(item_unique_id);
|
||||||
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> results{};
|
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> results{};
|
||||||
if (inst->IsClassBag() && inst->GetItem()->BagSlots > 0) {
|
if (inst->IsClassBag() && inst->GetItem()->BagSlots > 0) {
|
||||||
auto contents = inst->GetContents();
|
auto contents = inst->GetContents();
|
||||||
@@ -723,7 +730,7 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
}
|
}
|
||||||
|
|
||||||
item->SetEvolveCurrentAmount(i.evolve_amount);
|
item->SetEvolveCurrentAmount(i.evolve_amount);
|
||||||
|
item->SetUniqueID(i.item_unique_id);
|
||||||
if (CheckLoreConflict(item->GetItem())) {
|
if (CheckLoreConflict(item->GetItem())) {
|
||||||
if (RuleB(Parcel, DeleteOnDuplicate)) {
|
if (RuleB(Parcel, DeleteOnDuplicate)) {
|
||||||
MessageString(Chat::Yellow, PARCEL_DUPLICATE_DELETE, inst->GetItem()->Name);
|
MessageString(Chat::Yellow, PARCEL_DUPLICATE_DELETE, inst->GetItem()->Name);
|
||||||
@@ -772,6 +779,7 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
PlayerEvent::ParcelRetrieve e{};
|
PlayerEvent::ParcelRetrieve e{};
|
||||||
e.from_player_name = p->second.from_name;
|
e.from_player_name = p->second.from_name;
|
||||||
e.item_id = p->second.item_id;
|
e.item_id = p->second.item_id;
|
||||||
|
e.item_unique_id = p->second.item_unique_id;
|
||||||
e.augment_1_id = p->second.aug_slot_1;
|
e.augment_1_id = p->second.aug_slot_1;
|
||||||
e.augment_2_id = p->second.aug_slot_2;
|
e.augment_2_id = p->second.aug_slot_2;
|
||||||
e.augment_3_id = p->second.aug_slot_3;
|
e.augment_3_id = p->second.aug_slot_3;
|
||||||
@@ -785,6 +793,7 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
for (auto const &i:results) {
|
for (auto const &i:results) {
|
||||||
e.from_player_name = p->second.from_name;
|
e.from_player_name = p->second.from_name;
|
||||||
e.item_id = i.item_id;
|
e.item_id = i.item_id;
|
||||||
|
e.item_unique_id = i.item_unique_id;
|
||||||
e.augment_1_id = i.aug_slot_1;
|
e.augment_1_id = i.aug_slot_1;
|
||||||
e.augment_2_id = i.aug_slot_2;
|
e.augment_2_id = i.aug_slot_2;
|
||||||
e.augment_3_id = i.aug_slot_3;
|
e.augment_3_id = i.aug_slot_3;
|
||||||
@@ -794,8 +803,6 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
|||||||
e.quantity = i.quantity;
|
e.quantity = i.quantity;
|
||||||
e.sent_date = p->second.sent_date;
|
e.sent_date = p->second.sent_date;
|
||||||
RecordPlayerEventLog(PlayerEvent::PARCEL_RETRIEVE, e);
|
RecordPlayerEventLog(PlayerEvent::PARCEL_RETRIEVE, e);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,6 +308,7 @@
|
|||||||
#define PLAYER_CHARMED 1461 //You lose control of yourself!
|
#define PLAYER_CHARMED 1461 //You lose control of yourself!
|
||||||
#define TRADER_BUSY 1468 //That Trader is currently with a customer. Please wait until their transaction is finished.
|
#define TRADER_BUSY 1468 //That Trader is currently with a customer. Please wait until their transaction is finished.
|
||||||
#define SENSE_CORPSE_DIRECTION 1563 //You sense a corpse in this direction.
|
#define SENSE_CORPSE_DIRECTION 1563 //You sense a corpse in this direction.
|
||||||
|
#define HOW_CAN_YOU_BUY_MORE 1571 //%1 tells you, 'Your inventory appears full! How can you buy more?'
|
||||||
#define DUPE_LORE_MERCHANT 1573 //%1 tells you, 'You already have the lore item, %2, on your person, on your shroud, in the bank, in a real estate, or as an augment in another item. You cannot have more than one of a particular lore item at a time.'
|
#define DUPE_LORE_MERCHANT 1573 //%1 tells you, 'You already have the lore item, %2, on your person, on your shroud, in the bank, in a real estate, or as an augment in another item. You cannot have more than one of a particular lore item at a time.'
|
||||||
#define QUEUED_TELL 2458 //[queued]
|
#define QUEUED_TELL 2458 //[queued]
|
||||||
#define QUEUE_TELL_FULL 2459 //[zoing and queue is full]
|
#define QUEUE_TELL_FULL 2459 //[zoing and queue is full]
|
||||||
@@ -414,6 +415,7 @@
|
|||||||
#define MAX_ACTIVE_TASKS 6010 //Sorry %3, you already have the maximum number of active tasks.
|
#define MAX_ACTIVE_TASKS 6010 //Sorry %3, you already have the maximum number of active tasks.
|
||||||
#define TASK_REQUEST_COOLDOWN_TIMER 6011 //Sorry, %3, but you can't request another task for %4 minutes and %5 seconds.
|
#define TASK_REQUEST_COOLDOWN_TIMER 6011 //Sorry, %3, but you can't request another task for %4 minutes and %5 seconds.
|
||||||
#define FORAGE_MASTERY 6012 //Your forage mastery has enabled you to find something else!
|
#define FORAGE_MASTERY 6012 //Your forage mastery has enabled you to find something else!
|
||||||
|
#define BUYER 6056 //BUYER
|
||||||
#define BUYER_WELCOME 6065 //There are %1 Buyers waiting to purchase your loot. Type /barter to search for them, or use /buyer to set up your own Buy Lines.
|
#define BUYER_WELCOME 6065 //There are %1 Buyers waiting to purchase your loot. Type /barter to search for them, or use /buyer to set up your own Buy Lines.
|
||||||
#define BUYER_GREETING 6070 //%1 greets you, '%2'
|
#define BUYER_GREETING 6070 //%1 greets you, '%2'
|
||||||
#define GUILD_BANK_CANNOT_DEPOSIT 6097 // Cannot deposit this item. Containers must be empty, and only one of each LORE and no NO TRADE or TEMPORARY items may be deposited.
|
#define GUILD_BANK_CANNOT_DEPOSIT 6097 // Cannot deposit this item. Containers must be empty, and only one of each LORE and no NO TRADE or TEMPORARY items may be deposited.
|
||||||
@@ -465,6 +467,8 @@
|
|||||||
#define LDON_NO_LOCKPICK 7564 //You must have a lock pick in your inventory to do this.
|
#define LDON_NO_LOCKPICK 7564 //You must have a lock pick in your inventory to do this.
|
||||||
#define LDON_WAS_NOT_LOCKED 7565 //%1 was not locked.
|
#define LDON_WAS_NOT_LOCKED 7565 //%1 was not locked.
|
||||||
#define LDON_WAS_NOT_TRAPPED 7566 //%1 was not trapped
|
#define LDON_WAS_NOT_TRAPPED 7566 //%1 was not trapped
|
||||||
|
#define DUPLICATE_LORE 7623 //Transaction failed: Duplicate Lore Item!
|
||||||
|
#define INSUFFICIENT_FUNDS 7632 //Transaction failed: Insufficient funds!
|
||||||
#define GAIN_SINGLE_AA_SINGLE_AA 8019 //You have gained an ability point! You now have %1 ability point.
|
#define GAIN_SINGLE_AA_SINGLE_AA 8019 //You have gained an ability point! You now have %1 ability point.
|
||||||
#define GAIN_SINGLE_AA_MULTI_AA 8020 //You have gained an ability point! You now have %1 ability points.
|
#define GAIN_SINGLE_AA_MULTI_AA 8020 //You have gained an ability point! You now have %1 ability points.
|
||||||
#define GAIN_MULTI_AA_MULTI_AA 8021 //You have gained %1 ability point(s)! You now have %2 ability point(s).
|
#define GAIN_MULTI_AA_MULTI_AA 8021 //You have gained %1 ability point(s)! You now have %2 ability point(s).
|
||||||
@@ -539,6 +543,7 @@
|
|||||||
#define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite <name> to invite someone to your group.
|
#define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite <name> to invite someone to your group.
|
||||||
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
|
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
|
||||||
#define ALREADY_IN_PARTY 12272 //That person is already in your party.
|
#define ALREADY_IN_PARTY 12272 //That person is already in your party.
|
||||||
|
#define TRADER 12315 //TRADER
|
||||||
#define TALKING_TO_SELF 12323 //Talking to yourself again?
|
#define TALKING_TO_SELF 12323 //Talking to yourself again?
|
||||||
#define SPLIT_NO_GROUP 12328 //You are not in a group! Keep it all.
|
#define SPLIT_NO_GROUP 12328 //You are not in a group! Keep it all.
|
||||||
#define NO_LONGER_HIDDEN 12337 //You are no longer hidden.
|
#define NO_LONGER_HIDDEN 12337 //You are no longer hidden.
|
||||||
|
|||||||
+725
-789
File diff suppressed because it is too large
Load Diff
+394
-52
@@ -23,7 +23,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "common/misc_functions.h"
|
#include "common/misc_functions.h"
|
||||||
#include "common/patches/patches.h"
|
#include "common/patches/patches.h"
|
||||||
#include "common/profanity_manager.h"
|
#include "common/profanity_manager.h"
|
||||||
|
#include "common/repositories/account_repository.h"
|
||||||
#include "common/repositories/guild_tributes_repository.h"
|
#include "common/repositories/guild_tributes_repository.h"
|
||||||
|
#include "common/repositories/character_offline_transactions_repository.h"
|
||||||
|
#include "common/repositories/offline_character_sessions_repository.h"
|
||||||
#include "common/rulesys.h"
|
#include "common/rulesys.h"
|
||||||
#include "common/say_link.h"
|
#include "common/say_link.h"
|
||||||
#include "common/server_reload_types.h"
|
#include "common/server_reload_types.h"
|
||||||
@@ -54,6 +57,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "common/repositories/account_repository.h"
|
||||||
|
#include "common/repositories/character_offline_transactions_repository.h"
|
||||||
|
|
||||||
extern EntityList entity_list;
|
extern EntityList entity_list;
|
||||||
extern Zone *zone;
|
extern Zone *zone;
|
||||||
extern volatile bool is_zone_loaded;
|
extern volatile bool is_zone_loaded;
|
||||||
@@ -3766,62 +3772,268 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_BazaarPurchase: {
|
case ServerOP_BazaarPurchase: {
|
||||||
auto in = (BazaarPurchaseMessaging_Struct *) pack->pBuffer;
|
auto in = reinterpret_cast<BazaarPurchaseMessaging_Struct *>(pack->pBuffer);
|
||||||
auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id);
|
switch (in->transaction_status) {
|
||||||
if (!trader_pc) {
|
case BazaarPurchaseBuyerCompleteSendToSeller: {
|
||||||
LogTrading("Request trader_id <red>[{}] could not be found in zone_id <red>[{}]",
|
auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id);
|
||||||
in->trader_buy_struct.trader_id,
|
if (!trader_pc) {
|
||||||
zone->GetZoneID()
|
LogTrading(
|
||||||
);
|
"Request trader_id [{}] could not be found in zone_id [{}] instance_id [{}]",
|
||||||
return;
|
in->trader_buy_struct.trader_id,
|
||||||
}
|
zone->GetZoneID(),
|
||||||
|
zone->GetInstanceID()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (trader_pc->IsThereACustomer()) {
|
auto item = trader_pc->FindTraderItemByUniqueID(in->trader_buy_struct.item_unique_id);
|
||||||
auto customer = entity_list.GetClientByID(trader_pc->GetCustomerID());
|
if (!item) {
|
||||||
if (customer) {
|
in->transaction_status = BazaarPurchaseTraderFailed;
|
||||||
customer->CancelTraderTradeWindow();
|
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if there is a customer currently browsing, close to ensure no conflict of purchase
|
||||||
|
if (trader_pc->IsThereACustomer()) {
|
||||||
|
auto customer = entity_list.GetClientByID(trader_pc->GetCustomerID());
|
||||||
|
if (customer) {
|
||||||
|
customer->CancelTraderTradeWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the trader's db entries
|
||||||
|
if (item->IsStackable() && in->item_quantity != in->item_charges) {
|
||||||
|
TraderRepository::UpdateQuantity(database, in->trader_buy_struct.item_unique_id, item->GetCharges() - in->item_quantity);
|
||||||
|
LogTradingDetail(
|
||||||
|
"Step 4:Bazaar Purchase. Decreased database id {} from [{}] to [{}] charges",
|
||||||
|
in->trader_buy_struct.item_id,
|
||||||
|
item->GetCharges(),
|
||||||
|
item->GetCharges() - in->item_quantity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TraderRepository::DeleteOne(database, in->id);
|
||||||
|
LogTradingDetail(
|
||||||
|
"Step 4:Bazaar Purchase. Deleted database id [{}] because database quantity [{}] equals [{}] purchased quantity",
|
||||||
|
in->trader_buy_struct.item_id,
|
||||||
|
item->GetCharges(),
|
||||||
|
item->GetCharges() - in->item_quantity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//at this time, buyer checks ok, seller checks ok.
|
||||||
|
//perform actions to trader
|
||||||
|
uint64 total_cost = static_cast<uint64>(in->trader_buy_struct.price) * static_cast<uint64>(in->item_quantity);
|
||||||
|
if (!trader_pc->RemoveItemByItemUniqueId(in->trader_buy_struct.item_unique_id, in->item_quantity)) {
|
||||||
|
LogTradingDetail(
|
||||||
|
"Failed to remove item {} quantity [{}] from trader [{}]",
|
||||||
|
in->trader_buy_struct.item_unique_id,
|
||||||
|
in->item_quantity,
|
||||||
|
trader_pc->CharacterID()
|
||||||
|
);
|
||||||
|
in->transaction_status = BazaarPurchaseTraderFailed;
|
||||||
|
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTradingDetail(
|
||||||
|
"Step 5:Bazaar Purchase. Removed from inventory of Trader [{}] for sale of [{}] {}{}",
|
||||||
|
trader_pc->CharacterID(),
|
||||||
|
in->item_quantity,
|
||||||
|
in->item_quantity > 1 ? fmt::format("{}s", in->trader_buy_struct.item_name)
|
||||||
|
: in->trader_buy_struct.item_name,
|
||||||
|
item->GetItem()->MaxCharges > 0 ? fmt::format(" with charges of [{}]", in->item_charges)
|
||||||
|
: std::string("")
|
||||||
|
);
|
||||||
|
|
||||||
|
trader_pc->AddMoneyToPP(total_cost, true);
|
||||||
|
|
||||||
|
//Update the trader to indicate the sale has completed
|
||||||
|
EQApplicationPacket outapp(OP_Trader, sizeof(TraderBuy_Struct));
|
||||||
|
auto data = reinterpret_cast<TraderBuy_Struct *>(outapp.pBuffer);
|
||||||
|
|
||||||
|
memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct));
|
||||||
|
trader_pc->QueuePacket(&outapp);
|
||||||
|
|
||||||
|
if (item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_SELL)) {
|
||||||
|
auto e = PlayerEvent::TraderSellEvent{
|
||||||
|
.item_id = item->GetID(),
|
||||||
|
.augment_1_id = item->GetAugmentItemID(0),
|
||||||
|
.augment_2_id = item->GetAugmentItemID(1),
|
||||||
|
.augment_3_id = item->GetAugmentItemID(2),
|
||||||
|
.augment_4_id = item->GetAugmentItemID(3),
|
||||||
|
.augment_5_id = item->GetAugmentItemID(4),
|
||||||
|
.augment_6_id = item->GetAugmentItemID(5),
|
||||||
|
.item_name = in->trader_buy_struct.item_name,
|
||||||
|
.buyer_id = in->buyer_id,
|
||||||
|
.buyer_name = in->trader_buy_struct.buyer_name,
|
||||||
|
.price = in->trader_buy_struct.price,
|
||||||
|
.quantity = in->item_quantity,
|
||||||
|
.charges = in->item_charges,
|
||||||
|
.total_cost = total_cost,
|
||||||
|
.player_money_balance = trader_pc->GetCarriedMoney(),
|
||||||
|
.offline_purchase = trader_pc->IsOffline(),
|
||||||
|
};
|
||||||
|
RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trader_pc->IsOffline()) {
|
||||||
|
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||||
|
e.character_id = trader_pc->CharacterID();
|
||||||
|
e.item_name = in->trader_buy_struct.item_name;
|
||||||
|
e.price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
|
||||||
|
e.quantity = in->trader_buy_struct.quantity;
|
||||||
|
e.type = TRADER_TRANSACTION;
|
||||||
|
e.buyer_name = in->trader_buy_struct.buyer_name;
|
||||||
|
|
||||||
|
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
in->transaction_status = BazaarPurchaseSuccess;
|
||||||
|
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
|
||||||
|
LogTradingDetail("Step 6:Bazaar Purchase. Purchase checks complete for trader. Send Success to buyer via world.");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarPurchaseTraderFailed: {
|
||||||
|
auto buyer = entity_list.GetClientByCharID(in->buyer_id);
|
||||||
|
if (!buyer) {
|
||||||
|
LogTrading(
|
||||||
|
"Requested buyer_id [{}] could not be found in zone_id [{}] instance_id [{}]",
|
||||||
|
in->trader_buy_struct.trader_id,
|
||||||
|
zone->GetZoneID(),
|
||||||
|
zone->GetInstanceID()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return buyer's money including the fee
|
||||||
|
uint64 total_cost =
|
||||||
|
static_cast<uint64>(in->trader_buy_struct.price) * static_cast<uint64>(in->item_quantity);
|
||||||
|
uint64 fee = std::round(total_cost * RuleR(Bazaar, ParcelDeliveryCostMod));
|
||||||
|
buyer->AddMoneyToPP(total_cost + fee, false);
|
||||||
|
buyer->SendMoneyUpdate();
|
||||||
|
|
||||||
|
buyer->Message(Chat::Red, "Bazaar purchased failed. Returning your money.");
|
||||||
|
LogTradingDetail(
|
||||||
|
"Bazaar Purchase Failed. Returning money [{}] + fee [{}] to Buyer [{}]",
|
||||||
|
total_cost,
|
||||||
|
fee,
|
||||||
|
buyer->CharacterID()
|
||||||
|
);
|
||||||
|
buyer->TradeRequestFailed(in->trader_buy_struct);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarPurchaseSuccess: {
|
||||||
|
auto buyer = entity_list.GetClientByCharID(in->buyer_id);
|
||||||
|
if (!buyer) {
|
||||||
|
LogTrading(
|
||||||
|
"Requested buyer_id [{}] could not be found in zone_id [{}] instance_id [{}]",
|
||||||
|
in->trader_buy_struct.trader_id,
|
||||||
|
zone->GetZoneID(),
|
||||||
|
zone->GetInstanceID()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint64 total_cost =
|
||||||
|
static_cast<uint64>(in->trader_buy_struct.price) * static_cast<uint64>(in->item_quantity);
|
||||||
|
|
||||||
|
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_PURCHASE)) {
|
||||||
|
auto e = PlayerEvent::TraderPurchaseEvent{
|
||||||
|
.item_id = in->trader_buy_struct.item_id,
|
||||||
|
.augment_1_id = in->item_aug_1,
|
||||||
|
.augment_2_id = in->item_aug_2,
|
||||||
|
.augment_3_id = in->item_aug_3,
|
||||||
|
.augment_4_id = in->item_aug_4,
|
||||||
|
.augment_5_id = in->item_aug_5,
|
||||||
|
.augment_6_id = in->item_aug_6,
|
||||||
|
.item_name = in->trader_buy_struct.item_name,
|
||||||
|
.trader_id = in->trader_buy_struct.trader_id,
|
||||||
|
.trader_name = in->trader_buy_struct.seller_name,
|
||||||
|
.price = in->trader_buy_struct.price,
|
||||||
|
.quantity = in->item_quantity,
|
||||||
|
.charges = in->item_charges,
|
||||||
|
.total_cost = total_cost,
|
||||||
|
.player_money_balance = buyer->GetCarriedMoney(),
|
||||||
|
};
|
||||||
|
|
||||||
|
RecordPlayerEventLogWithClient(buyer, PlayerEvent::TRADER_PURCHASE, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = database.GetItem(in->trader_buy_struct.item_id);
|
||||||
|
auto quantity = in->item_quantity;
|
||||||
|
if (item->MaxCharges > 0) {
|
||||||
|
quantity = in->item_charges;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send the item via parcel
|
||||||
|
CharacterParcelsRepository::CharacterParcels parcel_out{};
|
||||||
|
parcel_out.from_name = in->trader_buy_struct.seller_name;
|
||||||
|
parcel_out.note = "Delivered from a Bazaar Purchase";
|
||||||
|
parcel_out.sent_date = time(nullptr);
|
||||||
|
parcel_out.quantity = quantity;
|
||||||
|
parcel_out.item_id = in->trader_buy_struct.item_id;
|
||||||
|
parcel_out.item_unique_id = in->trader_buy_struct.item_unique_id;
|
||||||
|
parcel_out.aug_slot_1 = in->item_aug_1;
|
||||||
|
parcel_out.aug_slot_2 = in->item_aug_2;
|
||||||
|
parcel_out.aug_slot_3 = in->item_aug_3;
|
||||||
|
parcel_out.aug_slot_4 = in->item_aug_4;
|
||||||
|
parcel_out.aug_slot_5 = in->item_aug_5;
|
||||||
|
parcel_out.aug_slot_6 = in->item_aug_6;
|
||||||
|
parcel_out.char_id = buyer->CharacterID();
|
||||||
|
parcel_out.slot_id = buyer->FindNextFreeParcelSlot(buyer->CharacterID());
|
||||||
|
parcel_out.id = 0;
|
||||||
|
|
||||||
|
CharacterParcelsRepository::InsertOne(database, parcel_out);
|
||||||
|
|
||||||
|
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::PARCEL_SEND)) {
|
||||||
|
PlayerEvent::ParcelSend e{};
|
||||||
|
e.from_player_name = parcel_out.from_name;
|
||||||
|
e.to_player_name = buyer->GetCleanName();
|
||||||
|
e.item_id = parcel_out.item_id;
|
||||||
|
e.augment_1_id = parcel_out.aug_slot_1;
|
||||||
|
e.augment_2_id = parcel_out.aug_slot_2;
|
||||||
|
e.augment_3_id = parcel_out.aug_slot_3;
|
||||||
|
e.augment_4_id = parcel_out.aug_slot_4;
|
||||||
|
e.augment_5_id = parcel_out.aug_slot_5;
|
||||||
|
e.augment_6_id = parcel_out.aug_slot_6;
|
||||||
|
e.quantity = in->item_quantity;
|
||||||
|
e.charges = in->item_charges;
|
||||||
|
e.sent_date = parcel_out.sent_date;
|
||||||
|
|
||||||
|
RecordPlayerEventLogWithClient(buyer, PlayerEvent::PARCEL_SEND, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parcel_Struct ps{};
|
||||||
|
ps.item_slot = parcel_out.slot_id;
|
||||||
|
strn0cpy(ps.send_to, buyer->GetCleanName(), sizeof(ps.send_to));
|
||||||
|
buyer->SendParcelDeliveryToWorld(ps);
|
||||||
|
|
||||||
|
LogTradingDetail("Step 7:Bazaar Purchase. Sent parcel to Buyer [{}] for purchase of [{}] {}{}",
|
||||||
|
buyer->CharacterID(),
|
||||||
|
quantity,
|
||||||
|
quantity > 1 ? fmt::format("{}s", in->trader_buy_struct.item_name) : in->trader_buy_struct.item_name,
|
||||||
|
item->MaxCharges > 0 ? fmt::format(" with charges of [{}]", in->item_charges) : std::string("")
|
||||||
|
);
|
||||||
|
|
||||||
|
//Update the buyer to indicate the sale has completed
|
||||||
|
EQApplicationPacket outapp(OP_Trader, sizeof(TraderBuy_Struct));
|
||||||
|
auto data = reinterpret_cast<TraderBuy_Struct *>(outapp.pBuffer);
|
||||||
|
|
||||||
|
memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct));
|
||||||
|
buyer->ReturnTraderReq(&outapp, in->item_quantity, in->trader_buy_struct.item_id);
|
||||||
|
LogTradingDetail("Step 8:Bazaar Purchase. Purchase complete. Sending update packet to buyer.");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item_sn = Strings::ToUnsignedBigInt(in->trader_buy_struct.serial_number);
|
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_Trader, static_cast<uint32>(sizeof(TraderBuy_Struct)));
|
|
||||||
auto data = (TraderBuy_Struct *) outapp->pBuffer;
|
|
||||||
|
|
||||||
memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct));
|
|
||||||
|
|
||||||
if (trader_pc->ClientVersion() < EQ::versions::ClientVersion::RoF) {
|
|
||||||
data->price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
|
||||||
|
|
||||||
auto item = trader_pc->FindTraderItemBySerialNumber(item_sn);
|
|
||||||
|
|
||||||
if (item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_SELL)) {
|
|
||||||
auto e = PlayerEvent::TraderSellEvent{
|
|
||||||
.item_id = item ? item->GetID() : 0,
|
|
||||||
.augment_1_id = item->GetAugmentItemID(0),
|
|
||||||
.augment_2_id = item->GetAugmentItemID(1),
|
|
||||||
.augment_3_id = item->GetAugmentItemID(2),
|
|
||||||
.augment_4_id = item->GetAugmentItemID(3),
|
|
||||||
.augment_5_id = item->GetAugmentItemID(4),
|
|
||||||
.augment_6_id = item->GetAugmentItemID(5),
|
|
||||||
.item_name = in->trader_buy_struct.item_name,
|
|
||||||
.buyer_id = in->buyer_id,
|
|
||||||
.buyer_name = in->trader_buy_struct.buyer_name,
|
|
||||||
.price = in->trader_buy_struct.price,
|
|
||||||
.quantity = in->trader_buy_struct.quantity,
|
|
||||||
.charges = item ? item->IsStackable() ? 1 : item->GetCharges() : 0,
|
|
||||||
.total_cost = (in->trader_buy_struct.price * in->trader_buy_struct.quantity),
|
|
||||||
.player_money_balance = trader_pc->GetCarriedMoney(),
|
|
||||||
};
|
|
||||||
RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
trader_pc->RemoveItemBySerialNumber(item_sn, in->trader_buy_struct.quantity);
|
|
||||||
trader_pc->AddMoneyToPP(in->trader_buy_struct.price * in->trader_buy_struct.quantity, true);
|
|
||||||
trader_pc->QueuePacket(outapp.get());
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_BuyerMessaging: {
|
case ServerOP_BuyerMessaging: {
|
||||||
@@ -4073,6 +4285,18 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
|
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buyer->IsOffline()) {
|
||||||
|
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||||
|
e.character_id = buyer->CharacterID();
|
||||||
|
e.item_name = sell_line.item_name;
|
||||||
|
e.price = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||||
|
e.quantity = sell_line.seller_quantity;
|
||||||
|
e.type = BUYER_TRANSACTION;
|
||||||
|
e.buyer_name = sell_line.seller_name;
|
||||||
|
|
||||||
|
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||||
|
}
|
||||||
|
|
||||||
in->action = Barter_BuyerTransactionComplete;
|
in->action = Barter_BuyerTransactionComplete;
|
||||||
worldserver.SendPacket(pack);
|
worldserver.SendPacket(pack);
|
||||||
|
|
||||||
@@ -4133,8 +4357,126 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_UsertoWorldCancelOfflineRequest: {
|
||||||
|
auto in = reinterpret_cast<UsertoWorldResponse *>(pack->pBuffer);
|
||||||
|
auto client = entity_list.GetClientByLSID(in->lsaccountid);
|
||||||
|
if (!client) {
|
||||||
|
LogLoginserverDetail("Step 6a(1) - Zone received ServerOP_UsertoWorldCancelOfflineRequest though could "
|
||||||
|
"not find client."
|
||||||
|
);
|
||||||
|
|
||||||
|
auto e = AccountRepository::GetWhere(database, fmt::format("`lsaccount_id` = '{}'", in->lsaccountid));
|
||||||
|
if (!e.empty()) {
|
||||||
|
auto r = e.front();
|
||||||
|
auto session = OfflineCharacterSessionsRepository::GetByAccountId(database, r.id);
|
||||||
|
auto trader = TraderRepository::GetAccountZoneIdAndInstanceIdByAccountId(database, r.id);
|
||||||
|
const uint32 character_id = session.id ? session.character_id : trader.character_id;
|
||||||
|
|
||||||
|
database.TransactionBegin();
|
||||||
|
r.offline = 0;
|
||||||
|
AccountRepository::UpdateOne(database, r);
|
||||||
|
OfflineCharacterSessionsRepository::DeleteByAccountId(database, r.id);
|
||||||
|
if (character_id) {
|
||||||
|
TraderRepository::DeleteWhere(database, fmt::format("`character_id` = '{}'", character_id));
|
||||||
|
BuyerRepository::DeleteBuyer(database, character_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto commit_result = database.TransactionCommit();
|
||||||
|
if (!commit_result.Success()) {
|
||||||
|
database.TransactionRollback();
|
||||||
|
LogError(
|
||||||
|
"Failed clearing orphaned offline session state for account [{}]: ({}) {}",
|
||||||
|
r.id,
|
||||||
|
commit_result.ErrorNumber(),
|
||||||
|
commit_result.ErrorMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 6a(2) - Zone cleared offline status in account table for user id {} / {}",
|
||||||
|
r.lsaccount_id,
|
||||||
|
r.charname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto sp = new ServerPacket(ServerOP_UsertoWorldCancelOfflineResponse, pack->size);
|
||||||
|
auto out = reinterpret_cast<UsertoWorldResponse *>(sp->pBuffer);
|
||||||
|
sp->opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
out->FromID = in->FromID;
|
||||||
|
out->lsaccountid = in->lsaccountid;
|
||||||
|
out->response = in->response;
|
||||||
|
out->ToID = in->ToID;
|
||||||
|
out->worldid = in->worldid;
|
||||||
|
strn0cpy(out->login, in->login, 64);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 6a(3) - Zone sending ServerOP_UsertoWorldCancelOfflineResponse back to world");
|
||||||
|
worldserver.SendPacket(sp);
|
||||||
|
safe_delete(sp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 6b(1) - Zone received ServerOP_UsertoWorldCancelOfflineRequest and found client {}",
|
||||||
|
client->GetCleanName()
|
||||||
|
);
|
||||||
|
LogLoginserverDetail(
|
||||||
|
"Step 6b(2) - Zone cleared offline status in account table for user id {} / {}",
|
||||||
|
client->CharacterID(),
|
||||||
|
client->GetCleanName()
|
||||||
|
);
|
||||||
|
AccountRepository::SetOfflineStatus(database, client->AccountID(), false);
|
||||||
|
OfflineCharacterSessionsRepository::DeleteByAccountId(database, client->AccountID());
|
||||||
|
|
||||||
|
if (client->IsThereACustomer()) {
|
||||||
|
auto customer = entity_list.GetClientByID(client->GetCustomerID());
|
||||||
|
if (customer) {
|
||||||
|
auto end_session = new EQApplicationPacket(OP_ShopEnd);
|
||||||
|
customer->FastQueuePacket(&end_session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->IsTrader()) {
|
||||||
|
LogLoginserverDetail("Step 6b(3) - Zone ending trader mode for client {}", client->GetCleanName());
|
||||||
|
client->TraderEndTrader();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->IsBuyer()) {
|
||||||
|
LogLoginserverDetail("Step 6b(4) - Zone ending buyer mode for client {}", client->GetCleanName());
|
||||||
|
client->ToggleBuyerMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 6b(5) - Zone updating UpdateWho(2) for client {}", client->GetCleanName());
|
||||||
|
client->UpdateWho(2);
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket();
|
||||||
|
LogLoginserverDetail("Step 6b(6) - Zone sending despawn packet for client {}", client->GetCleanName());
|
||||||
|
client->CreateDespawnPacket(outapp, false);
|
||||||
|
entity_list.QueueClients(nullptr, outapp, false);
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 6b(7) - Zone removing client from entity_list");
|
||||||
|
entity_list.RemoveMob(client->CastToMob()->GetID());
|
||||||
|
|
||||||
|
auto sp = new ServerPacket(ServerOP_UsertoWorldCancelOfflineResponse, pack->size);
|
||||||
|
auto out = reinterpret_cast<UsertoWorldResponse *>(sp->pBuffer);
|
||||||
|
sp->opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||||
|
out->FromID = in->FromID;
|
||||||
|
out->lsaccountid = in->lsaccountid;
|
||||||
|
out->response = in->response;
|
||||||
|
out->ToID = in->ToID;
|
||||||
|
out->worldid = in->worldid;
|
||||||
|
strn0cpy(out->login, in->login, 64);
|
||||||
|
|
||||||
|
LogLoginserverDetail("Step 6b(8) - Zone sending ServerOP_UsertoWorldCancelOfflineResponse back to world");
|
||||||
|
worldserver.SendPacket(sp);
|
||||||
|
safe_delete(sp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
|
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+57
-342
@@ -56,6 +56,9 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "common/repositories/inventory_repository.h"
|
||||||
|
#include "common/repositories/inventory_snapshots_repository.h"
|
||||||
|
|
||||||
extern Zone* zone;
|
extern Zone* zone;
|
||||||
|
|
||||||
ZoneDatabase database;
|
ZoneDatabase database;
|
||||||
@@ -304,19 +307,19 @@ void ZoneDatabase::DeleteWorldContainer(uint32 parent_id, uint32 zone_id)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 char_id, int serial_number)
|
std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 character_id, const std::string &unique_item_id)
|
||||||
{
|
{
|
||||||
auto results = TraderRepository::GetWhere(
|
auto results = TraderRepository::GetWhere(
|
||||||
database,
|
database,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"`char_id` = '{}' AND `item_sn` = '{}' ORDER BY slot_id",
|
"`character_id` = {} AND `item_unique_id` = '{}' ORDER BY slot_id",
|
||||||
char_id,
|
character_id,
|
||||||
serial_number
|
unique_item_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (results.empty()) {
|
if (results.empty()) {
|
||||||
LogTrading("Could not find item serial number {} for character id {}", serial_number, char_id);
|
LogTrading("Could not find item serial number {} for character id {}", unique_item_id, character_id);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,12 +341,12 @@ std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 char
|
|||||||
database.CreateItem(
|
database.CreateItem(
|
||||||
item_id,
|
item_id,
|
||||||
charges,
|
charges,
|
||||||
results.at(0).aug_slot_1,
|
results.at(0).augment_one,
|
||||||
results.at(0).aug_slot_2,
|
results.at(0).augment_two,
|
||||||
results.at(0).aug_slot_3,
|
results.at(0).augment_three,
|
||||||
results.at(0).aug_slot_4,
|
results.at(0).augment_four,
|
||||||
results.at(0).aug_slot_5,
|
results.at(0).augment_five,
|
||||||
results.at(0).aug_slot_6
|
results.at(0).augment_six
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
@@ -352,8 +355,7 @@ std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 char
|
|||||||
}
|
}
|
||||||
|
|
||||||
inst->SetCharges(charges);
|
inst->SetCharges(charges);
|
||||||
inst->SetSerialNumber(serial_number);
|
inst->SetUniqueID(unique_item_id);
|
||||||
inst->SetMerchantSlot(serial_number);
|
|
||||||
inst->SetPrice(cost);
|
inst->SetPrice(cost);
|
||||||
|
|
||||||
if (inst->IsStackable()) {
|
if (inst->IsStackable()) {
|
||||||
@@ -363,9 +365,9 @@ std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 char
|
|||||||
return std::move(inst);
|
return std::move(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneDatabase::UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 charges, uint32 new_price) {
|
void ZoneDatabase::UpdateTraderItemPrice(int character_id, uint32 item_id, uint32 charges, uint32 new_price) {
|
||||||
|
|
||||||
LogTrading("ZoneDatabase::UpdateTraderPrice([{}], [{}], [{}], [{}])", char_id, item_id, charges, new_price);
|
LogTrading("ZoneDatabase::UpdateTraderPrice([{}], [{}], [{}], [{}])", character_id, item_id, charges, new_price);
|
||||||
const EQ::ItemData *item = database.GetItem(item_id);
|
const EQ::ItemData *item = database.GetItem(item_id);
|
||||||
|
|
||||||
if(!item) {
|
if(!item) {
|
||||||
@@ -373,20 +375,20 @@ void ZoneDatabase::UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_price == 0) {
|
if (new_price == 0) {
|
||||||
LogTrading("Removing Trader items from the DB for char_id [{}], item_id [{}]", char_id, item_id);
|
LogTrading("Removing Trader items from the DB for char_id [{}], item_id [{}]", character_id, item_id);
|
||||||
|
|
||||||
auto results = TraderRepository::DeleteWhere(
|
auto results = TraderRepository::DeleteWhere(
|
||||||
database,
|
database,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"`char_id` = '{}' AND `item_id` = {}",
|
"`character_id` = {} AND `item_id` = {}",
|
||||||
char_id,
|
character_id,
|
||||||
item_id
|
item_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!results) {
|
if (!results) {
|
||||||
LogDebug("[CLIENT] Failed to remove trader item(s): [{}] for char_id: [{}]",
|
LogDebug("[CLIENT] Failed to remove trader item(s): [{}] for char_id: [{}]",
|
||||||
item_id,
|
item_id,
|
||||||
char_id
|
character_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,23 +396,23 @@ void ZoneDatabase::UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!item->Stackable) {
|
if (!item->Stackable) {
|
||||||
auto results = TraderRepository::UpdateItem(database, char_id, new_price, item_id, charges);
|
auto results = TraderRepository::UpdateItem(database, character_id, new_price, item_id, charges);
|
||||||
if (!results) {
|
if (!results) {
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"Failed to update price for trader item [{}] for char_id: [{}]",
|
"Failed to update price for trader item [{}] for char_id: [{}]",
|
||||||
item_id,
|
item_id,
|
||||||
char_id
|
character_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto results = TraderRepository::UpdateItem(database, char_id, new_price, item_id, 0);
|
auto results = TraderRepository::UpdateItem(database, character_id, new_price, item_id, 0);
|
||||||
if (!results) {
|
if (!results) {
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"Failed to update price for trader item [{}] for char_id: [{}]",
|
"Failed to update price for trader item [{}] for char_id: [{}]",
|
||||||
item_id,
|
item_id,
|
||||||
char_id
|
character_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1311,269 +1313,48 @@ bool ZoneDatabase::NoRentExpired(const std::string& name)
|
|||||||
return seconds > 1800;
|
return seconds > 1800;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::SaveCharacterInvSnapshot(uint32 character_id) {
|
bool ZoneDatabase::SaveCharacterInvSnapshot(uint32 character_id)
|
||||||
uint32 time_index = time(nullptr);
|
{
|
||||||
std::string query = StringFormat(
|
if (!InventorySnapshotsRepository::SaveCharacterInvSnapshot(database, character_id)) {
|
||||||
"INSERT "
|
|
||||||
"INTO"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"(`time_index`,"
|
|
||||||
" `charid`,"
|
|
||||||
" `slotid`,"
|
|
||||||
" `itemid`,"
|
|
||||||
" `charges`,"
|
|
||||||
" `color`,"
|
|
||||||
" `augslot1`,"
|
|
||||||
" `augslot2`,"
|
|
||||||
" `augslot3`,"
|
|
||||||
" `augslot4`,"
|
|
||||||
" `augslot5`,"
|
|
||||||
" `augslot6`,"
|
|
||||||
" `instnodrop`,"
|
|
||||||
" `custom_data`,"
|
|
||||||
" `ornamenticon`,"
|
|
||||||
" `ornamentidfile`,"
|
|
||||||
" `ornament_hero_model`,"
|
|
||||||
" `guid`"
|
|
||||||
") "
|
|
||||||
"SELECT"
|
|
||||||
" %u,"
|
|
||||||
" `character_id`,"
|
|
||||||
" `slot_id`,"
|
|
||||||
" `item_id`,"
|
|
||||||
" `charges`,"
|
|
||||||
" `color`,"
|
|
||||||
" `augment_one`,"
|
|
||||||
" `augment_two`,"
|
|
||||||
" `augment_three`,"
|
|
||||||
" `augment_four`,"
|
|
||||||
" `augment_five`,"
|
|
||||||
" `augment_six`,"
|
|
||||||
" `instnodrop`,"
|
|
||||||
" `custom_data`,"
|
|
||||||
" `ornament_icon`,"
|
|
||||||
" `ornament_idfile`,"
|
|
||||||
" `ornament_hero_model`,"
|
|
||||||
" `guid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory` "
|
|
||||||
"WHERE"
|
|
||||||
" `character_id` = %u",
|
|
||||||
time_index,
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = database.QueryDatabase(query);
|
|
||||||
LogInventory("[{}] ([{}])", character_id, (results.Success() ? "pass" : "fail"));
|
|
||||||
return results.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ZoneDatabase::CountCharacterInvSnapshots(uint32 character_id) {
|
|
||||||
std::string query = StringFormat(
|
|
||||||
"SELECT"
|
|
||||||
" COUNT(*) "
|
|
||||||
"FROM "
|
|
||||||
"("
|
|
||||||
"SELECT * FROM"
|
|
||||||
" `inventory_snapshots` a "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"GROUP BY"
|
|
||||||
" `time_index`"
|
|
||||||
") b",
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
|
|
||||||
if (!results.Success())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
auto& row = results.begin();
|
|
||||||
|
|
||||||
int64 count = Strings::ToBigInt(row[0]);
|
|
||||||
if (count > 2147483647)
|
|
||||||
return -2;
|
|
||||||
if (count < 0)
|
|
||||||
return -3;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::ClearCharacterInvSnapshots(uint32 character_id, bool from_now) {
|
|
||||||
uint32 del_time = time(nullptr);
|
|
||||||
if (!from_now) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; }
|
|
||||||
|
|
||||||
std::string query = StringFormat(
|
|
||||||
"DELETE "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" `time_index` <= %lu",
|
|
||||||
character_id,
|
|
||||||
(unsigned long)del_time
|
|
||||||
);
|
|
||||||
QueryDatabase(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::ListCharacterInvSnapshots(uint32 character_id, std::list<std::pair<uint32, int>> &is_list) {
|
|
||||||
std::string query = StringFormat(
|
|
||||||
"SELECT"
|
|
||||||
" `time_index`,"
|
|
||||||
" COUNT(*) "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"GROUP BY"
|
|
||||||
" `time_index` "
|
|
||||||
"ORDER BY"
|
|
||||||
" `time_index` "
|
|
||||||
"DESC",
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = 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])));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZoneDatabase::ValidateCharacterInvSnapshotTimestamp(uint32 character_id, uint32 timestamp) {
|
|
||||||
if (!character_id || !timestamp)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string query = StringFormat(
|
|
||||||
"SELECT"
|
|
||||||
" * "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" `time_index` = %u "
|
|
||||||
"LIMIT 1",
|
|
||||||
character_id,
|
|
||||||
timestamp
|
|
||||||
);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
|
|
||||||
if (!results.Success() || results.RowCount() == 0)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneDatabase::ParseCharacterInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &parse_list) {
|
int ZoneDatabase::CountCharacterInvSnapshots(uint32 character_id)
|
||||||
std::string query = StringFormat(
|
{
|
||||||
"SELECT"
|
return InventorySnapshotsRepository::CountCharacterInvSnapshots(*this, character_id);
|
||||||
" `slotid`,"
|
|
||||||
" `itemid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" `time_index` = %u "
|
|
||||||
"ORDER BY"
|
|
||||||
" `slotid`",
|
|
||||||
character_id,
|
|
||||||
timestamp
|
|
||||||
);
|
|
||||||
auto results = 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])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneDatabase::DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list) {
|
void ZoneDatabase::ClearCharacterInvSnapshots(uint32 character_id, bool from_now)
|
||||||
std::string query = StringFormat(
|
{
|
||||||
"SELECT"
|
InventorySnapshotsRepository::ClearCharacterInvSnapshots(*this, character_id, from_now);
|
||||||
" slotid,"
|
|
||||||
" itemid "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `time_index` = %u "
|
|
||||||
"AND"
|
|
||||||
" `charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" `slotid` NOT IN "
|
|
||||||
"("
|
|
||||||
"SELECT"
|
|
||||||
" a.`slotid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` a "
|
|
||||||
"JOIN"
|
|
||||||
" `inventory` b "
|
|
||||||
"USING"
|
|
||||||
" (`slot_id`, `item_id`) "
|
|
||||||
"WHERE"
|
|
||||||
" a.`time_index` = %u "
|
|
||||||
"AND"
|
|
||||||
" a.`charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" b.`character_id` = %u"
|
|
||||||
")",
|
|
||||||
timestamp,
|
|
||||||
character_id,
|
|
||||||
timestamp,
|
|
||||||
character_id,
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = 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])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneDatabase::DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list) {
|
void ZoneDatabase::ListCharacterInvSnapshots(uint32 character_id, std::list<std::pair<uint32, int>> &is_list)
|
||||||
std::string query = StringFormat(
|
{
|
||||||
"SELECT"
|
InventorySnapshotsRepository::ListCharacterInvSnapshots(*this, character_id, is_list);
|
||||||
" `slotid`,"
|
}
|
||||||
" `itemid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory` "
|
|
||||||
"WHERE"
|
|
||||||
" `character_id` = %u "
|
|
||||||
"AND"
|
|
||||||
" `slotid` NOT IN "
|
|
||||||
"("
|
|
||||||
"SELECT"
|
|
||||||
" a.`slotid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory` a "
|
|
||||||
"JOIN"
|
|
||||||
" `inventory_snapshots` b "
|
|
||||||
"USING"
|
|
||||||
" (`slotid`, `itemid`) "
|
|
||||||
"WHERE"
|
|
||||||
" b.`time_index` = %u "
|
|
||||||
"AND"
|
|
||||||
" b.`charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" a.`character_id` = %u"
|
|
||||||
")",
|
|
||||||
character_id,
|
|
||||||
timestamp,
|
|
||||||
character_id,
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
|
|
||||||
if (!results.Success())
|
bool ZoneDatabase::ValidateCharacterInvSnapshotTimestamp(uint32 character_id, uint32 timestamp)
|
||||||
return;
|
{
|
||||||
|
return InventorySnapshotsRepository::ValidateCharacterInvSnapshotTimestamp(*this, character_id, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto row : results)
|
void ZoneDatabase::ParseCharacterInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &parse_list)
|
||||||
compare_list.emplace_back(std::pair<int16, uint32>(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1])));
|
{
|
||||||
|
InventorySnapshotsRepository::ParseCharacterInvSnapshot(*this, character_id, timestamp, parse_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneDatabase::DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list)
|
||||||
|
{
|
||||||
|
InventorySnapshotsRepository::DivergeCharacterInvSnapshotFromInventory(*this, character_id, timestamp, compare_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneDatabase::DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list)
|
||||||
|
{
|
||||||
|
InventorySnapshotsRepository::DivergeCharacterInventoryFromInvSnapshot(*this, character_id, timestamp, compare_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 timestamp) {
|
bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 timestamp) {
|
||||||
@@ -1584,73 +1365,7 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string query = StringFormat(
|
return InventorySnapshotsRepository::RestoreCharacterInvSnapshot(database, character_id, timestamp);
|
||||||
"DELETE "
|
|
||||||
"FROM"
|
|
||||||
" `inventory` "
|
|
||||||
"WHERE"
|
|
||||||
" `character_id` = %u",
|
|
||||||
character_id
|
|
||||||
);
|
|
||||||
auto results = database.QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
query = StringFormat(
|
|
||||||
"INSERT "
|
|
||||||
"INTO"
|
|
||||||
" `inventory` "
|
|
||||||
"(`character_id`,"
|
|
||||||
" `slot_id`,"
|
|
||||||
" `item_id`,"
|
|
||||||
" `charges`,"
|
|
||||||
" `color`,"
|
|
||||||
" `augment_one`,"
|
|
||||||
" `augment_two`,"
|
|
||||||
" `augment_three`,"
|
|
||||||
" `augment_four`,"
|
|
||||||
" `augment_five`,"
|
|
||||||
" `augment_six`,"
|
|
||||||
" `instnodrop`,"
|
|
||||||
" `custom_data`,"
|
|
||||||
" `ornament_icon`,"
|
|
||||||
" `ornament_idfile`,"
|
|
||||||
" `ornament_hero_model`,"
|
|
||||||
" `guid` "
|
|
||||||
") "
|
|
||||||
"SELECT"
|
|
||||||
" `charid`,"
|
|
||||||
" `slotid`,"
|
|
||||||
" `itemid`,"
|
|
||||||
" `charges`,"
|
|
||||||
" `color`,"
|
|
||||||
" `augslot1`,"
|
|
||||||
" `augslot2`,"
|
|
||||||
" `augslot3`,"
|
|
||||||
" `augslot4`,"
|
|
||||||
" `augslot5`,"
|
|
||||||
" `augslot6`,"
|
|
||||||
" `instnodrop`,"
|
|
||||||
" `custom_data`,"
|
|
||||||
" `ornamenticon`,"
|
|
||||||
" `ornamentidfile`,"
|
|
||||||
" `ornament_hero_model`, "
|
|
||||||
" `guid` "
|
|
||||||
"FROM"
|
|
||||||
" `inventory_snapshots` "
|
|
||||||
"WHERE"
|
|
||||||
" `charid` = %u "
|
|
||||||
"AND"
|
|
||||||
" `time_index` = %u",
|
|
||||||
character_id,
|
|
||||||
timestamp
|
|
||||||
);
|
|
||||||
results = database.QueryDatabase(query);
|
|
||||||
|
|
||||||
LogInventory("[{}] snapshot for [{}] @ [{}]",
|
|
||||||
(results.Success() ? "restored" : "failed to restore"), character_id, timestamp);
|
|
||||||
|
|
||||||
return results.Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
|
const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
|
||||||
|
|||||||
+2
-2
@@ -389,11 +389,11 @@ public:
|
|||||||
/* Traders */
|
/* Traders */
|
||||||
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
||||||
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
||||||
void UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 charges, uint32 new_price);
|
void UpdateTraderItemPrice(int character_id, uint32 item_id, uint32 charges, uint32 new_price);
|
||||||
void DeleteTraderItem(uint32 char_id);
|
void DeleteTraderItem(uint32 char_id);
|
||||||
void DeleteTraderItem(uint32 char_id,uint16 slot_id);
|
void DeleteTraderItem(uint32 char_id,uint16 slot_id);
|
||||||
|
|
||||||
std::unique_ptr<EQ::ItemInstance> LoadSingleTraderItem(uint32 char_id, int serial_number);
|
std::unique_ptr<EQ::ItemInstance> LoadSingleTraderItem(uint32 char_id, const std::string &serial_number);
|
||||||
Trader_Struct* LoadTraderItem(uint32 char_id);
|
Trader_Struct* LoadTraderItem(uint32 char_id);
|
||||||
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user