[Database] Consolidate Starting Items Table (#3723)

* [Database] Consolidate Starting Items Table

# Notes
- Convert `class`, `deityId`, `race`, and `zoneid` columns to `|` separated columns.
- Consolidates up to 15 rows per item down to a singular row.
- Allows ease of use for operators.
- Entire process is automated and creates a backup of pre-existing table.

* Update shareddb.cpp

* Unnecessary.
This commit is contained in:
Alex King 2023-11-30 14:37:08 -05:00 committed by GitHub
parent e75c31d524
commit 33b40e83b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 184 additions and 90 deletions

View File

@ -5030,6 +5030,61 @@ ADD COLUMN `min_time` smallint(4) NOT NULL DEFAULT 0 AFTER `condition_value_filt
ADD COLUMN `max_time` smallint(4) NOT NULL DEFAULT 0 AFTER `min_time`; ADD COLUMN `max_time` smallint(4) NOT NULL DEFAULT 0 AFTER `min_time`;
)" )"
}, },
ManifestEntry{
.version = 9243,
.description = "2023_11_27_starting_items_revamp.sql",
.check = "SHOW COLUMNS FROM `starting_items` LIKE 'race_list'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `starting_items_backup_9243` LIKE `starting_items`;
INSERT INTO `starting_items_backup_9243` SELECT * FROM `starting_items`;
CREATE TABLE `starting_items_new` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`race_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`deity_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`zone_id_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`item_id` int(11) UNSIGNED NOT NULL DEFAULT 0,
`item_charges` tinyint(3) UNSIGNED NOT NULL DEFAULT 1,
`gm` mediumint(3) UNSIGNED NOT NULL DEFAULT 0,
`slot` mediumint(9) NOT NULL DEFAULT -1,
`min_expansion` tinyint(4) NOT NULL DEFAULT -1,
`max_expansion` tinyint(4) NOT NULL DEFAULT -1,
`content_flags` varchar(100) NULL,
`content_flags_disabled` varchar(100) NULL,
PRIMARY KEY (`id`)
);
INSERT INTO
`starting_items_new`
(
SELECT
0 AS `id`,
GROUP_CONCAT(DISTINCT `class` ORDER BY class ASC SEPARATOR '|') AS `class_list`,
GROUP_CONCAT(DISTINCT `race` ORDER BY race ASC SEPARATOR '|') AS `race_list`,
GROUP_CONCAT(DISTINCT `deityid` ORDER BY deityid ASC SEPARATOR '|') AS `deity_list`,
GROUP_CONCAT(DISTINCT `zoneid` ORDER BY zoneid ASC SEPARATOR '|') AS `zone_list`,
`itemid`,
`item_charges`,
`gm`,
`slot`,
`min_expansion`,
`max_expansion`,
`content_flags`,
`content_flags_disabled `
FROM
`starting_items`
GROUP BY
`itemid`
);
DROP TABLE `starting_items`;
RENAME TABLE `starting_items_new` TO `starting_items`;
)"
}
// -- template; copy/paste this when you need to create a new entry // -- template; copy/paste this when you need to create a new entry
// ManifestEntry{ // ManifestEntry{
// .version = 9228, // .version = 9228,

View File

