mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 18:51:29 +00:00
[Bug Fix] Fix client hotbar exchanging items when zoning (#4460)
* Add an exception process to assigning item serial numbers to correct a bug in the client hot bar clicky system. * fixed missing guid in replace statement * added snapshot support * upate #show inventory command to protect against crash conditions
This commit is contained in:
parent
8d8ef6d480
commit
3da24fffa4
@ -5733,6 +5733,19 @@ CHANGE COLUMN `value` `bucket_value` varchar(100) CHARACTER SET latin1 COLLATE l
|
|||||||
ADD COLUMN `bucket_comparison` tinyint UNSIGNED NOT NULL DEFAULT 0 AFTER `bucket_value`,
|
ADD COLUMN `bucket_comparison` tinyint UNSIGNED NOT NULL DEFAULT 0 AFTER `bucket_value`,
|
||||||
DROP PRIMARY KEY,
|
DROP PRIMARY KEY,
|
||||||
ADD PRIMARY KEY (`spell_id`) USING BTREE;
|
ADD PRIMARY KEY (`spell_id`) USING BTREE;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9283,
|
||||||
|
.description = "2024_08_05_fix_client_hotbar",
|
||||||
|
.check = "SHOW COLUMNS FROM `inventory` LIKE 'guid'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `inventory`
|
||||||
|
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||||
|
ALTER TABLE `inventory_snapshots`
|
||||||
|
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
|
|||||||
@ -32,10 +32,11 @@
|
|||||||
|
|
||||||
//#include <iostream>
|
//#include <iostream>
|
||||||
|
|
||||||
int32 NextItemInstSerialNumber = 1;
|
int32 next_item_serial_number = 1;
|
||||||
|
std::unordered_set<uint64> guids{};
|
||||||
static inline int32 GetNextItemInstSerialNumber() {
|
|
||||||
|
|
||||||
|
static inline int32 GetNextItemInstSerialNumber()
|
||||||
|
{
|
||||||
// The Bazaar relies on each item a client has up for Trade having a unique
|
// The Bazaar relies on each item a client has up for Trade having a unique
|
||||||
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
||||||
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
||||||
@ -46,12 +47,18 @@ static inline int32 GetNextItemInstSerialNumber() {
|
|||||||
// NextItemInstSerialNumber is the next one to hand out.
|
// NextItemInstSerialNumber is the next one to hand out.
|
||||||
//
|
//
|
||||||
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
||||||
if(NextItemInstSerialNumber >= INT_MAX)
|
if (next_item_serial_number >= INT32_MAX) {
|
||||||
NextItemInstSerialNumber = 1;
|
next_item_serial_number = 1;
|
||||||
else
|
}
|
||||||
NextItemInstSerialNumber++;
|
else {
|
||||||
|
next_item_serial_number++;
|
||||||
|
}
|
||||||
|
|
||||||
return NextItemInstSerialNumber;
|
while (guids.contains(next_item_serial_number)) {
|
||||||
|
next_item_serial_number++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_item_serial_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1935,6 +1942,15 @@ int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augmen
|
|||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EQ::ItemInstance::AddGUIDToMap(uint64 existing_serial_number)
|
||||||
|
{
|
||||||
|
guids.emplace(existing_serial_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::ItemInstance::ClearGUIDMap()
|
||||||
|
{
|
||||||
|
guids.clear();
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// class EvolveInfo
|
// class EvolveInfo
|
||||||
//
|
//
|
||||||
|
|||||||
@ -309,6 +309,8 @@ namespace EQ
|
|||||||
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
||||||
uint32 GetItemGuildFavor() const;
|
uint32 GetItemGuildFavor() const;
|
||||||
std::vector<uint32> GetAugmentIDs() const;
|
std::vector<uint32> GetAugmentIDs() const;
|
||||||
|
static void AddGUIDToMap(uint64 existing_serial_number);
|
||||||
|
static void ClearGUIDMap();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|||||||
@ -35,6 +35,7 @@ public:
|
|||||||
uint32_t ornamenticon;
|
uint32_t ornamenticon;
|
||||||
uint32_t ornamentidfile;
|
uint32_t ornamentidfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
|
uint64_t guid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@ -61,6 +62,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +85,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +142,7 @@ public:
|
|||||||
e.ornamenticon = 0;
|
e.ornamenticon = 0;
|
||||||
e.ornamentidfile = 0;
|
e.ornamentidfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
|
e.guid = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -191,6 +195,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -240,6 +245,7 @@ public:
|
|||||||
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
|
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
|
||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
|
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -277,6 +283,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -322,6 +329,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@ -371,6 +379,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -411,6 +420,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -501,6 +511,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -539,6 +550,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ public:
|
|||||||
uint32_t ornamenticon;
|
uint32_t ornamenticon;
|
||||||
uint32_t ornamentidfile;
|
uint32_t ornamentidfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
|
uint64_t guid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@ -63,6 +64,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +88,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +146,7 @@ public:
|
|||||||
e.ornamenticon = 0;
|
e.ornamenticon = 0;
|
||||||
e.ornamentidfile = 0;
|
e.ornamentidfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
|
e.guid = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -196,6 +200,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -246,6 +251,7 @@ public:
|
|||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -284,6 +290,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -330,6 +337,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@ -380,6 +388,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -421,6 +430,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = 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;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -512,6 +522,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -551,6 +562,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
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));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
#include "repositories/character_item_recast_repository.h"
|
#include "repositories/character_item_recast_repository.h"
|
||||||
#include "repositories/character_corpses_repository.h"
|
#include "repositories/character_corpses_repository.h"
|
||||||
#include "repositories/skill_caps_repository.h"
|
#include "repositories/skill_caps_repository.h"
|
||||||
|
#include "repositories/inventory_repository.h"
|
||||||
|
|
||||||
namespace ItemField
|
namespace ItemField
|
||||||
{
|
{
|
||||||
@ -300,15 +301,15 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance*
|
|||||||
// Update/Insert item
|
// Update/Insert item
|
||||||
const std::string query = StringFormat("REPLACE INTO inventory "
|
const std::string query = StringFormat("REPLACE INTO inventory "
|
||||||
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
|
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
|
||||||
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model) "
|
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model, guid) "
|
||||||
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
|
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
|
||||||
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
||||||
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
|
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
|
||||||
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
|
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
|
||||||
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
|
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
|
||||||
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
|
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
|
||||||
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
|
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
|
||||||
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()));
|
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()), inst->GetSerialNumber());
|
||||||
const auto results = QueryDatabase(query);
|
const auto results = QueryDatabase(query);
|
||||||
|
|
||||||
// Save bag contents, if slot supports bag contents
|
// Save bag contents, if slot supports bag contents
|
||||||
@ -651,48 +652,67 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Retrieve character inventory
|
// Retrieve character inventory
|
||||||
const std::string query =
|
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`;", char_id));
|
||||||
StringFormat("SELECT slotid, itemid, charges, color, augslot1, augslot2, augslot3, augslot4, augslot5, "
|
if (results.empty()) {
|
||||||
"augslot6, instnodrop, custom_data, ornamenticon, ornamentidfile, ornament_hero_model FROM "
|
LogError("Error loading inventory for char_id {} from the database.", char_id);
|
||||||
"inventory WHERE charid = %i ORDER BY slotid",
|
|
||||||
char_id);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success()) {
|
|
||||||
LogError("If you got an error related to the 'instnodrop' field, run the "
|
|
||||||
"following SQL Queries:\nalter table inventory add instnodrop "
|
|
||||||
"tinyint(1) unsigned default 0 not null;\n");
|
|
||||||
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;
|
||||||
|
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||||
|
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
||||||
|
|
||||||
auto cv_conflict = false;
|
std::vector<InventoryRepository::Inventory> queue{};
|
||||||
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
for (auto &row: results) {
|
||||||
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
const int16 slot_id = row.slotid;
|
||||||
|
const uint32 item_id = row.itemid;
|
||||||
|
const uint16 charges = row.charges;
|
||||||
|
const uint32 color = row.color;
|
||||||
|
const bool instnodrop = row.instnodrop;
|
||||||
|
const uint32 ornament_icon = row.ornamenticon;
|
||||||
|
const uint32 ornament_idfile = row.ornamentidfile;
|
||||||
|
const uint32 ornament_hero_model = row.ornament_hero_model;
|
||||||
|
|
||||||
for (auto& row = results.begin(); row != results.end(); ++row) {
|
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
||||||
int16 slot_id = Strings::ToInt(row[0]);
|
aug[0] = row.augslot1;
|
||||||
|
aug[1] = row.augslot2;
|
||||||
|
aug[2] = row.augslot3;
|
||||||
|
aug[3] = row.augslot4;
|
||||||
|
aug[4] = row.augslot5;
|
||||||
|
aug[5] = row.augslot6;
|
||||||
|
|
||||||
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) { // Titanium thru UF check
|
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
|
||||||
|
// Titanium thru UF check
|
||||||
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
|
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) { // Titanium thru UF check
|
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) {
|
||||||
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + ((slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
// Titanium thru UF check
|
||||||
|
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + (
|
||||||
|
(slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||||
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
|
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) { // Titanium check
|
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) {
|
||||||
|
// Titanium check
|
||||||
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
|
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) { // Titanium check
|
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) {
|
||||||
|
// Titanium check
|
||||||
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||||
if (parent_index >= bank_size) {
|
if (parent_index >= bank_size) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
@ -700,64 +720,55 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 item_id = Strings::ToUnsignedInt(row[1]);
|
auto *item = GetItem(item_id);
|
||||||
const uint16 charges = Strings::ToUnsignedInt(row[2]);
|
|
||||||
const uint32 color = Strings::ToUnsignedInt(row[3]);
|
|
||||||
|
|
||||||
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
|
||||||
|
|
||||||
aug[0] = Strings::ToUnsignedInt(row[4]);
|
|
||||||
aug[1] = Strings::ToUnsignedInt(row[5]);
|
|
||||||
aug[2] = Strings::ToUnsignedInt(row[6]);
|
|
||||||
aug[3] = Strings::ToUnsignedInt(row[7]);
|
|
||||||
aug[4] = Strings::ToUnsignedInt(row[8]);
|
|
||||||
aug[5] = Strings::ToUnsignedInt(row[9]);
|
|
||||||
|
|
||||||
const bool instnodrop = (row[10] && static_cast<uint16>(Strings::ToUnsignedInt(row[10])));
|
|
||||||
|
|
||||||
const uint32 ornament_icon = Strings::ToUnsignedInt(row[12]);
|
|
||||||
const uint32 ornament_idfile = Strings::ToUnsignedInt(row[13]);
|
|
||||||
uint32 ornament_hero_model = Strings::ToUnsignedInt(row[14]);
|
|
||||||
|
|
||||||
const EQ::ItemData *item = GetItem(item_id);
|
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
LogError("Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]", char_id, item_id,
|
LogError(
|
||||||
slot_id);
|
"Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::ItemInstance *inst = CreateBaseItem(item, charges);
|
auto *inst = CreateBaseItem(item, charges);
|
||||||
|
if (!inst) {
|
||||||
if (inst == nullptr)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (row[11]) {
|
if (!row.custom_data.empty()) {
|
||||||
std::string data_str(row[11]);
|
inst->SetCustomDataString(row.custom_data);
|
||||||
inst->SetCustomDataString(data_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->SetOrnamentIcon(ornament_icon);
|
inst->SetOrnamentIcon(ornament_icon);
|
||||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
||||||
|
|
||||||
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END))
|
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <=
|
||||||
|
EQ::invslot::EQUIPMENT_END)) {
|
||||||
inst->SetAttuned(true);
|
inst->SetAttuned(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (color > 0)
|
if (color > 0) {
|
||||||
inst->SetColor(color);
|
inst->SetColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
if (charges == 0x7FFF)
|
if (charges == 0x7FFF) {
|
||||||
inst->SetCharges(-1);
|
inst->SetCharges(-1);
|
||||||
else if (charges == 0 && inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable.
|
}
|
||||||
|
else if (charges == 0 && inst->IsStackable()) {
|
||||||
|
// Stackable items need a minimum charge of 1 remain moveable.
|
||||||
inst->SetCharges(1);
|
inst->SetCharges(1);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
inst->SetCharges(charges);
|
inst->SetCharges(charges);
|
||||||
|
}
|
||||||
|
|
||||||
if (item->RecastDelay) {
|
if (item->RecastDelay) {
|
||||||
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
|
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
|
||||||
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
||||||
} else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
}
|
||||||
|
else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
||||||
inst->SetRecastTimestamp(timestamps.at(item->ID));
|
inst->SetRecastTimestamp(timestamps.at(item->ID));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -767,35 +778,50 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
|
|
||||||
if (item->IsClassCommon()) {
|
if (item->IsClassCommon()) {
|
||||||
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
||||||
if (aug[i])
|
if (aug[i]) {
|
||||||
inst->PutAugment(this, i, aug[i]);
|
inst->PutAugment(this, i, aug[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 put_slot_id;
|
int16 put_slot_id;
|
||||||
if (slot_id >= 8000 && slot_id <= 8999) {
|
if (slot_id >= 8000 && slot_id <= 8999) {
|
||||||
put_slot_id = inv->PushCursor(*inst);
|
put_slot_id = inv->PushCursor(*inst);
|
||||||
} else if (slot_id >= 3111 && slot_id <= 3179) {
|
}
|
||||||
|
else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||||
// Admins: please report any occurrences of this error
|
// Admins: please report any occurrences of this error
|
||||||
LogError("Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
LogError(
|
||||||
char_id, item_id, slot_id);
|
"Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
put_slot_id = inv->PushCursor(*inst);
|
put_slot_id = inv->PushCursor(*inst);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
row.guid = inst->GetSerialNumber();
|
||||||
|
queue.push_back(row);
|
||||||
|
|
||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
|
|
||||||
// Save ptr to item in inventory
|
// Save ptr to item in inventory
|
||||||
if (put_slot_id == INVALID_INDEX) {
|
if (put_slot_id == INVALID_INDEX) {
|
||||||
LogError("Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
LogError(
|
||||||
char_id, item_id, slot_id);
|
"Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_conflict) {
|
if (cv_conflict) {
|
||||||
const std::string& char_name = GetCharName(char_id);
|
const std::string &char_name = GetCharName(char_id);
|
||||||
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
LogError(
|
||||||
|
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||||
char_name,
|
char_name,
|
||||||
char_id,
|
char_id,
|
||||||
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
||||||
@ -803,6 +829,12 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!queue.empty()) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -160,23 +160,22 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
linker.SetItemInst(inst_main);
|
linker.SetItemInst(inst_main);
|
||||||
|
|
||||||
if (item_data) {
|
if (item_data && inst_main) {
|
||||||
|
//auto inst = c->GetInv().GetItem(scope_bit & peekWorld ? EQ::invslot::WORLD_BEGIN + index_main : index_main);
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Slot {} | {} ({}/{}){}",
|
"Slot {} | {} ({}/{}){}",
|
||||||
((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,
|
||||||
c->GetInv().GetItem(((scope_bit &peekWorld) ? (EQ::invslot::WORLD_BEGIN + index_main) : index_main))->GetSerialNumber(),
|
inst_main->GetSerialNumber(),
|
||||||
(
|
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
||||||
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
fmt::format(
|
||||||
fmt::format(
|
" (Stack of {})",
|
||||||
" (Stack of {})",
|
inst_main->GetCharges()
|
||||||
inst_main->GetCharges()
|
) :
|
||||||
) :
|
""
|
||||||
""
|
|
||||||
)
|
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -239,7 +238,7 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
sub_index,
|
sub_index,
|
||||||
linker.GenerateLink(),
|
linker.GenerateLink(),
|
||||||
item_data->ID,
|
item_data->ID,
|
||||||
c->GetInv().GetItem(EQ::InventoryProfile::CalcSlotId(index_main, sub_index))->GetSerialNumber(),
|
inst_sub->GetSerialNumber(),
|
||||||
(
|
(
|
||||||
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
|
|||||||
@ -1327,7 +1327,8 @@ bool ZoneDatabase::SaveCharacterInvSnapshot(uint32 character_id) {
|
|||||||
" `custom_data`,"
|
" `custom_data`,"
|
||||||
" `ornamenticon`,"
|
" `ornamenticon`,"
|
||||||
" `ornamentidfile`,"
|
" `ornamentidfile`,"
|
||||||
" `ornament_hero_model`"
|
" `ornament_hero_model`,"
|
||||||
|
" `guid`"
|
||||||
") "
|
") "
|
||||||
"SELECT"
|
"SELECT"
|
||||||
" %u,"
|
" %u,"
|
||||||
@ -1346,7 +1347,8 @@ bool ZoneDatabase::SaveCharacterInvSnapshot(uint32 character_id) {
|
|||||||
" `custom_data`,"
|
" `custom_data`,"
|
||||||
" `ornamenticon`,"
|
" `ornamenticon`,"
|
||||||
" `ornamentidfile`,"
|
" `ornamentidfile`,"
|
||||||
" `ornament_hero_model` "
|
" `ornament_hero_model`,"
|
||||||
|
" `guid` "
|
||||||
"FROM"
|
"FROM"
|
||||||
" `inventory` "
|
" `inventory` "
|
||||||
"WHERE"
|
"WHERE"
|
||||||
@ -1607,7 +1609,8 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times
|
|||||||
" `custom_data`,"
|
" `custom_data`,"
|
||||||
" `ornamenticon`,"
|
" `ornamenticon`,"
|
||||||
" `ornamentidfile`,"
|
" `ornamentidfile`,"
|
||||||
" `ornament_hero_model`"
|
" `ornament_hero_model`,"
|
||||||
|
" `guid`"
|
||||||
") "
|
") "
|
||||||
"SELECT"
|
"SELECT"
|
||||||
" `charid`,"
|
" `charid`,"
|
||||||
@ -1625,7 +1628,8 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times
|
|||||||
" `custom_data`,"
|
" `custom_data`,"
|
||||||
" `ornamenticon`,"
|
" `ornamenticon`,"
|
||||||
" `ornamentidfile`,"
|
" `ornamentidfile`,"
|
||||||
" `ornament_hero_model` "
|
" `ornament_hero_model`, "
|
||||||
|
" `guid` "
|
||||||
"FROM"
|
"FROM"
|
||||||
" `inventory_snapshots` "
|
" `inventory_snapshots` "
|
||||||
"WHERE"
|
"WHERE"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user