Fixes hotfix loading.

This commit is contained in:
hondacrx
2023-02-04 18:50:13 -05:00
parent 1ebd81dcd7
commit e0e20b6b1c
3 changed files with 228 additions and 214 deletions
+9 -3
View File
@@ -17,7 +17,7 @@ namespace Game.DataStorage
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
string db2Path = dataPath + "/dbc"; string db2Path = $"{dataPath}/dbc";
BitSet availableDb2Locales = new((int)Locale.Total); BitSet availableDb2Locales = new((int)Locale.Total);
foreach (var dir in Directory.GetDirectories(db2Path)) foreach (var dir in Directory.GetDirectories(db2Path))
@@ -33,7 +33,13 @@ namespace Game.DataStorage
uint loadedFileCount = 0; uint loadedFileCount = 0;
DB6Storage<T> ReadDB2<T>(string fileName, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale = 0) where T : new() DB6Storage<T> ReadDB2<T>(string fileName, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale = 0) where T : new()
{ {
return DBReader.Read<T>(availableDb2Locales, $"{db2Path}/{defaultLocale}/", fileName, preparedStatement, preparedStatementLocale, ref loadedFileCount); DB6Storage<T> storage = new();
storage.LoadData($"{db2Path}/{defaultLocale}/{fileName}");
storage.LoadHotfixData(availableDb2Locales, preparedStatement, preparedStatementLocale);
Global.DB2Mgr.AddDB2(storage.GetTableHash(), storage);
loadedFileCount++;
return storage;
} }
AchievementStorage = ReadDB2<AchievementRecord>("Achievement.db2", HotfixStatements.SEL_ACHIEVEMENT, HotfixStatements.SEL_ACHIEVEMENT_LOCALE); AchievementStorage = ReadDB2<AchievementRecord>("Achievement.db2", HotfixStatements.SEL_ACHIEVEMENT, HotfixStatements.SEL_ACHIEVEMENT_LOCALE);
@@ -420,7 +426,7 @@ namespace Game.DataStorage
!MapStorage.ContainsKey(2582) || // last map added in 10.0.5 (47660) !MapStorage.ContainsKey(2582) || // last map added in 10.0.5 (47660)
!SpellNameStorage.ContainsKey(401848)) // last spell added in 10.0.5 (47660) !SpellNameStorage.ContainsKey(401848)) // last spell added in 10.0.5 (47660)
{ {
Log.outError(LogFilter.Misc, "You have _outdated_ DB2 files. Please extract correct versions from current using client."); Log.outFatal(LogFilter.ServerLoading, "You have _outdated_ DB2 files. Please extract correct versions from current using client.");
Environment.Exit(1); Environment.Exit(1);
} }
@@ -8,6 +8,7 @@ using Framework.IO;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Reflection; using System.Reflection;
@@ -29,23 +30,66 @@ namespace Game.DataStorage
public class DB6Storage<T> : Dictionary<uint, T>, IDB2Storage where T : new() public class DB6Storage<T> : Dictionary<uint, T>, IDB2Storage where T : new()
{ {
WDCHeader _header; WDCHeader _header;
string _tableName; string _tableName = typeof(T).Name;
public void LoadData(WDCHeader header, BitSet availableDb2Locales, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale) public void LoadData(string fullFileName)
{ {
_header = header; if (!File.Exists(fullFileName))
_tableName = typeof(T).Name; {
Log.outError(LogFilter.ServerLoading, $"File {fullFileName} not found.");
return;
}
SQLResult result = DB.Hotfix.Query(DB.Hotfix.GetPreparedStatement(preparedStatement)); DBReader reader = new();
if (!result.IsEmpty()) using (var stream = new FileStream(fullFileName, FileMode.Open))
{ {
if (!reader.Load(stream))
{
Log.outError(LogFilter.ServerLoading, $"Error loading {fullFileName}.");
return;
}
}
_header = reader.Header;
foreach (var b in reader.Records)
Add((uint)b.Key, b.Value.As<T>());
}
public void LoadHotfixData(BitSet availableDb2Locales, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale)
{
LoadFromDB(false, preparedStatement);
LoadFromDB(true, preparedStatement);
if (preparedStatementLocale == 0)
return;
for (Locale locale = 0; locale < Locale.Total; ++locale)
{
if (!availableDb2Locales[(int)locale])
continue;
LoadStringsFromDB(false, locale, preparedStatementLocale);
LoadStringsFromDB(true, locale, preparedStatementLocale);
}
}
void LoadFromDB(bool custom, HotfixStatements preparedStatement)
{
// Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
PreparedStatement stmt = DB.Hotfix.GetPreparedStatement(preparedStatement);
stmt.AddValue(0, !custom);
SQLResult result = DB.Hotfix.Query(stmt);
if (result.IsEmpty())
return;
do do
{ {
var obj = new T(); var obj = new T();
int dbIndex = 0; int dbIndex = 0;
var fields = typeof(T).GetFields(); var fields = typeof(T).GetFields();
foreach (var f in typeof(T).GetFields()) foreach (var f in fields)
{ {
Type type = f.FieldType; Type type = f.FieldType;
@@ -178,30 +222,25 @@ namespace Game.DataStorage
} }
} }
var id = (uint)fields[header.IdIndex == -1 ? 0 : header.IdIndex].GetValue(obj); var id = (uint)fields[_header.IdIndex == -1 ? 0 : _header.IdIndex].GetValue(obj);
base[id] = obj; base[id] = obj;
} }
while (result.NextRow()); while (result.NextRow());
} }
if (preparedStatementLocale == 0) void LoadStringsFromDB(bool custom, Locale locale, HotfixStatements preparedStatement)
return;
for (Locale locale = 0; locale < Locale.Total; ++locale)
{ {
if (Global.WorldMgr.GetDefaultDbcLocale() == locale || !availableDb2Locales[(int)locale]) PreparedStatement stmt = DB.Hotfix.GetPreparedStatement(preparedStatement);
continue; stmt.AddValue(0, !custom);
stmt.AddValue(1, locale.ToString());
PreparedStatement stmt = DB.Hotfix.GetPreparedStatement(preparedStatementLocale); SQLResult result = DB.Hotfix.Query(stmt);
stmt.AddValue(0, locale.ToString()); if (result.IsEmpty())
SQLResult localeResult = DB.Hotfix.Query(stmt); return;
if (localeResult.IsEmpty())
continue;
do do
{ {
int index = 0; int index = 0;
var obj = this.LookupByKey(localeResult.Read<uint>(index++)); var obj = this.LookupByKey(result.Read<uint>(index++));
if (obj == null) if (obj == null)
continue; continue;
@@ -211,10 +250,9 @@ namespace Game.DataStorage
continue; continue;
LocalizedString locString = (LocalizedString)f.GetValue(obj); LocalizedString locString = (LocalizedString)f.GetValue(obj);
locString[locale] = localeResult.Read<string>(index++); locString[locale] = result.Read<string>(index++);
}
} while (localeResult.NextRow());
} }
} while (result.NextRow());
} }
TValue[] ReadArray<TValue>(SQLResult result, int dbIndex, int arrayLength) TValue[] ReadArray<TValue>(SQLResult result, int dbIndex, int arrayLength)
@@ -21,37 +21,15 @@ namespace Game.DataStorage
{ {
private const uint WDC3FmtSig = 0x33434457; // WDC3 private const uint WDC3FmtSig = 0x33434457; // WDC3
public static DB6Storage<T> Read<T>(BitSet availableDb2Locales, string db2Path, string fileName, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale, ref uint loadedFileCount) where T : new() public WDCHeader Header;
{ public FieldMetaData[] FieldMeta;
DB6Storage<T> storage = new(); public ColumnMetaData[] ColumnMeta;
public Value32[][] PalletData;
public Dictionary<int, Value32>[] CommonData;
if (!File.Exists(db2Path + fileName)) public Dictionary<int, WDC3Row> Records = new();
{
Log.outError(LogFilter.ServerLoading, $"File {fileName} not found.");
return storage;
}
DBReader reader = new(); public bool Load(Stream stream)
using (var stream = new FileStream(db2Path + fileName, FileMode.Open))
{
if (!reader.Load(stream))
{
Log.outError(LogFilter.ServerLoading, $"Error loading {fileName}.");
return storage;
}
}
foreach (var b in reader._records)
storage.Add((uint)b.Key, b.Value.As<T>());
storage.LoadData(reader.Header, availableDb2Locales, preparedStatement, preparedStatementLocale);
Global.DB2Mgr.AddDB2(reader.Header.TableHash, storage);
loadedFileCount++;
return storage;
}
bool Load(Stream stream)
{ {
using (var reader = new BinaryReader(stream, Encoding.UTF8)) using (var reader = new BinaryReader(stream, Encoding.UTF8))
{ {
@@ -229,16 +207,16 @@ namespace Game.DataStorage
long recordOffset = (recordIndex * Header.RecordSize) - (Header.RecordCount * Header.RecordSize); long recordOffset = (recordIndex * Header.RecordSize) - (Header.RecordCount * Header.RecordSize);
var rec = new WDC3Row(this, bitReader, (int)recordOffset, Header.HasIndexTable() ? (isIndexEmpty ? i : indexData[i]) : -1, hasRef ? refId : -1, stringsTable); var rec = new WDC3Row(this, bitReader, (int)recordOffset, Header.HasIndexTable() ? (isIndexEmpty ? i : indexData[i]) : -1, hasRef ? refId : -1, stringsTable);
_records.Add(rec.Id, rec); Records.Add(rec.Id, rec);
} }
foreach (var copyRow in copyData) foreach (var copyRow in copyData)
{ {
if (copyRow.Key != 0) if (copyRow.Key != 0)
{ {
var rec = _records[copyRow.Value].Clone(); var rec = Records[copyRow.Value].Clone();
rec.Id = copyRow.Key; rec.Id = copyRow.Key;
_records.Add(copyRow.Key, rec); Records.Add(copyRow.Key, rec);
} }
} }
@@ -249,14 +227,6 @@ namespace Game.DataStorage
return true; return true;
} }
internal WDCHeader Header;
internal FieldMetaData[] FieldMeta;
internal ColumnMetaData[] ColumnMeta;
internal Value32[][] PalletData;
internal Dictionary<int, Value32>[] CommonData;
Dictionary<int, WDC3Row> _records = new();
} }
class WDC3Row class WDC3Row