@ -16,17 +16,18 @@
#include "../../strings.h" #include "../../strings.h"
#include <ctime> #include <ctime>
class BaseStartingItemsRepository { class BaseStartingItemsRepository {
public: public:
struct StartingItems { struct StartingItems {
uint32_t id; uint32_t id;
int32_t race; std::string race_list;
int32_t class_; std::string class_list;
int32_t deityid; std::string deity_list;
int32_t zoneid; std::string zone_id_list;
int32_t itemid; uint32_t item_id;
uint8_t item_charges; uint8_t item_charges;
int8_t gm; uint8_t gm;
int32_t slot; int32_t slot;
int8_t min_expansion; int8_t min_expansion;
int8_t max_expansion; int8_t max_expansion;
@ -43,11 +44,11 @@ public:
{ {
return { return {
"id", "id",
"race", "race_list",
"`class`", "class_list",
"deityid", "deity_list",
"zoneid", "zone_id_list",
"itemid", "item_id",
"item_charges", "item_charges",
"gm", "gm",
"slot", "slot",
@ -62,11 +63,11 @@ public:
{ {
return { return {
"id", "id",
"race", "race_list",
"`class`", "class_list",
"deityid", "deity_list",
"zoneid", "zone_id_list",
"itemid", "item_id",
"item_charges", "item_charges",
"gm", "gm",
"slot", "slot",
@ -115,11 +116,11 @@ public:
StartingItems e{}; StartingItems e{};
e.id = 0; e.id = 0;
e.race = 0; e.race_list = "";
e.class_ = 0; e.class_list = "";
e.deityid = 0; e.deity_list = "";
e.zoneid = 0; e.zone_id_list = "";
e.itemid = 0; e.item_id = 0;
e.item_charges = 1; e.item_charges = 1;
e.gm = 0; e.gm = 0;
e.slot = -1; e.slot = -1;
@ -152,8 +153,9 @@ public:
{ {
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
"{} WHERE id = {} LIMIT 1", "{} WHERE {} = {} LIMIT 1",
BaseSelect(), BaseSelect(),
PrimaryKey(),
starting_items_id starting_items_id
) )
); );
@ -163,13 +165,13 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1])); e.race_list = row[1] ? row[1] : "";
e.class_ = static_cast<int32_t>(atoi(row[2])); e.class_list = row[2] ? row[2] : "";
e.deityid = static_cast<int32_t>(atoi(row[3])); e.deity_list = row[3] ? row[3] : "";
e.zoneid = static_cast<int32_t>(atoi(row[4])); e.zone_id_list = row[4] ? row[4] : "";
e.itemid = static_cast<int32_t>(atoi(row[5])); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<int8_t>(atoi(row[7])); e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.slot = static_cast<int32_t>(atoi(row[8])); e.slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));
@ -208,11 +210,11 @@ public:
auto columns = Columns(); auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.race)); v.push_back(columns[1] + " = '" + Strings::Escape(e.race_list) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.class_)); v.push_back(columns[2] + " = '" + Strings::Escape(e.class_list) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.deityid)); v.push_back(columns[3] + " = '" + Strings::Escape(e.deity_list) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.zoneid)); v.push_back(columns[4] + " = '" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.itemid)); v.push_back(columns[5] + " = " + std::to_string(e.item_id));
v.push_back(columns[6] + " = " + std::to_string(e.item_charges)); v.push_back(columns[6] + " = " + std::to_string(e.item_charges));
v.push_back(columns[7] + " = " + std::to_string(e.gm)); v.push_back(columns[7] + " = " + std::to_string(e.gm));
v.push_back(columns[8] + " = " + std::to_string(e.slot)); v.push_back(columns[8] + " = " + std::to_string(e.slot));
@ -242,11 +244,11 @@ 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.race)); v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back(std::to_string(e.class_)); v.push_back("'" + Strings::Escape(e.class_list) + "'");
v.push_back(std::to_string(e.deityid)); v.push_back("'" + Strings::Escape(e.deity_list) + "'");
v.push_back(std::to_string(e.zoneid)); v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.itemid)); v.push_back(std::to_string(e.item_id));
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.gm)); v.push_back(std::to_string(e.gm));
v.push_back(std::to_string(e.slot)); v.push_back(std::to_string(e.slot));
@ -284,11 +286,11 @@ 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.race)); v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back(std::to_string(e.class_)); v.push_back("'" + Strings::Escape(e.class_list) + "'");
v.push_back(std::to_string(e.deityid)); v.push_back("'" + Strings::Escape(e.deity_list) + "'");
v.push_back(std::to_string(e.zoneid)); v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.itemid)); v.push_back(std::to_string(e.item_id));
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.gm)); v.push_back(std::to_string(e.gm));
v.push_back(std::to_string(e.slot)); v.push_back(std::to_string(e.slot));
@ -330,13 +332,13 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1])); e.race_list = row[1] ? row[1] : "";
e.class_ = static_cast<int32_t>(atoi(row[2])); e.class_list = row[2] ? row[2] : "";
e.deityid = static_cast<int32_t>(atoi(row[3])); e.deity_list = row[3] ? row[3] : "";
e.zoneid = static_cast<int32_t>(atoi(row[4])); e.zone_id_list = row[4] ? row[4] : "";
e.itemid = static_cast<int32_t>(atoi(row[5])); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<int8_t>(atoi(row[7])); e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.slot = static_cast<int32_t>(atoi(row[8])); e.slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));
@ -367,13 +369,13 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1])); e.race_list = row[1] ? row[1] : "";
e.class_ = static_cast<int32_t>(atoi(row[2])); e.class_list = row[2] ? row[2] : "";
e.deityid = static_cast<int32_t>(atoi(row[3])); e.deity_list = row[3] ? row[3] : "";
e.zoneid = static_cast<int32_t>(atoi(row[4])); e.zone_id_list = row[4] ? row[4] : "";
e.itemid = static_cast<int32_t>(atoi(row[5])); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<int8_t>(atoi(row[7])); e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.slot = static_cast<int32_t>(atoi(row[8])); e.slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));

