Core/DataStores: Implement optional data in hotfix packets

Port From (https://github.com/TrinityCore/TrinityCore/commit/fbbf40981cc14523fa181cf6125336b254e8ae4d)
This commit is contained in:
hondacrx
2020-12-31 15:04:02 -05:00
parent 2485ea604d
commit 13c9e3d56d
7 changed files with 147 additions and 17 deletions
+2 -2
View File
@@ -285,7 +285,7 @@ namespace Game.DataStorage
SpellVisualKitStorage = ReadDB2<SpellVisualKitRecord>("SpellVisualKit.db2", HotfixStatements.SEL_SPELL_VISUAL_KIT);
SpellXSpellVisualStorage = ReadDB2<SpellXSpellVisualRecord>("SpellXSpellVisual.db2", HotfixStatements.SEL_SPELL_X_SPELL_VISUAL);
SummonPropertiesStorage = ReadDB2<SummonPropertiesRecord>("SummonProperties.db2", HotfixStatements.SEL_SUMMON_PROPERTIES);
//TactKeyStorage = ReadDB2<TactKeyRecord>("TactKey.db2", HotfixStatements.SEL_TACT_KEY);
TactKeyStorage = ReadDB2<TactKeyRecord>("TactKey.db2", HotfixStatements.SEL_TACT_KEY);
TalentStorage = ReadDB2<TalentRecord>("Talent.db2", HotfixStatements.SEL_TALENT, HotfixStatements.SEL_TALENT_LOCALE);
TaxiNodesStorage = ReadDB2<TaxiNodesRecord>("TaxiNodes.db2", HotfixStatements.SEL_TAXI_NODES, HotfixStatements.SEL_TAXI_NODES_LOCALE);
TaxiPathStorage = ReadDB2<TaxiPathRecord>("TaxiPath.db2", HotfixStatements.SEL_TAXI_PATH);
@@ -641,7 +641,7 @@ namespace Game.DataStorage
public static DB6Storage<SpellVisualKitRecord> SpellVisualKitStorage;
public static DB6Storage<SpellXSpellVisualRecord> SpellXSpellVisualStorage;
public static DB6Storage<SummonPropertiesRecord> SummonPropertiesStorage;
//public static DB6Storage<TactKeyRecord> TactKeyStorage;
public static DB6Storage<TactKeyRecord> TactKeyStorage;
public static DB6Storage<TalentRecord> TalentStorage;
public static DB6Storage<TaxiNodesRecord> TaxiNodesStorage;
public static DB6Storage<TaxiPathRecord> TaxiPathStorage;
@@ -39,8 +39,12 @@ namespace Game.DataStorage
[Serializable]
public class DB6Storage<T> : Dictionary<uint, T>, IDB2Storage where T : new()
{
public void LoadData(int indexField, BitSet availableDb2Locales, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale)
uint _tableHash;
public void LoadData(WDCHeader header, BitSet availableDb2Locales, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale)
{
_tableHash = header.TableHash;
SQLResult result = DB.Hotfix.Query(DB.Hotfix.GetPreparedStatement(preparedStatement));
if (!result.IsEmpty())
{
@@ -183,7 +187,7 @@ namespace Game.DataStorage
}
}
var id = (uint)fields[indexField == -1 ? 0 : indexField].GetValue(obj);
var id = (uint)fields[header.IdIndex == -1 ? 0 : header.IdIndex].GetValue(obj);
base[id] = obj;
}
while (result.NextRow());
@@ -358,5 +362,7 @@ namespace Game.DataStorage
{
Remove(id);
}
public uint GetTableHash() { return _tableHash; }
}
}
@@ -58,7 +58,7 @@ namespace Game.DataStorage
foreach (var b in reader._records)
storage.Add((uint)b.Key, b.Value.As<T>());
storage.LoadData(reader.Header.IdIndex, availableDb2Locales, preparedStatement, preparedStatementLocale);
storage.LoadData(reader.Header, availableDb2Locales, preparedStatement, preparedStatementLocale);
Global.DB2Mgr.AddDB2(reader.Header.TableHash, storage);
loadedFileCount++;
+102 -6
View File
@@ -43,7 +43,10 @@ namespace Game.DataStorage
_nameValidators[i] = new List<string>();
for (var i = 0; i < (int)Locale.Total; ++i)
_hotfixBlob[i] = new Dictionary<Tuple<uint, int>, byte[]>();
{
_hotfixBlob[i] = new Dictionary<(uint tableHas, int recordId), byte[]>();
_hotfixOptionalData[i] = new MultiMap<(uint tableHas, int recordId), HotfixOptionalData>();
}
}
public void LoadStores()
@@ -748,7 +751,7 @@ namespace Game.DataStorage
var storeItr = _storage.LookupByKey(tableHash);
if (storeItr != null)
{
Log.outError(LogFilter.ServerLoading, $"Table hash 0x{tableHash:X} points to a loaded DB2 store {nameof(storeItr)}, fill related table instead of hotfix_blob");
Log.outError(LogFilter.Sql, $"Table hash 0x{tableHash:X} points to a loaded DB2 store {nameof(storeItr)}, fill related table instead of hotfix_blob");
continue;
}
@@ -758,20 +761,96 @@ namespace Game.DataStorage
Locale locale = localeName.ToEnum<Locale>();
if (!SharedConst.IsValidLocale(locale))
{
Log.outError(LogFilter.ServerLoading, $"`hotfix_blob` contains invalid locale: {localeName} at TableHash: 0x{tableHash:X} and RecordID: {recordId}");
Log.outError(LogFilter.Sql, $"`hotfix_blob` contains invalid locale: {localeName} at TableHash: 0x{tableHash:X} and RecordID: {recordId}");
continue;
}
if (!availableDb2Locales[(int)locale])
continue;
_hotfixBlob[(int)locale][Tuple.Create(tableHash, recordId)] = result.Read<byte[]>(3);
_hotfixBlob[(int)locale][(tableHash, recordId)] = result.Read<byte[]>(3);
hotfixBlobCount++;
} while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, $"Loaded {hotfixBlobCount} hotfix blob records in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}
public void LoadHotfixOptionalData(BitSet availableDb2Locales)
{
// Register allowed optional data keys
_allowedHotfixOptionalData.Add(CliDB.BroadcastTextStorage.GetTableHash(), Tuple.Create(CliDB.TactKeyStorage.GetTableHash(), (AllowedHotfixOptionalData)ValidateBroadcastTextTactKeyOptionalData));
uint oldMSTime = Time.GetMSTime();
SQLResult result = DB.Hotfix.Query("SELECT TableHash, RecordId, locale, `Key`, `Data` FROM hotfix_optional_data ORDER BY TableHash");
if (result.IsEmpty())
{
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 hotfix optional data records.");
return;
}
uint hotfixOptionalDataCount = 0;
do
{
uint tableHash = result.Read<uint>(0);
var allowedHotfixes = _allowedHotfixOptionalData.LookupByKey(tableHash);
if (allowedHotfixes.Empty())
{
Log.outError(LogFilter.Sql, $"Table `hotfix_optional_data` references DB2 store by hash 0x{tableHash:X} that is not allowed to have optional data");
continue;
}
uint recordId = result.Read<uint>(1);
var db2storage = _storage.LookupByKey(tableHash);
if (db2storage == null)
{
Log.outError(LogFilter.Sql, $"Table `hotfix_optional_data` references unknown DB2 store by hash 0x{tableHash:X} with RecordID: {recordId}");
continue;
}
string localeName = result.Read<string>(2);
Locale locale = localeName.ToEnum<Locale>();
if (!SharedConst.IsValidLocale(locale))
{
Log.outError(LogFilter.Sql, $"`hotfix_optional_data` contains invalid locale: {localeName} at TableHash: 0x{tableHash:X} and RecordID: {recordId}");
continue;
}
if (!availableDb2Locales[(int)locale])
continue;
HotfixOptionalData optionalData = new HotfixOptionalData();
optionalData.Key = result.Read<uint>(3);
var allowedHotfixItr = allowedHotfixes.Find(v =>
{
return v.Item1 == optionalData.Key;
});
if (allowedHotfixItr == null)
{
Log.outError(LogFilter.Sql, $"Table `hotfix_optional_data` references non-allowed optional data key 0x{optionalData.Key:X} for DB2 store by hash 0x{tableHash:X} and RecordID: {recordId}");
continue;
}
optionalData.Data = result.Read<byte[]>(4);
if (!allowedHotfixItr.Item2(optionalData.Data))
{
Log.outError(LogFilter.Sql, $"Table `hotfix_optional_data` contains invalid data for DB2 store 0x{tableHash:X}, RecordID: {recordId} and Key: 0x{optionalData.Key:X}");
continue;
}
_hotfixOptionalData[(int)locale].Add((tableHash, (int)recordId), optionalData);
hotfixOptionalDataCount++;
} while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, $"Loaded {hotfixOptionalDataCount} hotfix optional data records in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}
public bool ValidateBroadcastTextTactKeyOptionalData(byte[] data)
{
return data.Length == 8 + 16;
}
public uint GetHotfixCount() { return (uint)_hotfixData.Count; }
public List<HotfixRecord> GetHotfixData() { return _hotfixData; }
@@ -783,6 +862,13 @@ namespace Game.DataStorage
return _hotfixBlob[(int)locale].LookupByKey(Tuple.Create(tableHash, recordId));
}
public List<HotfixOptionalData> GetHotfixOptionalData(uint tableHash, uint recordId, Locale locale)
{
Cypher.Assert(SharedConst.IsValidLocale(locale), $"Locale {locale} is invalid locale");
return _hotfixOptionalData[(int)locale].LookupByKey((tableHash, (int)recordId));
}
public uint GetEmptyAnimStateID()
{
return (uint)CliDB.AnimationDataStorage.Count;
@@ -2154,9 +2240,13 @@ namespace Game.DataStorage
_storage[tableHash] = store;
}
delegate bool AllowedHotfixOptionalData(byte[] data);
Dictionary<uint, IDB2Storage> _storage = new Dictionary<uint, IDB2Storage>();
List<HotfixRecord> _hotfixData = new List<HotfixRecord>();
Dictionary<Tuple<uint, int>, byte[]>[] _hotfixBlob = new Dictionary<Tuple<uint, int>, byte[]>[(int)Locale.Total];
Dictionary<(uint tableHas, int recordId), byte[]>[] _hotfixBlob = new Dictionary<(uint tableHas, int recordId), byte[]>[(int)Locale.Total];
MultiMap<uint, Tuple<uint, AllowedHotfixOptionalData>> _allowedHotfixOptionalData = new MultiMap<uint, Tuple<uint, AllowedHotfixOptionalData>>();
MultiMap<(uint tableHas, int recordId), HotfixOptionalData>[]_hotfixOptionalData = new MultiMap<(uint tableHas, int recordId), HotfixOptionalData>[(int)Locale.Total];
MultiMap<uint, uint> _areaGroupMembers = new MultiMap<uint, uint>();
MultiMap<uint, ArtifactPowerRecord> _artifactPowers = new MultiMap<uint, ArtifactPowerRecord>();
@@ -2408,7 +2498,13 @@ namespace Game.DataStorage
HotfixID = data.ReadInt32();
}
}
public class HotfixOptionalData
{
public uint Key;
public byte[] Data;
}
class ChrClassesXPowerTypesRecordComparer : IComparer<ChrClassesXPowerTypesRecord>
{
public int Compare(ChrClassesXPowerTypesRecord left, ChrClassesXPowerTypesRecord right)
+16 -6
View File
@@ -29,11 +29,6 @@ namespace Game
void HandleDBQueryBulk(DBQueryBulk dbQuery)
{
IDB2Storage store = Global.DB2Mgr.GetStorage(dbQuery.TableHash);
if (store == null)
{
Log.outError(LogFilter.Network, "CMSG_DB_QUERY_BULK: {0} requested unsupported unknown hotfix type: {1}", GetPlayerInfo(), dbQuery.TableHash);
return;
}
foreach (DBQueryBulk.DBQueryRecord record in dbQuery.Queries)
{
@@ -41,11 +36,18 @@ namespace Game
dbReply.TableHash = dbQuery.TableHash;
dbReply.RecordID = record.RecordID;
if (store.HasRecord(record.RecordID))
if (store != null && store.HasRecord(record.RecordID))
{
dbReply.Status = 1;
dbReply.Timestamp = (uint)GameTime.GetGameTime();
store.WriteRecord(record.RecordID, GetSessionDbcLocale(), dbReply.Data);
var optionalDataEntries = Global.DB2Mgr.GetHotfixOptionalData(dbQuery.TableHash, record.RecordID, GetSessionDbcLocale());
foreach (HotfixOptionalData optionalData in optionalDataEntries)
{
dbReply.Data.WriteUInt32(optionalData.Key);
dbReply.Data.WriteBytes(optionalData.Data);
}
}
else
{
@@ -80,6 +82,14 @@ namespace Game
{
uint pos = hotfixQueryResponse.HotfixContent.GetSize();
storage.WriteRecord((uint)hotfixRecord.RecordID, GetSessionDbcLocale(), hotfixQueryResponse.HotfixContent);
var optionalDataEntries = Global.DB2Mgr.GetHotfixOptionalData(hotfixRecord.TableHash, (uint)hotfixRecord.RecordID, GetSessionDbcLocale());
foreach (HotfixOptionalData optionalData in optionalDataEntries)
{
hotfixQueryResponse.HotfixContent.WriteUInt32(optionalData.Key);
hotfixQueryResponse.HotfixContent.WriteBytes(optionalData.Data);
}
hotfixData.Size.Set(hotfixQueryResponse.HotfixContent.GetSize() - pos);
}
else
+3
View File
@@ -410,6 +410,9 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loading hotfix info...");
Global.DB2Mgr.LoadHotfixData();
Log.outInfo(LogFilter.ServerLoading, "Loading hotfix optional data...");
Global.DB2Mgr.LoadHotfixOptionalData(m_availableDbcLocaleMask);
//- Load M2 fly by cameras
M2Storage.LoadM2Cameras(_dataPath);
@@ -0,0 +1,15 @@
--
-- Table structure for table `hotfix_optional_data`
--
DROP TABLE IF EXISTS `hotfix_optional_data`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `hotfix_optional_data` (
`TableHash` int(10) unsigned NOT NULL,
`RecordId` int(10) unsigned NOT NULL,
`locale` varchar(4) NOT NULL,
`Key` int(10) unsigned NOT NULL,
`Data` blob NOT NULL,
`VerifiedBuild` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;