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: 0c44bd33ee

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 fd26c3c87c

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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

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

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;

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);

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;

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,

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);

View File

@@ -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

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";