View File

@ -41,6 +41,7 @@
#include "repositories/criteria/content_filter_criteria.h" #include "repositories/criteria/content_filter_criteria.h"
#include "repositories/account_repository.h" #include "repositories/account_repository.h"
#include "repositories/faction_association_repository.h" #include "repositories/faction_association_repository.h"
#include "repositories/starting_items_repository.h"
#include "path_manager.h" #include "path_manager.h"
#include "repositories/loottable_repository.h" #include "repositories/loottable_repository.h"
@ -446,45 +447,81 @@ bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) {
return true; return true;
} }
bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, EQ::InventoryProfile* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) { bool SharedDatabase::SetStartingItems(
PlayerProfile_Struct *pp,
EQ::InventoryProfile *inv,
uint32 si_race,
uint32 si_class,
uint32 si_deity,
uint32 si_current_zone,
char *si_name,
int admin_level
)
{
const EQ::ItemData *item_data;
const EQ::ItemData *myitem; const auto &l = StartingItemsRepository::All(*this);
const std::string query = StringFormat( if (l.empty()) {
"SELECT itemid, item_charges, slot FROM starting_items "
"WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND "
"(deityid = %i or deityid = 0) AND (zoneid = %i or zoneid = 0) AND "
"gm <= %i %s ORDER BY id",
si_race,
si_class,
si_deity,
si_current_zone,
admin_level,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false; return false;
} }
std::vector<StartingItemsRepository::StartingItems> v;
for (auto& row = results.begin(); row != results.end(); ++row) { for (const auto &e : l) {
const int32 itemid = Strings::ToInt(row[0]); const auto &classes = Strings::Split(e.class_list, "|");
const int32 charges = Strings::ToInt(row[1]); const auto &deities = Strings::Split(e.deity_list, "|");
int32 slot = Strings::ToInt(row[2]); const auto &races = Strings::Split(e.race_list, "|");
myitem = GetItem(itemid); const auto &zones = Strings::Split(e.zone_id_list, "|");
if(!myitem) const std::string &all = std::to_string(0);
if (classes[0] != all) {
if (!Strings::Contains(classes, std::to_string(si_class))) {
continue; continue;
}
}
const EQ::ItemInstance* myinst = CreateBaseItem(myitem, charges); if (deities[0] != all) {
if (!Strings::Contains(deities, std::to_string(si_deity))) {
continue;
}
}
if(slot < 0) if (races[0] != all) {
slot = inv->FindFreeSlot(0, 0); if (!Strings::Contains(races, std::to_string(si_race))) {
continue;
}
}
inv->PutItem(slot, *myinst); if (zones[0] != all) {
safe_delete(myinst); if (!Strings::Contains(zones, std::to_string(si_current_zone))) {
continue;
}
}
v.emplace_back(e);
}
for (const auto &e : v) {
const uint32 item_id = e.item_id;
const uint8 item_charges = e.item_charges;
int32 slot = e.slot;
item_data = GetItem(item_id);
if (!item_data) {
continue;
}
const auto *inst = CreateBaseItem(item_data, item_charges);
if (slot < EQ::invslot::slotCharm) {
slot = inv->FindFreeSlot(false, false);
}
inv->PutItem(slot, *inst);
safe_delete(inst);
} }
return true; return true;

View File

@ -42,7 +42,7 @@
* 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 9242 #define CURRENT_BINARY_DATABASE_VERSION 9243
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040