feat(core\dbc): item.dbc, sItemStore, item_dbc, item enforcement conf, subclass fix (#14675)

feat (core\log\db): item.dbc and enforcement

dbc enforcement partial pick from tc: https://github.com/TrinityCore/TrinityCore/commit/0c44bd33ee7b42c924859139a9f4b04cf2b91261

Custom Item for testing by menevia16a (SPP DEV VEIL)

feat (core\log\db): item.dbc and enforcement

Update Item.sql

Update DBCStores.cpp

Update World.cpp

Update ObjectMgr.cpp

further replacement from template to dbc lookup

further logging and implementation

cherry pick tc https://github.com/TrinityCore/TrinityCore/commit/fd26c3c87c5e75952d5af033a66c9a28c9af29b9

replace with db lookup

update (sql): Murder all the backticks

line break fixit

fix (item_template): fix incorrect subclass

fix incorrect subclass matching with dbc enforcement

update: log correction for sub class

update log correction for sub class

add subclass to dbc enforcement

add subclass dbc enforcement since it is part of the item.dbc item_dbc

update (log): additional log

Co-authored-by: blub <trinity.michael_vincent@gmx.eu>
Co-authored-by: Shocker <511388+shocker@users.noreply.github.com>
Co-authored-by: Veil <1913466+menevia16a@users.noreply.github.com>
Co-authored-by: Shocker <43253032+shockerqt@users.noreply.github.com>
This commit is contained in:
M'Dic
2023-04-27 19:26:44 -04:00
committed by GitHub
parent c2f6f5b881
commit ab2c062f03
11 changed files with 143 additions and 41 deletions
@@ -0,0 +1,15 @@
-- add item_dbc table
DROP TABLE IF EXISTS `item_dbc`;
CREATE TABLE `item_dbc` ( `ID` INT NOT NULL DEFAULT '0', `ClassID` INT NOT NULL DEFAULT '0', `SubclassID` INT NOT NULL DEFAULT '0', `Sound_Override_Subclassid` INT NOT NULL DEFAULT '0', `Material` INT NOT NULL DEFAULT '0', `DisplayInfoID` INT NOT NULL DEFAULT '0', `InventoryType` INT NOT NULL DEFAULT '0', `SheatheType` INT NOT NULL DEFAULT '0', PRIMARY KEY (`ID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Corrects subclass error messages
UPDATE `item_template` SET `subclass`=4 WHERE `entry`=17;
UPDATE `item_template` SET `subclass`=6 WHERE `entry`=2556;
UPDATE `item_template` SET `subclass`=0 WHERE `entry`=20221;
UPDATE `item_template` SET `subclass`=13 WHERE `entry`=31802;
UPDATE `item_template` SET `subclass`=3 WHERE `entry`=33080;
UPDATE `item_template` SET `subclass`=3 WHERE `entry`=33604;
UPDATE `item_template` SET `subclass`=8 WHERE `entry`=37445;
UPDATE `item_template` SET `subclass`=12 WHERE `entry`=37677;
UPDATE `item_template` SET `subclass`=7 WHERE `entry`=41749;
UPDATE `item_template` SET `subclass`=1 WHERE `entry`=53048;
@@ -1309,6 +1309,14 @@ DeletedCharacterTicketTrace = 0
DungeonFinder.OptionsMask = 5
#
# DBC.EnforceItemAttributes
# Disallow overriding item attributes stored in DBC files with values from the database
# Default: 0 - Off, Use DB values
# 1 - On, Enforce DBC Values (default)
DBC.EnforceItemAttributes = 1
#
# AccountInstancesPerHour
# Description: Controls the max amount of different instances player can enter within hour
@@ -2007,7 +2007,7 @@ private:
bool IsItemValid(SmartScriptHolder const& e, uint32 entry)
{
if (!sObjectMgr->GetItemTemplate(entry))
if (!sItemStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Item entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
return false;
+4 -1
View File
@@ -98,6 +98,7 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
DBCStorage <ItemEntry> sItemStore(Itemfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
@@ -317,6 +318,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sGtRegenHPPerSptStore, "gtRegenHPPerSpt.dbc", "gtregenhpperspt_dbc");
LOAD_DBC(sGtRegenMPPerSptStore, "gtRegenMPPerSpt.dbc", "gtregenmpperspt_dbc");
LOAD_DBC(sHolidaysStore, "Holidays.dbc", "holidays_dbc");
LOAD_DBC(sItemStore, "Item.dbc", "item_dbc");
LOAD_DBC(sItemBagFamilyStore, "ItemBagFamily.dbc", "itembagfamily_dbc");
LOAD_DBC(sItemDisplayInfoStore, "ItemDisplayInfo.dbc", "itemdisplayinfo_dbc");
//LOAD_DBC(sItemCondExtCostsStore, "ItemCondExtCosts.dbc", "itemcondextcosts_dbc");
@@ -631,9 +633,10 @@ void LoadDBCStores(const std::string& dataPath)
}
// Check loaded DBC files proper version
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
!sItemStore.LookupEntry(56806) || // last client known item added in 3.3.5a
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
+1
View File
@@ -124,6 +124,7 @@ extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
extern DBCStorage <ItemEntry> sItemStore;
extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore;
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
+94 -36
View File
@@ -1595,9 +1595,9 @@ void ObjectMgr::LoadEquipmentTemplates()
if (!equipmentInfo.ItemEntry[i])
continue;
ItemTemplate const* item = GetItemTemplate(equipmentInfo.ItemEntry[i]);
ItemEntry const* dbcItem = sItemStore.LookupEntry(equipmentInfo.ItemEntry[i]);
if (!item)
if (!dbcItem)
{
LOG_ERROR("sql.sql", "Unknown item (ID={}) in creature_equip_template.ItemID{} for CreatureID = {} and ID = {}, forced to 0.",
equipmentInfo.ItemEntry[i], i + 1, entry, id);
@@ -1605,15 +1605,15 @@ void ObjectMgr::LoadEquipmentTemplates()
continue;
}
if (item->InventoryType != INVTYPE_WEAPON &&
item->InventoryType != INVTYPE_SHIELD &&
item->InventoryType != INVTYPE_RANGED &&
item->InventoryType != INVTYPE_2HWEAPON &&
item->InventoryType != INVTYPE_WEAPONMAINHAND &&
item->InventoryType != INVTYPE_WEAPONOFFHAND &&
item->InventoryType != INVTYPE_HOLDABLE &&
item->InventoryType != INVTYPE_THROWN &&
item->InventoryType != INVTYPE_RANGEDRIGHT)
if (dbcItem->InventoryType != INVTYPE_WEAPON &&
dbcItem->InventoryType != INVTYPE_SHIELD &&
dbcItem->InventoryType != INVTYPE_RANGED &&
dbcItem->InventoryType != INVTYPE_2HWEAPON &&
dbcItem->InventoryType != INVTYPE_WEAPONMAINHAND &&
dbcItem->InventoryType != INVTYPE_WEAPONOFFHAND &&
dbcItem->InventoryType != INVTYPE_HOLDABLE &&
dbcItem->InventoryType != INVTYPE_THROWN &&
dbcItem->InventoryType != INVTYPE_RANGEDRIGHT)
{
LOG_ERROR("sql.sql", "Item (ID={}) in creature_equip_template.ItemID{} for CreatureID = {} and ID = {} is not equipable in a hand, forced to 0.",
equipmentInfo.ItemEntry[i], i + 1, entry, id);
@@ -2741,8 +2741,10 @@ void ObjectMgr::LoadItemTemplates()
return;
}
_itemTemplateStore.rehash(result->GetRowCount());
_itemTemplateStore.reserve(result->GetRowCount());
uint32 count = 0;
// original inspiration https://github.com/TrinityCore/TrinityCore/commit/0c44bd33ee7b42c924859139a9f4b04cf2b91261
bool enforceDBCAttributes = sWorld->getBoolConfig(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES);
do
{
@@ -2859,17 +2861,55 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.FlagsCu = fields[137].Get<uint32>();
// Checks
if (itemTemplate.Class >= MAX_ITEM_CLASS)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({})", entry, itemTemplate.Class);
itemTemplate.Class = ITEM_CLASS_MISC;
}
ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
if (itemTemplate.SubClass >= MaxItemSubclassValues[itemTemplate.Class])
if (dbcitem)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}", entry, itemTemplate.SubClass, itemTemplate.Class);
itemTemplate.SubClass = 0;// exist for all item classes
if (itemTemplate.Class != dbcitem->ClassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
if (enforceDBCAttributes)
itemTemplate.Class = dbcitem->ClassID;
}
if (itemTemplate.SubClass != dbcitem->SubclassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
if (enforceDBCAttributes)
itemTemplate.SubClass = dbcitem->SubclassID;
}
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass);
if (enforceDBCAttributes)
itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclassID;
}
if (itemTemplate.Material != dbcitem->Material)
{
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
if (enforceDBCAttributes)
itemTemplate.Material = dbcitem->Material;
}
if (itemTemplate.InventoryType != dbcitem->InventoryType)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
if (enforceDBCAttributes)
itemTemplate.InventoryType = dbcitem->InventoryType;
}
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
{
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
if (enforceDBCAttributes)
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
}
if (itemTemplate.Sheath != dbcitem->SheatheType)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
if (enforceDBCAttributes)
itemTemplate.Sheath = dbcitem->SheatheType;
}
}
else
LOG_ERROR("sql.sql", "Item (Entry: {}) does not exist in item.dbc! (not correct id?).", entry);
if (itemTemplate.Quality >= MAX_ITEM_QUALITY)
{
@@ -2902,12 +2942,6 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.BuyCount = 1;
}
if (itemTemplate.InventoryType >= MAX_INVTYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({})", entry, itemTemplate.InventoryType);
itemTemplate.InventoryType = INVTYPE_NON_EQUIP;
}
if (itemTemplate.RequiredSkill >= MAX_SKILL_TYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong RequiredSkill value ({})", entry, itemTemplate.RequiredSkill);
@@ -3118,12 +3152,6 @@ void ObjectMgr::LoadItemTemplates()
if (itemTemplate.LockID && !sLockStore.LookupEntry(itemTemplate.LockID))
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong LockID ({})", entry, itemTemplate.LockID);
if (itemTemplate.Sheath >= MAX_SHEATHETYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({})", entry, itemTemplate.Sheath);
itemTemplate.Sheath = SHEATHETYPE_NONE;
}
if (itemTemplate.RandomProperty)
{
// To be implemented later
@@ -9995,8 +10023,8 @@ void ObjectMgr::LoadGameObjectQuestItems()
{
uint32 oldMSTime = getMSTime();
// 0 1
QueryResult result = WorldDatabase.Query("SELECT GameObjectEntry, ItemId FROM gameobject_questitem ORDER BY Idx ASC");
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT GameObjectEntry, ItemId, Idx FROM gameobject_questitem ORDER BY Idx ASC");
if (!result)
{
@@ -10011,6 +10039,21 @@ void ObjectMgr::LoadGameObjectQuestItems()
uint32 entry = fields[0].Get<uint32>();
uint32 item = fields[1].Get<uint32>();
uint32 idx = fields[2].Get<uint32>();
GameObjectTemplate const* goInfo = GetGameObjectTemplate(entry);
if (!goInfo)
{
LOG_ERROR("sql.sql", "Table `gameobject_questitem` has data for nonexistent gameobject (entry: {}, idx: {}), skipped", entry, idx);
continue;
};
ItemEntry const* dbcData = sItemStore.LookupEntry(item);
if (!dbcData)
{
LOG_ERROR("sql.sql", "Table `gameobject_questitem` has nonexistent item (ID: {}) in gameobject (entry: {}, idx: {}), skipped", item, entry, idx);
continue;
};
_gameObjectQuestItemStore[entry].push_back(item);
@@ -10025,8 +10068,8 @@ void ObjectMgr::LoadCreatureQuestItems()
{
uint32 oldMSTime = getMSTime();
// 0 1
QueryResult result = WorldDatabase.Query("SELECT CreatureEntry, ItemId FROM creature_questitem ORDER BY Idx ASC");
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT CreatureEntry, ItemId, Idx FROM creature_questitem ORDER BY Idx ASC");
if (!result)
{
@@ -10041,6 +10084,21 @@ void ObjectMgr::LoadCreatureQuestItems()
uint32 entry = fields[0].Get<uint32>();
uint32 item = fields[1].Get<uint32>();
uint32 idx = fields[2].Get<uint32>();
CreatureTemplate const* creatureInfo = GetCreatureTemplate(entry);
if (!creatureInfo)
{
LOG_ERROR("sql.sql", "Table `creature_questitem` has data for nonexistent creature (entry: {}, idx: {}), skipped", entry, idx);
continue;
};
ItemEntry const* dbcData = sItemStore.LookupEntry(item);
if (!dbcData)
{
LOG_ERROR("sql.sql", "Table `creature_questitem` has nonexistent item (ID: {}) in creature (entry: {}, idx: {}), skipped", item, entry, idx);
continue;
};
_creatureQuestItemStore[entry].push_back(item);
+3 -3
View File
@@ -4928,11 +4928,11 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
{
if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
{
if (ItemTemplate const* itemEntry = sObjectMgr->GetItemTemplate(item_id))
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
{
if (itemEntry->Class == ITEM_CLASS_WEAPON)
if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
{
switch (itemEntry->SubClass)
switch (itemEntry->SubclassID)
{
case ITEM_SUBCLASS_WEAPON_THROWN:
ammoDisplayID = itemEntry->DisplayInfoID;
+1
View File
@@ -138,6 +138,7 @@ enum WorldBoolConfigs
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_PDUMP_NO_PATHS,
CONFIG_PDUMP_NO_OVERWRITE,
+3
View File
@@ -1356,6 +1356,9 @@ void World::LoadConfigSettings(bool reload)
// Dungeon finder
_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetOption<int32>("DungeonFinder.OptionsMask", 5);
// DBC_ItemAttributes
_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetOption<bool>("DBC.EnforceItemAttributes", true);
// Max instances per hour
_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetOption<int32>("AccountInstancesPerHour", 5);
@@ -1127,6 +1127,18 @@ struct HolidaysEntry
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
};
struct ItemEntry
{
uint32 ID; // 0
uint32 ClassID; // 1
uint32 SubclassID; // 2
int32 SoundOverrideSubclassID; // 3
int32 Material; // 4
uint32 DisplayInfoID; // 5
uint32 InventoryType; // 6
uint32 SheatheType; // 7
};
struct ItemBagFamilyEntry
{
uint32 ID; // 0
+1
View File
@@ -68,6 +68,7 @@ char constexpr GtOCTRegenHPfmt[] = "df";
char constexpr GtRegenHPPerSptfmt[] = "df";
char constexpr GtRegenMPPerSptfmt[] = "df";
char constexpr Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
char constexpr Itemfmt[] = "niiiiiii";
char constexpr ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx";
char constexpr ItemDisplayTemplateEntryfmt[] = "nxxxxsxxxxxxxxxxxxxxxxxxx";
//char constexpr ItemCondExtCostsEntryfmt[] = "xiii";