Core/DataStores: Implement optional data in hotfix packets
Port From (https://github.com/TrinityCore/TrinityCore/commit/fbbf40981cc14523fa181cf6125336b254e8ae4d)
This commit is contained in:
@@ -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++;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */;
|
||||
Reference in New Issue
Block a user