From f414068883599b983131404ac568de0e2304a2f4 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Fri, 14 Dec 2018 18:43:35 -0500 Subject: [PATCH] Fixed DB2 loading and world login!!!!! --- Source/BNetServer/Networking/Session.cs | 4 +- Source/Framework/Collections/Array.cs | 19 +- Source/Framework/Constants/CliDBConst.cs | 24 +- Source/Framework/Constants/ItemConst.cs | 2 +- Source/Framework/Framework.csproj | 2 +- Source/Framework/IO/ByteBuffer.cs | 57 - Source/Game/Conditions/ConditionManager.cs | 3 +- Source/Game/DataStorage/CliDB.cs | 4 +- .../DataStorage/ClientReader/BitReader.cs | 88 +- .../DataStorage/ClientReader/DB6Storage.cs | 197 ++- .../Game/DataStorage/ClientReader/DBReader.cs | 1064 ++++++++--------- Source/Game/DataStorage/DB2Manager.cs | 8 +- Source/Game/DataStorage/Structs/A_Records.cs | 6 +- Source/Game/DataStorage/Structs/B_Records.cs | 4 +- Source/Game/DataStorage/Structs/C_Records.cs | 4 +- Source/Game/DataStorage/Structs/E_Records.cs | 2 +- Source/Game/DataStorage/Structs/G_Records.cs | 20 +- Source/Game/DataStorage/Structs/I_Records.cs | 10 +- Source/Game/DataStorage/Structs/M_Records.cs | 2 +- Source/Game/DataStorage/Structs/P_Records.cs | 4 +- Source/Game/DataStorage/Structs/S_Records.cs | 2 +- Source/Game/DataStorage/Structs/U_Records.cs | 2 +- .../Game/Entities/Object/Update/UpdateMask.cs | 4 +- Source/Game/Entities/Object/WorldObject.cs | 4 +- Source/Game/Entities/Player/Player.DB.cs | 6 +- Source/Game/Entities/Player/Player.Fields.cs | 2 +- Source/Game/Entities/Taxi/TaxiPathGraph.cs | 2 +- Source/Game/Entities/Unit/Unit.Movement.cs | 3 +- Source/Game/Game.csproj | 5 + Source/Game/Globals/ObjectManager.cs | 4 +- .../Game/Network/Packets/ArtifactPackets.cs | 2 +- .../Network/Packets/AuctionHousePackets.cs | 6 +- .../Network/Packets/AuthenticationPackets.cs | 2 +- .../Game/Network/Packets/BattlenetPackets.cs | 3 +- .../Game/Network/Packets/CharacterPackets.cs | 10 +- .../Game/Network/Packets/EquipmentPackets.cs | 8 +- .../Game/Network/Packets/MovementPackets.cs | 19 +- Source/Game/Network/Packets/QueryPackets.cs | 4 +- .../Game/Network/Packets/ScenarioPackets.cs | 2 +- Source/Game/Network/Packets/SystemPackets.cs | 1 + Source/Game/Network/Packets/TalentPackets.cs | 5 +- .../Packets/TransmogrificationPackets.cs | 2 +- THANKS | 7 +- .../world/master/2018_09_02_00_world.sql | 2 +- 44 files changed, 779 insertions(+), 852 deletions(-) diff --git a/Source/BNetServer/Networking/Session.cs b/Source/BNetServer/Networking/Session.cs index 822c57b43..7d78d3e8a 100644 --- a/Source/BNetServer/Networking/Session.cs +++ b/Source/BNetServer/Networking/Session.cs @@ -469,7 +469,9 @@ namespace BNetServer.Networking { var realmListTicketClientInformation = Json.CreateObject(clientInfo.BlobValue.ToStringUtf8(), true); clientInfoOk = true; - _clientSecret.AddRange(realmListTicketClientInformation.Info.Secret.Select(Convert.ToByte).ToArray()); + int i = 0; + foreach (var b in realmListTicketClientInformation.Info.Secret.Select(Convert.ToByte)) + _clientSecret[i++] = b; } if (!clientInfoOk) diff --git a/Source/Framework/Collections/Array.cs b/Source/Framework/Collections/Array.cs index 2f644c608..7b2a57024 100644 --- a/Source/Framework/Collections/Array.cs +++ b/Source/Framework/Collections/Array.cs @@ -21,6 +21,8 @@ namespace System.Collections.Generic { public class Array : List { + int _limit; + public Array(int size) : base(size) { _limit = size; @@ -31,8 +33,9 @@ namespace System.Collections.Generic _limit = args.Length; } - public Array(int size, T defaultFillValue) : this(size) + public Array(int size, T defaultFillValue) : base(size) { + _limit = size; Fill(defaultFillValue); } @@ -42,14 +45,6 @@ namespace System.Collections.Generic Add(value); } - public new void Add(T value) - { - if (base.Count >= _limit) - throw new InternalBufferOverflowException("Attempted to read more array elements from packet " + base.Count + 1 + " than allowed " + _limit); - - base.Add(value); - } - public new T this[int index] { get @@ -61,8 +56,8 @@ namespace System.Collections.Generic if (index >= Count) { if (Count >= _limit) - throw new InternalBufferOverflowException("Attempted to read more array elements from packet " + base.Count + 1 + " than allowed " + _limit); - base.Insert(index, value); + throw new InternalBufferOverflowException("Attempted to read more array elements from packet " + Count + 1 + " than allowed " + _limit); + Insert(index, value); } else base[index] = value; @@ -75,7 +70,5 @@ namespace System.Collections.Generic { return array.ToArray(); } - - int _limit; } } diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 17f26b08e..cef76ce25 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -13,10 +13,32 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - */ + */ +using System; namespace Framework.Constants { + public enum DB2ColumnCompression : uint + { + None, + Immediate, + Common, + Pallet, + PalletArray, + SignedImmediate + } + + [Flags] + public enum HeaderFlags : short + { + None = 0x0, + OffsetMap = 0x1, + SecondIndex = 0x2, + IndexMap = 0x4, + Unknown = 0x8, + Compressed = 0x10, + } + public enum AbilityLearnType : byte { OnSkillValue = 1, // Spell state will update depending on skill value diff --git a/Source/Framework/Constants/ItemConst.cs b/Source/Framework/Constants/ItemConst.cs index 000645817..82c28c345 100644 --- a/Source/Framework/Constants/ItemConst.cs +++ b/Source/Framework/Constants/ItemConst.cs @@ -36,7 +36,7 @@ namespace Framework.Constants public const int MaxItemSubclassTotal = 21; - public const int MaxItemSetItems = 10; + public const int MaxItemSetItems = 17; public const int MaxItemSetSpells = 8; public static uint[] ItemQualityColors = diff --git a/Source/Framework/Framework.csproj b/Source/Framework/Framework.csproj index 2a7bc8e8f..58730e42c 100644 --- a/Source/Framework/Framework.csproj +++ b/Source/Framework/Framework.csproj @@ -12,7 +12,7 @@ - + diff --git a/Source/Framework/IO/ByteBuffer.cs b/Source/Framework/IO/ByteBuffer.cs index 3a0c81837..cc9e21538 100644 --- a/Source/Framework/IO/ByteBuffer.cs +++ b/Source/Framework/IO/ByteBuffer.cs @@ -305,44 +305,6 @@ namespace Framework.IO WriteBytes(buffer.GetData()); } - public void Replace(int pos, T value) - { - int retpos = (int)writeStream.BaseStream.Position; - - writeStream.Seek(pos, SeekOrigin.Begin); - switch (typeof(T).Name) - { - case "Byte": - WriteUInt8(Convert.ToByte(value)); - break; - case "SByte": - WriteInt8(Convert.ToSByte(value)); - break; - case "Float": - WriteFloat(Convert.ToSingle(value)); - break; - case "Int16": - WriteInt16(Convert.ToInt16(value)); - break; - case "UInt16": - WriteUInt16(Convert.ToUInt16(value)); - break; - case "Int32": - WriteInt32(Convert.ToInt32(value)); - break; - case "UInt32": - WriteUInt32(Convert.ToUInt32(value)); - break; - case "Int64": - WriteInt64(Convert.ToInt64(value)); - break; - case "UInt64": - WriteUInt64(Convert.ToUInt64(value)); - break; - } - writeStream.Seek(retpos, SeekOrigin.Begin); - } - public void WriteVector3(Vector3 pos) { WriteFloat(pos.X); @@ -401,25 +363,6 @@ namespace Framework.IO } #endregion - public int GetPosition() - { - long pos = 0; - if (writeStream != null) - pos = writeStream.BaseStream.Position; - else if (readStream != null) - pos = readStream.BaseStream.Position; - - return (int)pos; - } - - public void SetPosition(long pos) - { - if (writeStream != null) - writeStream.BaseStream.Position = pos; - else if (readStream != null) - readStream.BaseStream.Position = pos; - } - public void FlushBits() { if (BitPosition == 8) diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 01b5f748a..8daa2a6b6 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -2120,7 +2120,8 @@ namespace Game new ConditionTypeInfo("Pet type", true, false, false), new ConditionTypeInfo("On Taxi", false,false, false), new ConditionTypeInfo("Quest state mask", true, true, false), - new ConditionTypeInfo("Objective Complete", true, false, false) + new ConditionTypeInfo("Objective Complete", true, false, false), + new ConditionTypeInfo("Map Difficulty", true, false, false) }; public struct ConditionTypeInfo diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index d29956684..38cd2b25c 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -275,6 +275,8 @@ namespace Game.DataStorage WorldMapOverlayStorage = DBReader.Read("WorldMapOverlay.db2", HotfixStatements.SEL_WORLD_MAP_OVERLAY); WorldSafeLocsStorage = DBReader.Read("WorldSafeLocs.db2", HotfixStatements.SEL_WORLD_SAFE_LOCS, HotfixStatements.SEL_WORLD_SAFE_LOCS_LOCALE); + Global.DB2Mgr.LoadStores(); + foreach (var entry in TaxiPathStorage.Values) { if (!TaxiPathSetBySource.ContainsKey(entry.FromTaxiNode)) @@ -321,8 +323,6 @@ namespace Game.DataStorage OldContinentsNodesMask[field] |= submask; } - Global.DB2Mgr.LoadStores(); - // Check loaded DB2 files proper version if (!AreaTableStorage.ContainsKey(10048) || // last area added in 8.0.1 (28153) !CharTitlesStorage.ContainsKey(633) || // last char title added in 8.0.1 (28153) diff --git a/Source/Game/DataStorage/ClientReader/BitReader.cs b/Source/Game/DataStorage/ClientReader/BitReader.cs index c628a947f..75e9a55c3 100644 --- a/Source/Game/DataStorage/ClientReader/BitReader.cs +++ b/Source/Game/DataStorage/ClientReader/BitReader.cs @@ -15,72 +15,58 @@ * along with this program. If not, see . */ -using Framework.IO; -using System; +using System.Runtime.CompilerServices; +using System.Text; namespace Game.DataStorage { public class BitReader { + private byte[] m_data; + private int m_bitPosition; + private int m_offset; + + public int Position { get => m_bitPosition; set => m_bitPosition = value; } + public int Offset { get => m_offset; set => m_offset = value; } + public byte[] Data { get => m_data; set => m_data = value; } + public BitReader(byte[] data) { - m_array = data; + m_data = data; } public BitReader(byte[] data, int offset) { - m_array = data; - m_readOffset = offset; + m_data = data; + m_offset = offset; } - public uint ReadUInt32(int numBits) + public T Read(int numBits) where T : unmanaged { - uint result = BitConverter.ToUInt32(m_array, m_readOffset + (m_readPos >> 3)) << (32 - numBits - (m_readPos & 7)) >> (32 - numBits); - m_readPos += numBits; + ulong result = Unsafe.As(ref m_data[m_offset + (m_bitPosition >> 3)]) << (64 - numBits - (m_bitPosition & 7)) >> (64 - numBits); + m_bitPosition += numBits; + return Unsafe.As(ref result); + } + + public T ReadSigned(int numBits) where T : unmanaged + { + ulong result = Unsafe.As(ref m_data[m_offset + (m_bitPosition >> 3)]) << (64 - numBits - (m_bitPosition & 7)) >> (64 - numBits); + m_bitPosition += numBits; + ulong signedShift = (1UL << (numBits - 1)); + result = (signedShift ^ result) - signedShift; + return Unsafe.As(ref result); + } + + public string ReadCString() + { + int start = m_bitPosition; + + while (m_data[m_offset + (m_bitPosition >> 3)] != 0) + m_bitPosition += 8; + + string result = Encoding.UTF8.GetString(m_data, m_offset + (start >> 3), (m_bitPosition - start) >> 3); + m_bitPosition += 8; return result; } - - public ulong ReadUInt64(int bitWidth, int bitOffset) - { - int bitsToRead = bitOffset & 7; - ulong result = BitConverter.ToUInt64(m_array, m_readOffset + (m_readPos >> 3)) << (64 - bitsToRead - bitWidth) >> (64 - bitWidth); - m_readPos += bitWidth; - return result; - } - - public byte[] ReadValue(int bitWidth, int bitOffset = 0, bool isSigned = false) - { - ulong result = ReadUInt64(bitWidth, bitOffset); - if (isSigned) - { - ulong mask = 1ul << (bitWidth - 1); - result = (result ^ mask) - mask; - } - - var ulongBytes = BitConverter.GetBytes(result); - byte[] data = new byte[NextPow2((bitWidth + 7) / 8)]; - Buffer.BlockCopy(ulongBytes, 0, data, 0, data.Length); - - return data; - } - - private int NextPow2(int v) - { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return Math.Max(v, 1); - } - - public int Position { get => m_readPos; set => m_readPos = value; } - public int Offset { get => m_readOffset; set => m_readOffset = value; } - - private byte[] m_array; - private int m_readPos; - private int m_readOffset; } } diff --git a/Source/Game/DataStorage/ClientReader/DB6Storage.cs b/Source/Game/DataStorage/ClientReader/DB6Storage.cs index 27537fd4c..918b88524 100644 --- a/Source/Game/DataStorage/ClientReader/DB6Storage.cs +++ b/Source/Game/DataStorage/ClientReader/DB6Storage.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Framework.Database; +using Framework.Dynamic; using Framework.GameMath; using Framework.IO; using System; @@ -37,146 +38,130 @@ namespace Game.DataStorage [Serializable] public class DB6Storage : Dictionary, IDB2Storage where T : new() { - public void LoadData(int indexField, DB6FieldInfo[] helpers, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale) + public void LoadData(int indexField, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale) { SQLResult result = DB.Hotfix.Query(DB.Hotfix.GetPreparedStatement(preparedStatement)); if (!result.IsEmpty()) { do { - var idValue = result.Read(indexField == -1 ? 0 : indexField); + var id = result.Read(indexField == -1 ? 0 : indexField); var obj = new T(); - int index = 0; - for (var fieldIndex = 0; fieldIndex < helpers.Length; fieldIndex++) + + int dbIndex = 0; + foreach (var f in typeof(T).GetFields()) { - var helper = helpers[fieldIndex]; - if (helper.IsArray) + Type type = f.FieldType; + + if (type.IsArray) { - Array array = (Array)helper.Getter(obj); - for (var i = 0; i < array.Length; ++i) + Type arrayElementType = type.GetElementType(); + if (arrayElementType.IsEnum) + arrayElementType = arrayElementType.GetEnumUnderlyingType(); + + Array array = (Array)f.GetValue(obj); + switch (Type.GetTypeCode(arrayElementType)) { - switch (Type.GetTypeCode(helper.FieldType)) - { - case TypeCode.SByte: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.Byte: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.Int16: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.UInt16: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.Int32: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.UInt32: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.Single: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.String: - helper.SetValue(array, result.Read(index++), i); - break; - case TypeCode.Object: - switch (helper.FieldType.Name) - { - case "Vector2": - var vector2 = new Vector2(); - vector2.X = result.Read(index++); - vector2.Y = result.Read(index++); - helper.SetValue(array, vector2, i); - break; - case "Vector3": - var vector3 = new Vector3(); - vector3.X = result.Read(index++); - vector3.Y = result.Read(index++); - vector3.Z = result.Read(index++); - helper.SetValue(array, vector3, i); - break; - case "LocalizedString": - LocalizedString locString = new LocalizedString(); - locString[Global.WorldMgr.GetDefaultDbcLocale()] = result.Read(index++); - helper.SetValue(array, locString, i); - break; - default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", helper.FieldType.Name); - break; - } - break; - default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", helper.FieldType.Name); - break; - } + case TypeCode.SByte: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.Byte: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.Int16: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.UInt16: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.Int32: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.UInt32: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.Single: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.String: + f.SetValue(obj, ReadArray(result, dbIndex, array.Length)); + break; + case TypeCode.Object: + if (arrayElementType == typeof(Vector3)) + f.SetValue(obj, new Vector3(ReadArray(result, dbIndex, 3))); + break; + default: + Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", arrayElementType.Name); + break; } + + dbIndex += array.Length; } else { - switch (Type.GetTypeCode(helper.FieldType)) + if (type.IsEnum) + type = type.GetEnumUnderlyingType(); + + switch (Type.GetTypeCode(type)) { case TypeCode.SByte: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.Byte: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.Int16: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.UInt16: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.Int32: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.UInt32: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.Single: - helper.SetValue(obj, result.Read(index++)); + f.SetValue(obj, result.Read(dbIndex++)); break; case TypeCode.String: - string str = result.Read(index++); - helper.SetValue(obj, str); + string str = result.Read(dbIndex++); + f.SetValue(obj, str); break; case TypeCode.Object: - switch (helper.FieldType.Name) + if (type == typeof(LocalizedString)) { - case "Vector2": - var vector2 = new Vector2(); - vector2.X = result.Read(index++); - vector2.Y = result.Read(index++); - helper.SetValue(obj, vector2); - break; - case "Vector3": - var vector3 = new Vector3(); - vector3.X = result.Read(index++); - vector3.Y = result.Read(index++); - vector3.Z = result.Read(index++); - helper.SetValue(obj, vector3); - break; - case "LocalizedString": - LocalizedString locString = new LocalizedString(); - locString[Global.WorldMgr.GetDefaultDbcLocale()] = result.Read(index++); - helper.SetValue(obj, locString); - break; - default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", helper.FieldType.Name); - break; + LocalizedString locString = new LocalizedString(); + locString[Global.WorldMgr.GetDefaultDbcLocale()] = result.Read(dbIndex++); + + f.SetValue(obj, locString); + } + else if (type == typeof(Vector2)) + { + f.SetValue(obj, new Vector2(ReadArray(result, dbIndex, 2))); + dbIndex += 2; + } + else if (type == typeof(Vector3)) + { + f.SetValue(obj, new Vector3(ReadArray(result, dbIndex, 3))); + dbIndex += 3; + } + else if (type == typeof(FlagArray128)) + { + f.SetValue(obj, new FlagArray128(ReadArray(result, dbIndex, 4))); + dbIndex += 4; } break; default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", helper.FieldType.Name); + Log.outError(LogFilter.ServerLoading, "Wrong Type: {0}", type.Name); break; } } } - base[idValue] = obj; + base[id] = obj; } while (result.NextRow()); } @@ -202,19 +187,27 @@ namespace Game.DataStorage if (obj == null) continue; - for (var i = 0; i < helpers.Length; i++) + foreach (var f in typeof(T).GetFields()) { - var fieldInfo = helpers[i]; - if (fieldInfo.FieldType != typeof(LocalizedString)) + if (f.FieldType != typeof(LocalizedString)) continue; - LocalizedString locString = (LocalizedString)fieldInfo.Getter(obj); + LocalizedString locString = (LocalizedString)f.GetValue(obj); locString[locale] = localeResult.Read(index++); } } while (localeResult.NextRow()); } } + TValue[] ReadArray(SQLResult result, int dbIndex, int arrayLength) + { + TValue[] values = new TValue[arrayLength]; + for (int i = 0; i < arrayLength; ++i) + values[i] = result.Read(dbIndex + i); + + return values; + } + public bool HasRecord(uint id) { return ContainsKey(id); diff --git a/Source/Game/DataStorage/ClientReader/DBReader.cs b/Source/Game/DataStorage/ClientReader/DBReader.cs index c1b0da0d4..8f15a1945 100644 --- a/Source/Game/DataStorage/ClientReader/DBReader.cs +++ b/Source/Game/DataStorage/ClientReader/DBReader.cs @@ -24,596 +24,542 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; namespace Game.DataStorage { class DBReader { + private const int HeaderSize = 72 + 1 * 36; + private const uint WDC2FmtSig = 0x32434457; // WDC2 + public static DB6Storage Read(string fileName, HotfixStatements preparedStatement, HotfixStatements preparedStatementLocale = 0) where T : new() { - ClearData(); - DB6Storage storage = new DB6Storage(); if (!File.Exists(CliDB.DataPath + fileName)) { - Log.outError(LogFilter.ServerLoading, "File {0} not found.", fileName); + Log.outError(LogFilter.ServerLoading, $"File {fileName} not found."); return storage; } - //First lets load field Info - var fields = typeof(T).GetFields(); - DB6FieldInfo[] fieldsInfo = new DB6FieldInfo[fields.Length]; - for (var i = 0; i < fields.Length; ++i) - fieldsInfo[i] = new DB6FieldInfo(fields[i]); - - using (var fileReader = new BinaryReader(new MemoryStream(File.ReadAllBytes(CliDB.DataPath + fileName)))) + DBReader reader = new DBReader(); + using (var stream = new FileStream(CliDB.DataPath + fileName, FileMode.Open)) { - ReadHeader(fileReader); - - var records = ReadData(fileReader); - foreach (var pair in records) + if (!reader.Load(stream)) { - using (BinaryReader dataReader = new BinaryReader(new MemoryStream(pair.Value), System.Text.Encoding.UTF8)) - { - var obj = new T(); - - int objectFieldIndex = 0; - //First check if index is in data - if (Header.HasIndexTable()) - fieldsInfo[objectFieldIndex++].SetValue(obj, (uint)pair.Key); - - for (var dataFieldIndex = 0; dataFieldIndex < Header.FieldCount; ++dataFieldIndex) - { - int arrayLength = ColumnMeta[dataFieldIndex].ArraySize; - if (arrayLength > 1) - { - while (arrayLength > 0) - { - var fieldInfo = fieldsInfo[objectFieldIndex++]; - if (fieldInfo.IsArray) - { - Array array = (Array)fieldInfo.Getter(obj); - SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader); - - arrayLength -= array.Length; - } - else - { - //Only Data is Array - if (Type.GetTypeCode(fieldInfo.FieldType) == TypeCode.Object) - { - switch (fieldInfo.FieldType.Name) - { - case "Vector2": - fieldInfo.SetValue(obj, dataReader.Read()); - arrayLength -= 2; - break; - case "Vector3": - fieldInfo.SetValue(obj, dataReader.Read()); - arrayLength -= 3; - break; - case "LocalizedString": - LocalizedString locString = new LocalizedString(); - locString[Global.WorldMgr.GetDefaultDbcLocale()] = GetString(dataReader); - fieldInfo.SetValue(obj, locString); - arrayLength -= 1; - break; - case "FlagArray128": - fieldInfo.SetValue(obj, new FlagArray128(dataReader.ReadUInt32(), dataReader.ReadUInt32(), dataReader.ReadUInt32(), dataReader.ReadUInt32())); - arrayLength -= 4; - break; - default: - Log.outError(LogFilter.ServerLoading, "Unknown Array Type {0} in DBClient File", fieldInfo.FieldType.Name, nameof(T)); - break; - } - } - else - SetValue(obj, fieldInfo, dataReader); - } - - dataReader.BaseStream.Position += GetPadding(fieldInfo.FieldType, dataFieldIndex); - } - } - else - { - var fieldInfo = fieldsInfo[objectFieldIndex++]; - if (fieldInfo.IsArray) - { - Array array = (Array)fieldInfo.Getter(obj); - SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader); - - dataFieldIndex += array.Length - 1; - } - else - SetValue(obj, fieldInfo, dataReader); - - dataReader.BaseStream.Position += GetPadding(fieldInfo.FieldType, dataFieldIndex); - } - } - - //Check if there is parent ids and fill them - if (objectFieldIndex < fieldsInfo.Length && Header.LookupColumnCount > 0) - fieldsInfo[objectFieldIndex].SetValue(obj, dataReader.ReadUInt32()); - - storage.Add((uint)pair.Key, obj); - } + Log.outError(LogFilter.ServerLoading, $"Error loading {fileName}."); + return storage; } - - storage.LoadData(Header.IdIndex, fieldsInfo, preparedStatement, preparedStatementLocale); } - Global.DB2Mgr.AddDB2(Header.TableHash, storage); + foreach (var b in reader._records) + storage.Add((uint)b.Key, b.Value.As()); + + storage.LoadData(reader.Header.IdIndex, preparedStatement, preparedStatementLocale); + + Global.DB2Mgr.AddDB2(reader.Header.TableHash, storage); CliDB.LoadedFileCount++; return storage; } - static void ClearData() + bool Load(Stream stream) { - Header = null; - StringTable = null; - FieldStructure = null; - ColumnMeta = null; - } - - static void ReadHeader(BinaryReader reader) - { - Header = new DB6Header(); - Header.Signature = reader.ReadUInt32(); - Header.RecordCount = reader.ReadUInt32(); - Header.FieldCount = reader.ReadUInt32(); - Header.RecordSize = reader.ReadUInt32(); - Header.StringTableSize = reader.ReadUInt32(); // also offset for sparse table - - Header.TableHash = reader.ReadUInt32(); - Header.LayoutHash = reader.ReadUInt32(); - Header.MinId = reader.ReadInt32(); - Header.MaxId = reader.ReadInt32(); - Header.Locale = reader.ReadInt32(); - Header.Flags = (HeaderFlags)reader.ReadUInt16(); - Header.IdIndex = reader.ReadUInt16(); - Header.TotalFieldCount = reader.ReadUInt32(); - - Header.BitpackedDataOffset = reader.ReadUInt32(); - Header.LookupColumnCount = reader.ReadUInt32(); - Header.ColumnMetaSize = reader.ReadUInt32(); - Header.CommonDataSize = reader.ReadUInt32(); - Header.PalletDataSize = reader.ReadUInt32(); - Header.SectionsCount = reader.ReadUInt32(); - } - - static Dictionary ReadData(BinaryReader reader) - { - Dictionary records = new Dictionary(); - - var sections = reader.ReadArray(Header.SectionsCount); - - //Gather field structures - FieldStructure = reader.ReadArray(Header.FieldCount); - - // column meta data - ColumnMeta = new List(); - for (int i = 0; i < Header.FieldCount; i++) + using (var reader = new BinaryReader(stream, Encoding.UTF8)) { - var column = new ColumnStructureEntry() + Header = new WDCHeader(); + Header.Signature = reader.ReadUInt32(); + if (Header.Signature != WDC2FmtSig) + return false; + + Header.RecordCount = reader.ReadUInt32(); + Header.FieldCount = reader.ReadUInt32(); + Header.RecordSize = reader.ReadUInt32(); + Header.StringTableSize = reader.ReadUInt32(); + Header.TableHash = reader.ReadUInt32(); + Header.LayoutHash = reader.ReadUInt32(); + Header.MinId = reader.ReadInt32(); + Header.MaxId = reader.ReadInt32(); + Header.Locale = reader.ReadInt32(); + Header.Flags = (HeaderFlags)reader.ReadUInt16(); + Header.IdIndex = reader.ReadUInt16(); + Header.TotalFieldCount = reader.ReadUInt32(); + Header.BitpackedDataOffset = reader.ReadUInt32(); + Header.LookupColumnCount = reader.ReadUInt32(); + Header.ColumnMetaSize = reader.ReadUInt32(); + Header.CommonDataSize = reader.ReadUInt32(); + Header.PalletDataSize = reader.ReadUInt32(); + Header.SectionsCount = reader.ReadUInt32(); + + var sections = reader.ReadArray(Header.SectionsCount); + + // field meta data + FieldMeta = reader.ReadArray(Header.FieldCount); + + // column meta data + ColumnMeta = reader.ReadArray(Header.FieldCount); + + // pallet data + PalletData = new Value32[ColumnMeta.Length][]; + for (int i = 0; i < ColumnMeta.Length; i++) { - RecordOffset = reader.ReadUInt16(), - Size = reader.ReadUInt16(), - AdditionalDataSize = reader.ReadUInt32(), // size of pallet / sparse values - CompressionType = (DB2ColumnCompression)reader.ReadUInt32(), - BitOffset = reader.ReadInt32(), - BitWidth = reader.ReadInt32(), - Cardinality = reader.ReadInt32() - }; - - // preload arraysizes - if (column.CompressionType == DB2ColumnCompression.None) - column.ArraySize = Math.Max(column.Size / FieldStructure[i].BitCount, 1); - else if (column.CompressionType == DB2ColumnCompression.PalletArray) - column.ArraySize = Math.Max(column.Cardinality, 1); - - ColumnMeta.Add(column); - } - - // Pallet values - for (int i = 0; i < ColumnMeta.Count; i++) - { - if (ColumnMeta[i].CompressionType == DB2ColumnCompression.Pallet || ColumnMeta[i].CompressionType == DB2ColumnCompression.PalletArray) - { - int elements = (int)ColumnMeta[i].AdditionalDataSize / 4; - int cardinality = Math.Max(ColumnMeta[i].Cardinality, 1); - - ColumnMeta[i].PalletValues = new List(); - for (int j = 0; j < elements / cardinality; j++) - ColumnMeta[i].PalletValues.Add(reader.ReadBytes(cardinality * 4)); - } - } - - // Sparse values - for (int i = 0; i < ColumnMeta.Count; i++) - { - if (ColumnMeta[i].CompressionType == DB2ColumnCompression.CommonData) - { - ColumnMeta[i].SparseValues = new Dictionary(); - for (int j = 0; j < ColumnMeta[i].AdditionalDataSize / 8; j++) - ColumnMeta[i].SparseValues[reader.ReadInt32()] = reader.ReadBytes(4); - } - } - - List> offsetmap = new List>(); - - bool hasIndexTable = Header.HasIndexTable(); - - byte[] recordData; - for (int sectionIndex = 0; sectionIndex < Header.SectionsCount; sectionIndex++) - { - reader.BaseStream.Position = sections[sectionIndex].FileOffset; - - if (Header.HasOffsetTable()) - { - // sparse data with inlined strings - recordData = reader.ReadBytes(sections[sectionIndex].SparseTableOffset - sections[sectionIndex].FileOffset); - - // OffsetTable - for (int i = 0; i < (Header.MaxId - Header.MinId + 1); i++) + if (ColumnMeta[i].CompressionType == DB2ColumnCompression.Pallet || ColumnMeta[i].CompressionType == DB2ColumnCompression.PalletArray) { - int offset = reader.ReadInt32(); - int length = reader.ReadInt32(); - - offsetmap.Add(new Tuple(offset, length)); - } - } - else - { - // records data - recordData = reader.ReadBytes((int)(sections[sectionIndex].NumRecords * Header.RecordSize)); - - Array.Resize(ref recordData, recordData.Length + 8); // pad with extra zeros so we don't crash when reading - - // string data - StringTable = new Dictionary(); - - for (int i = 0; i < sections[sectionIndex].StringTableSize;) - { - int oldPos = (int)reader.BaseStream.Position; - - StringTable[i] = reader.ReadCString(); - - i += (int)(reader.BaseStream.Position - oldPos); + PalletData[i] = reader.ReadArray(ColumnMeta[i].AdditionalDataSize / 4); } } - // IndexTable - int[] m_indexes = reader.ReadArray((uint)(sections[sectionIndex].IndexDataSize / 4)); + // common data + CommonData = new Dictionary[ColumnMeta.Length]; - // duplicate rows data - Dictionary copyData = new Dictionary(); - - for (int i = 0; i < sections[sectionIndex].CopyTableSize / 8; i++) - copyData[reader.ReadInt32()] = reader.ReadInt32(); - - // Relationships - RelationShipData relationShipData = null; - if (sections[sectionIndex].ParentLookupDataSize > 0) + for (int i = 0; i < ColumnMeta.Length; i++) { - relationShipData = new RelationShipData() + if (ColumnMeta[i].CompressionType == DB2ColumnCompression.Common) { - Records = reader.ReadUInt32(), - MinId = reader.ReadUInt32(), - MaxId = reader.ReadUInt32(), - Entries = new Dictionary() - }; + Dictionary commonValues = new Dictionary(); + CommonData[i] = commonValues; - for (int i = 0; i < relationShipData.Records; i++) - { - byte[] foreignKey = reader.ReadBytes(4); - uint index = reader.ReadUInt32(); - // has duplicates just like the copy table does... why? - if (!relationShipData.Entries.ContainsKey(index)) - relationShipData.Entries.Add(index, foreignKey); + for (int j = 0; j < ColumnMeta[i].AdditionalDataSize / 8; j++) + commonValues[reader.ReadInt32()] = reader.Read(); } } - // Record Data - if (Header.HasOffsetTable() && hasIndexTable) + for (int sectionIndex = 0; sectionIndex < Header.SectionsCount; sectionIndex++) { - for (int i = 0; i < Header.RecordCount; ++i) + reader.BaseStream.Position = sections[sectionIndex].FileOffset; + + byte[] recordsData; + Dictionary stringsTable = null; + List> offsetmap = null; + if (!Header.HasOffsetTable()) { - int id = m_indexes[records.Count]; - var map = offsetmap[i]; + // records data + recordsData = reader.ReadBytes((int)(sections[sectionIndex].NumRecords * Header.RecordSize)); - reader.BaseStream.Position = map.Item1; + Array.Resize(ref recordsData, recordsData.Length + 8); // pad with extra zeros so we don't crash when reading - byte[] data = reader.ReadBytes(map.Item2); + // string data + stringsTable = new Dictionary(); - IEnumerable recordbytes = data; - - // append relationship id - if (relationShipData != null) + for (int i = 0; i < sections[sectionIndex].StringTableSize;) { - // seen cases of missing indicies - if (relationShipData.Entries.TryGetValue((uint)i, out byte[] foreignData)) - recordbytes = recordbytes.Concat(foreignData); - else - recordbytes = recordbytes.Concat(new byte[4]); - } + long oldPos = reader.BaseStream.Position; - records.Add(id, recordbytes.ToArray()); + stringsTable[oldPos] = reader.ReadCString(); + + i += (int)(reader.BaseStream.Position - oldPos); + } } - } - else - { - BitReader bitReader = new BitReader(recordData); + else + { + // sparse data with inlined strings + recordsData = reader.ReadBytes(sections[sectionIndex].SparseTableOffset - sections[sectionIndex].FileOffset); + + if (reader.BaseStream.Position != sections[sectionIndex].SparseTableOffset) + throw new Exception("reader.BaseStream.Position != sections[sectionIndex].SparseTableOffset"); + + offsetmap = new List>(); + for (int i = 0; i < (Header.MaxId - Header.MinId + 1); i++) + { + int offset = reader.ReadInt32(); + short length = reader.ReadInt16(); + + if (offset == 0 || length == 0) + continue; + + offsetmap.Add(new Tuple(offset, length)); + } + } + + // index data + int[] indexData = reader.ReadArray((uint)(sections[sectionIndex].IndexDataSize / 4)); + + // duplicate rows data + Dictionary copyData = new Dictionary(); + + for (int i = 0; i < sections[sectionIndex].CopyTableSize / 8; i++) + copyData[reader.ReadInt32()] = reader.ReadInt32(); + + // reference data + ReferenceData refData = null; + + if (sections[sectionIndex].ParentLookupDataSize > 0) + { + refData = new ReferenceData + { + NumRecords = reader.ReadInt32(), + MinId = reader.ReadInt32(), + MaxId = reader.ReadInt32() + }; + + refData.Entries = new Dictionary(); + ReferenceEntry[] entries = reader.ReadArray((uint)refData.NumRecords); + foreach (var entry in entries) + if (!refData.Entries.ContainsKey(entry.Index)) + refData.Entries[entry.Index] = entry.Id; + } + else + { + refData = new ReferenceData + { + Entries = new Dictionary() + }; + } + + BitReader bitReader = new BitReader(recordsData); + for (int i = 0; i < Header.RecordCount; ++i) { bitReader.Position = 0; - bitReader.Offset = i * (int)Header.RecordSize; + if (offsetmap != null) + bitReader.Offset = offsetmap[i].Item1 - sections[sectionIndex].FileOffset; + else + bitReader.Offset = i * (int)Header.RecordSize; - MemoryStream stream = new MemoryStream(); - BinaryWriter binaryWriter = new BinaryWriter(stream); + bool hasRef = refData.Entries.TryGetValue(i, out int refId); + + var rec = new WDC2Row(this, bitReader, sections[sectionIndex].FileOffset, sections[sectionIndex].IndexDataSize != 0 ? indexData[i] : -1, hasRef ? refId : -1, stringsTable); - int id = 0; if (sections[sectionIndex].IndexDataSize != 0) - id = m_indexes[i]; + _records.Add(indexData[i], rec); + else + _records.Add(rec.Id, rec); + } - for (int f = 0; f < Header.FieldCount; f++) - { - int bitWidth = ColumnMeta[f].BitWidth; - - switch (ColumnMeta[f].CompressionType) - { - case DB2ColumnCompression.None: - int bitSize = FieldStructure[f].BitCount; - if (!hasIndexTable && f == Header.IdIndex) - { - id = (int)bitReader.ReadUInt32(bitSize);// always read Ids as ints - binaryWriter.Write(id); - } - else - { - for (int x = 0; x < ColumnMeta[f].ArraySize; x++) - binaryWriter.Write(bitReader.ReadValue(bitSize)); - } - break; - - case DB2ColumnCompression.Immediate: - case DB2ColumnCompression.SignedImmediate: - if (!hasIndexTable && f == Header.IdIndex) - { - id = (int)bitReader.ReadUInt32(bitWidth);// always read Ids as ints - binaryWriter.Write(id); - continue; - } - else - binaryWriter.Write(bitReader.ReadValue(bitWidth, ColumnMeta[f].BitOffset, ColumnMeta[f].CompressionType == DB2ColumnCompression.SignedImmediate)); - break; - - case DB2ColumnCompression.CommonData: - if (ColumnMeta[f].SparseValues.TryGetValue(id, out byte[] valBytes)) - binaryWriter.Write(valBytes); - else - binaryWriter.Write(ColumnMeta[f].BitOffset); - break; - - case DB2ColumnCompression.Pallet: - case DB2ColumnCompression.PalletArray: - uint palletIndex = bitReader.ReadUInt32(bitWidth); - binaryWriter.Write(ColumnMeta[f].PalletValues[(int)palletIndex]); - break; - - default: - throw new Exception($"Unknown compression {ColumnMeta[f].CompressionType}"); - } - } - - // append relationship id - if (relationShipData != null) - { - // seen cases of missing indicies - if (relationShipData.Entries.TryGetValue((uint)i, out byte[] foreignData)) - binaryWriter.Write(foreignData); - else - binaryWriter.Write(0); - } - - records.Add(id, stream.ToArray()); + foreach (var copyRow in copyData) + { + var rec = _records[copyRow.Value].Clone(); + rec.Id = copyRow.Key; + _records.Add(copyRow.Key, rec); } } - - foreach (var copyRow in copyData) - { - byte[] newrecord = records[copyRow.Value].ToArray(); - records.Add(copyRow.Key, newrecord); - } } - return records; + return true; } - static Dictionary bytecounts = new Dictionary() + internal WDCHeader Header; + internal FieldMetaData[] FieldMeta; + internal ColumnMetaData[] ColumnMeta; + internal Value32[][] PalletData; + internal Dictionary[] CommonData; + + Dictionary _records = new Dictionary(); + } + + class WDC2Row + { + private BitReader _data; + private int _dataOffset; + private int _recordsOffset; + private int _refId; + private bool _dataHasId; + + public int Id { get; set; } + + private FieldMetaData[] _fieldMeta; + private ColumnMetaData[] _columnMeta; + private Value32[][] _palletData; + private Dictionary[] _commonData; + private Dictionary _stringsTable; + + public WDC2Row(DBReader reader, BitReader data, int recordsOffset, int id, int refId, Dictionary stringsTable) { - { typeof(byte), 1 }, - { typeof(sbyte), 1 }, - { typeof(short), 2 }, - { typeof(ushort), 2 }, - }; + _data = data; + _recordsOffset = recordsOffset; + _refId = refId; - static int GetPadding(Type type, int fieldIndex) - { - if (ColumnMeta[fieldIndex].CompressionType < DB2ColumnCompression.CommonData) - return 0; + _dataOffset = _data.Offset; - if (!bytecounts.ContainsKey(type)) - return 0; + _fieldMeta = reader.FieldMeta; + _columnMeta = reader.ColumnMeta.ToArray(); + _palletData = reader.PalletData; + _commonData = reader.CommonData; + _stringsTable = stringsTable; - return 4 - bytecounts[type]; - } - - static FieldMetaData[] GetBits() - { - List bits = new List(); - for (int i = 0; i < ColumnMeta.Count; i++) + if (id != -1) + Id = id; + else { - short bitcount = (short)(FieldStructure[i].BitCount == 64 ? FieldStructure[i].BitCount : 0); // force bitcounts - bits.Add(new FieldMetaData(bitcount, 0)); - } + int idFieldIndex = reader.Header.IdIndex; + _data.Position = _columnMeta[idFieldIndex].RecordOffset; - return bits.ToArray(); - } - - static void SetArrayValue(object obj, uint arraySize, DB6FieldInfo fieldInfo, BinaryReader reader) - { - switch (Type.GetTypeCode(fieldInfo.FieldType)) - { - case TypeCode.SByte: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.Byte: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.Int16: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.UInt16: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.Int32: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.UInt32: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.Int64: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.UInt64: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.Single: - fieldInfo.SetValue(obj, reader.ReadArray(arraySize)); - break; - case TypeCode.String: - string[] str = new string[arraySize]; - for (var i = 0; i < arraySize; ++i) - str[i] = GetString(reader); - fieldInfo.SetValue(obj, str); - break; - default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", fieldInfo.FieldType.Name); - break; + Id = GetFieldValue(idFieldIndex); + _dataHasId = true; } } - static void SetValue(object obj, DB6FieldInfo fieldInfo, BinaryReader reader) + T GetFieldValue(int fieldIndex) where T : unmanaged { - switch (Type.GetTypeCode(fieldInfo.FieldType)) + var columnMeta = _columnMeta[fieldIndex]; + switch (columnMeta.CompressionType) { - case TypeCode.SByte: - fieldInfo.SetValue(obj, reader.ReadSByte()); - break; - case TypeCode.Byte: - fieldInfo.SetValue(obj, reader.ReadByte()); - break; - case TypeCode.Int16: - fieldInfo.SetValue(obj, reader.ReadInt16()); - break; - case TypeCode.UInt16: - fieldInfo.SetValue(obj, reader.ReadUInt16()); - break; - case TypeCode.Int32: - fieldInfo.SetValue(obj, reader.ReadInt32()); - break; - case TypeCode.UInt32: - fieldInfo.SetValue(obj, reader.ReadUInt32()); - break; - case TypeCode.Int64: - fieldInfo.SetValue(obj, reader.ReadInt64()); - break; - case TypeCode.UInt64: - fieldInfo.SetValue(obj, reader.ReadUInt64()); - break; - case TypeCode.Single: - fieldInfo.SetValue(obj, reader.ReadSingle()); - break; - case TypeCode.String: - string str = GetString(reader); - fieldInfo.SetValue(obj, str); - break; - case TypeCode.Object: - switch (fieldInfo.FieldType.Name) + case DB2ColumnCompression.None: + int bitSize = 32 - _fieldMeta[fieldIndex].Bits; + if (bitSize > 0) + return _data.Read(bitSize); + else + return _data.Read(columnMeta.Immediate.BitWidth); + case DB2ColumnCompression.Immediate: + return _data.Read(columnMeta.Immediate.BitWidth); + case DB2ColumnCompression.SignedImmediate: + return _data.ReadSigned(columnMeta.Immediate.BitWidth); + case DB2ColumnCompression.Common: + if (_commonData[fieldIndex].TryGetValue(Id, out Value32 val)) + return val.As(); + else + return columnMeta.Common.DefaultValue.As(); + case DB2ColumnCompression.Pallet: + case DB2ColumnCompression.PalletArray: //need for SummonProperties.db2 + uint palletIndex = _data.Read(columnMeta.Pallet.BitWidth); + return _palletData[fieldIndex][palletIndex].As(); + } + throw new Exception(string.Format("Unexpected compression type {0}", _columnMeta[fieldIndex].CompressionType)); + } + + T[] GetFieldValueArray(int fieldIndex, int arraySize) where T : unmanaged + { + var columnMeta = _columnMeta[fieldIndex]; + + switch (columnMeta.CompressionType) + { + case DB2ColumnCompression.None: + int bitSize = 32 - _fieldMeta[fieldIndex].Bits; + + T[] arr1 = new T[arraySize]; + + for (int i = 0; i < arr1.Length; i++) { - case "Vector2": - fieldInfo.SetValue(obj, reader.Read()); + if (bitSize > 0) + arr1[i] = _data.Read(bitSize); + else + arr1[i] = _data.Read(columnMeta.Immediate.BitWidth); + } + + return arr1; + case DB2ColumnCompression.Immediate: + T[] arr2 = new T[arraySize]; + + for (int i = 0; i < arr2.Length; i++) + arr2[i] = _data.Read(columnMeta.Immediate.BitWidth); + + return arr2; + case DB2ColumnCompression.SignedImmediate: + T[] arr4 = new T[arraySize]; + + for (int i = 0; i < arr4.Length; i++) + arr4[i] = _data.ReadSigned(columnMeta.Immediate.BitWidth); + + return arr4; + case DB2ColumnCompression.PalletArray: + int cardinality = columnMeta.Pallet.Cardinality; + + if (arraySize != cardinality) + throw new Exception("Struct missmatch for pallet array field?"); + + uint palletArrayIndex = _data.Read(columnMeta.Pallet.BitWidth); + + T[] arr3 = new T[cardinality]; + + for (int i = 0; i < arr3.Length; i++) + arr3[i] = _palletData[fieldIndex][i + cardinality * (int)palletArrayIndex].As(); + + return arr3; + } + throw new Exception(string.Format("Unexpected compression type {0}", columnMeta.CompressionType)); + } + + public T As() where T : new() + { + _data.Position = 0; + _data.Offset = _dataOffset; + + int fieldIndex = 0; + T obj = new T(); + + foreach (var f in typeof(T).GetFields()) + { + Type type = f.FieldType; + + if (f.Name == "Id" && !_dataHasId) + { + f.SetValue(obj, (uint)Id); + continue; + } + + if (fieldIndex >= _fieldMeta.Length) + { + if (_refId != -1) + f.SetValue(obj, (uint)_refId); + continue; + } + + if (type.IsArray) + { + Type arrayElementType = type.GetElementType(); + if (arrayElementType.IsEnum) + arrayElementType = arrayElementType.GetEnumUnderlyingType(); + + Array atr = (Array)f.GetValue(obj); + switch (Type.GetTypeCode(arrayElementType)) + { + case TypeCode.SByte: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); break; - case "Vector3": - fieldInfo.SetValue(obj, reader.Read()); + case TypeCode.Byte: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); break; - case "LocalizedString": - LocalizedString locString = new LocalizedString(); - locString[Global.WorldMgr.GetDefaultDbcLocale()] = GetString(reader); - fieldInfo.SetValue(obj, locString); + case TypeCode.Int16: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.UInt16: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.Int32: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.UInt32: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.UInt64: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.Single: + f.SetValue(obj, GetFieldValueArray(fieldIndex, atr.Length)); + break; + case TypeCode.String: + string[] array = new string[atr.Length]; + + if (_stringsTable == null) + { + for (int i = 0; i < array.Length; i++) + array[i] = _data.ReadCString(); + } + else + { + var pos = _recordsOffset + _data.Offset + (_data.Position >> 3); + + int[] strIdx = GetFieldValueArray(fieldIndex, atr.Length); + + for (int i = 0; i < array.Length; i++) + array[i] = _stringsTable[pos + i * 4 + strIdx[i]]; + } + + f.SetValue(obj, array); + break; + case TypeCode.Object: + if (arrayElementType == typeof(Vector3)) + { + float[] pos = GetFieldValueArray(fieldIndex, atr.Length * 3); + + Vector3[] vectors = new Vector3[atr.Length]; + for (var i = 0; i < atr.Length; ++i) + vectors[i] = new Vector3(pos[i * 3], pos[(i * 3) + 1], pos[(i * 3) + 2]); + + f.SetValue(obj, vectors); + } break; default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", fieldInfo.FieldType.Name); + throw new Exception("Unhandled array type: " + arrayElementType.Name); + } + } + else + { + if (type.IsEnum) + type = type.GetEnumUnderlyingType(); + + switch (Type.GetTypeCode(type)) + { + case TypeCode.Single: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.Int64: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.UInt64: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.Int32: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.UInt32: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.Int16: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.UInt16: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.Byte: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.SByte: + f.SetValue(obj, GetFieldValue(fieldIndex)); + break; + case TypeCode.String: + if (_stringsTable == null) + { + f.SetValue(obj, _data.ReadCString()); + } + else + { + var pos = _recordsOffset + _data.Offset + (_data.Position >> 3); + int ofs = GetFieldValue(fieldIndex); + f.SetValue(obj, _stringsTable[pos + ofs]); + } + break; + case TypeCode.Object: + if (type == typeof(LocalizedString)) + { + LocalizedString localized = new LocalizedString(); + if (_stringsTable == null) + { + localized[LocaleConstant.enUS] = _data.ReadCString(); + } + else + { + var pos = _recordsOffset + _data.Offset + (_data.Position >> 3); + int ofs = GetFieldValue(fieldIndex); + localized[LocaleConstant.enUS] = _stringsTable[pos + ofs]; + } + + f.SetValue(obj, localized); + } + else if (type == typeof(Vector2)) + { + float[] pos = GetFieldValueArray(fieldIndex, 2); + f.SetValue(obj, new Vector2(pos)); + } + else if (type == typeof(Vector3)) + { + float[] pos = GetFieldValueArray(fieldIndex, 3); + f.SetValue(obj, new Vector3(pos)); + } + else if (type == typeof(FlagArray128)) + { + uint[] flags = GetFieldValueArray(fieldIndex, 4); + f.SetValue(obj, new FlagArray128(flags)); + } break; } - break; - default: - Log.outError(LogFilter.ServerLoading, "Wrong Array Type: {0}", fieldInfo.FieldType.Name); - break; - } - } + } - static string GetString(BinaryReader reader) - { - if (StringTable != null) - return StringTable.LookupByKey(reader.ReadUInt32()); - - return reader.ReadCString(); - } - - static DB6Header Header; - static Dictionary StringTable; - - static FieldMetaData[] FieldStructure; - static List ColumnMeta; - } - - public struct DB6FieldInfo - { - public DB6FieldInfo(FieldInfo fieldInfo) - { - IsArray = false; - FieldType = fieldInfo.FieldType; - - if (fieldInfo.FieldType.IsArray) - { - FieldType = fieldInfo.FieldType.GetElementType(); - IsArray = true; + fieldIndex++; } - Setter = fieldInfo.CompileSetter(); - Getter = fieldInfo.CompileGetter(); + return obj; } - public void SetValue(Array array, object value, int arrayIndex) + public WDC2Row Clone() { - array.SetValue(value, arrayIndex % array.Length); + return (WDC2Row)MemberwiseClone(); } - - public void SetValue(object obj, object value) - { - Setter(obj, value); - } - - public Type FieldType; - public bool IsArray; - Action Setter; - public Func Getter; } - public class DB6Header + public class WDCHeader { public bool HasIndexTable() { @@ -647,6 +593,7 @@ namespace Game.DataStorage public uint SectionsCount; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct FieldMetaData { public short Bits; @@ -679,25 +626,50 @@ namespace Game.DataStorage } } - public class ColumnStructureEntry + [StructLayout(LayoutKind.Explicit)] + public struct ColumnMetaData { - public ushort RecordOffset { get; set; } - public ushort Size { get; set; } - public uint AdditionalDataSize { get; set; } - public DB2ColumnCompression CompressionType { get; set; } - public int BitOffset { get; set; } // used as common data column for Sparse - public int BitWidth { get; set; } - public int Cardinality { get; set; } // flags for Immediate, &1: Signed - - public List PalletValues { get; set; } - public Dictionary SparseValues { get; set; } - public int ArraySize { get; set; } = 1; + [FieldOffset(0)] + public ushort RecordOffset; + [FieldOffset(2)] + public ushort Size; + [FieldOffset(4)] + public uint AdditionalDataSize; + [FieldOffset(8)] + public DB2ColumnCompression CompressionType; + [FieldOffset(12)] + public ColumnCompressionData_Immediate Immediate; + [FieldOffset(12)] + public ColumnCompressionData_Pallet Pallet; + [FieldOffset(12)] + public ColumnCompressionData_Common Common; } + public struct ColumnCompressionData_Immediate + { + public int BitOffset; + public int BitWidth; + public int Flags; // 0x1 signed + } + + public struct ColumnCompressionData_Pallet + { + public int BitOffset; + public int BitWidth; + public int Cardinality; + } + + public struct ColumnCompressionData_Common + { + public Value32 DefaultValue; + public int B; + public int C; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SectionHeader { - public int unk1; - public int unk2; + public long TactKeyLookup; public int FileOffset; public int NumRecords; public int StringTableSize; @@ -707,23 +679,34 @@ namespace Game.DataStorage public int ParentLookupDataSize; // uint NumRecords, uint minId, uint maxId, {uint id, uint index}[NumRecords], questionable usefulness... } - public class RelationShipData + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SparseEntry { - public uint Records; - public uint MinId; - public uint MaxId; - public Dictionary Entries; // index, id + public int Offset; + public ushort Size; } - struct OffsetDuplicate + public struct ReferenceEntry { - public int HiddenIndex { get; } - public int VisibleIndex { get; } + public int Id; + public int Index; + } - public OffsetDuplicate(int hidden, int visible) + public class ReferenceData + { + public int NumRecords { get; set; } + public int MinId { get; set; } + public int MaxId { get; set; } + public Dictionary Entries { get; set; } + } + + public struct Value32 + { + private uint Value; + + public T As() where T : unmanaged { - HiddenIndex = hidden; - VisibleIndex = visible; + return Unsafe.As(ref Value); } } @@ -748,25 +731,4 @@ namespace Game.DataStorage StringArray stringStorage = new StringArray((int)LocaleConstant.Total); } - - public enum DB2ColumnCompression : uint - { - None, - Immediate, - CommonData, - Pallet, - PalletArray, - SignedImmediate - } - - [Flags] - public enum HeaderFlags : short - { - None = 0x0, - OffsetMap = 0x1, - SecondIndex = 0x2, - IndexMap = 0x4, - Unknown = 0x8, - Compressed = 0x10, - } } diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index 6e649bc9f..e18988f4f 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -164,11 +164,11 @@ namespace Game.DataStorage foreach (GameObjectDisplayInfoRecord gameObjectDisplayInfo in CliDB.GameObjectDisplayInfoStorage.Values) { if (gameObjectDisplayInfo.GeoBoxMax.X < gameObjectDisplayInfo.GeoBoxMin.X) - Extensions.Swap(ref gameObjectDisplayInfo.GeoBoxMax.X, ref gameObjectDisplayInfo.GeoBoxMin.X); + Extensions.Swap(ref gameObjectDisplayInfo.GeoBox[3], ref gameObjectDisplayInfo.GeoBox[0]); if (gameObjectDisplayInfo.GeoBoxMax.Y < gameObjectDisplayInfo.GeoBoxMin.Y) - Extensions.Swap(ref gameObjectDisplayInfo.GeoBoxMax.Y, ref gameObjectDisplayInfo.GeoBoxMin.Y); + Extensions.Swap(ref gameObjectDisplayInfo.GeoBox[4], ref gameObjectDisplayInfo.GeoBox[1]); if (gameObjectDisplayInfo.GeoBoxMax.Z < gameObjectDisplayInfo.GeoBoxMin.Z) - Extensions.Swap(ref gameObjectDisplayInfo.GeoBoxMax.Z, ref gameObjectDisplayInfo.GeoBoxMin.Z); + Extensions.Swap(ref gameObjectDisplayInfo.GeoBox[5], ref gameObjectDisplayInfo.GeoBox[2]); } foreach (HeirloomRecord heirloom in CliDB.HeirloomStorage.Values) @@ -1732,7 +1732,7 @@ namespace Game.DataStorage UiMapAssignmentRecord FindNearestMapAssignment(float x, float y, float z, int mapId, int areaId, int wmoDoodadPlacementId, int wmoGroupId, UiMapSystem system) { - UiMapAssignmentStatus nearestMapAssignment = null; + UiMapAssignmentStatus nearestMapAssignment = new UiMapAssignmentStatus(); var iterateUiMapAssignments = new Action, int>((assignments, id) => { foreach (var assignment in assignments.LookupByKey(id)) diff --git a/Source/Game/DataStorage/Structs/A_Records.cs b/Source/Game/DataStorage/Structs/A_Records.cs index 055e1f5ee..b8b89c003 100644 --- a/Source/Game/DataStorage/Structs/A_Records.cs +++ b/Source/Game/DataStorage/Structs/A_Records.cs @@ -173,7 +173,7 @@ namespace Game.DataStorage public ushort AltHandUICameraID; public sbyte ForgeAttachmentOverride; public byte Flags; - public byte ArtifactID; + public uint ArtifactID; } public sealed class ArtifactCategoryRecord @@ -214,7 +214,7 @@ namespace Game.DataStorage public uint SpellID; public ushort ItemBonusListID; public float AuraPointsOverride; - public ushort ArtifactPowerID; + public uint ArtifactPowerID; } public sealed class ArtifactQuestXPRecord @@ -240,7 +240,7 @@ namespace Game.DataStorage public byte PowerRank; public ushort ItemBonusListID; public uint PlayerConditionID; - public byte ArtifactID; + public uint ArtifactID; } public sealed class AuctionHouseRecord diff --git a/Source/Game/DataStorage/Structs/B_Records.cs b/Source/Game/DataStorage/Structs/B_Records.cs index d3dfffe58..eccc6fc8d 100644 --- a/Source/Game/DataStorage/Structs/B_Records.cs +++ b/Source/Game/DataStorage/Structs/B_Records.cs @@ -55,7 +55,7 @@ namespace Game.DataStorage public uint Id; public byte BattlePetStateID; public ushort Value; - public byte BattlePetBreedID; + public uint BattlePetBreedID; } public sealed class BattlePetSpeciesRecord @@ -78,7 +78,7 @@ namespace Game.DataStorage public uint Id; public byte BattlePetStateID; public int Value; - public ushort BattlePetSpeciesID; + public uint BattlePetSpeciesID; } public sealed class BattlemasterListRecord diff --git a/Source/Game/DataStorage/Structs/C_Records.cs b/Source/Game/DataStorage/Structs/C_Records.cs index 10b9273b0..9de486099 100644 --- a/Source/Game/DataStorage/Structs/C_Records.cs +++ b/Source/Game/DataStorage/Structs/C_Records.cs @@ -68,7 +68,7 @@ namespace Game.DataStorage public uint PetDisplayID; // Pet Model ID for starting pet public byte PetFamilyID; // Pet Family Entry for starting pet public int[] ItemID = new int[24]; - public byte RaceID; + public uint RaceID; } public sealed class CharTitlesRecord @@ -117,7 +117,7 @@ namespace Game.DataStorage { public uint Id; public sbyte PowerType; - public byte ClassID; + public uint ClassID; } public sealed class ChrRacesRecord diff --git a/Source/Game/DataStorage/Structs/E_Records.cs b/Source/Game/DataStorage/Structs/E_Records.cs index 6c2e088c8..0744fa300 100644 --- a/Source/Game/DataStorage/Structs/E_Records.cs +++ b/Source/Game/DataStorage/Structs/E_Records.cs @@ -45,7 +45,7 @@ namespace Game.DataStorage public byte ClassId; public byte SexId; public uint SoundId; - public ushort EmotesTextId; + public uint EmotesTextId; } public sealed class ExpectedStatRecord diff --git a/Source/Game/DataStorage/Structs/G_Records.cs b/Source/Game/DataStorage/Structs/G_Records.cs index 9ad3cca9c..f44fcbf1b 100644 --- a/Source/Game/DataStorage/Structs/G_Records.cs +++ b/Source/Game/DataStorage/Structs/G_Records.cs @@ -23,12 +23,22 @@ namespace Game.DataStorage public sealed class GameObjectDisplayInfoRecord { public uint Id; - public Vector3 GeoBoxMin; - public Vector3 GeoBoxMax; + public float[] GeoBox = new float[6]; public int FileDataID; public short ObjectEffectPackageID; public float OverrideLootEffectScale; public float OverrideNameScale; + + public Vector3 GeoBoxMin + { + get { return new Vector3(GeoBox[0], GeoBox[1], GeoBox[2]); } + set { GeoBox[0] = value.X; GeoBox[1] = value.Y; GeoBox[2] = value.Z; } + } + public Vector3 GeoBoxMax + { + get { return new Vector3(GeoBox[3], GeoBox[4], GeoBox[5]); } + set { GeoBox[3] = value.X; GeoBox[4] = value.Y; GeoBox[5] = value.Z; } + } } public sealed class GameObjectsRecord @@ -151,7 +161,7 @@ namespace Game.DataStorage public byte OrderIndex; public byte FactionIndex; public ushort GarrAbilityID; - public ushort GarrFollowerID; + public uint GarrFollowerID; } public sealed class GarrPlotRecord @@ -215,7 +225,7 @@ namespace Game.DataStorage { public uint Id; public int SpellID; - public short GlyphPropertiesID; + public uint GlyphPropertiesID; } public sealed class GlyphPropertiesRecord @@ -231,7 +241,7 @@ namespace Game.DataStorage { public uint Id; public ushort ChrSpecializationID; - public ushort GlyphPropertiesID; + public uint GlyphPropertiesID; } public sealed class GuildColorBackgroundRecord diff --git a/Source/Game/DataStorage/Structs/I_Records.cs b/Source/Game/DataStorage/Structs/I_Records.cs index fdca56d1a..d88cddf44 100644 --- a/Source/Game/DataStorage/Structs/I_Records.cs +++ b/Source/Game/DataStorage/Structs/I_Records.cs @@ -119,7 +119,7 @@ namespace Game.DataStorage public ushort ChildItemBonusTreeID; public ushort ChildItemBonusListID; public ushort ChildItemLevelSelectorID; - public ushort ParentItemBonusTreeID; + public uint ParentItemBonusTreeID; } public sealed class ItemChildEquipmentRecord @@ -169,7 +169,7 @@ namespace Game.DataStorage public ushort MaxLevel; public ushort SkillRequired; public sbyte ExpansionID; - public byte Class; + public uint Class; } public sealed class ItemEffectRecord @@ -183,7 +183,7 @@ namespace Game.DataStorage public ushort SpellCategoryID; public int SpellID; public ushort ChrSpecializationID; - public int ParentItemID; + public uint ParentItemID; } public sealed class ItemExtendedCostRecord @@ -213,7 +213,7 @@ namespace Game.DataStorage public uint Id; public uint QualityItemBonusListID; public sbyte Quality; - public short ParentILSQualitySetID; + public uint ParentILSQualitySetID; } public sealed class ItemLevelSelectorQualitySetRecord @@ -306,7 +306,7 @@ namespace Game.DataStorage public ushort ChrSpecID; public uint SpellID; public byte Threshold; - public ushort ItemSetID; + public uint ItemSetID; } public sealed class ItemSparseRecord diff --git a/Source/Game/DataStorage/Structs/M_Records.cs b/Source/Game/DataStorage/Structs/M_Records.cs index 753a402fd..e2ec36eaa 100644 --- a/Source/Game/DataStorage/Structs/M_Records.cs +++ b/Source/Game/DataStorage/Structs/M_Records.cs @@ -103,7 +103,7 @@ namespace Game.DataStorage public byte MaxPlayers; public byte ItemContext; public byte Flags; - public ushort MapID; + public uint MapID; public uint GetRaidDuration() { diff --git a/Source/Game/DataStorage/Structs/P_Records.cs b/Source/Game/DataStorage/Structs/P_Records.cs index aeab93c4b..d78ee6cd5 100644 --- a/Source/Game/DataStorage/Structs/P_Records.cs +++ b/Source/Game/DataStorage/Structs/P_Records.cs @@ -30,7 +30,7 @@ namespace Game.DataStorage { public uint Id; public ushort PhaseId; - public ushort PhaseGroupID; + public uint PhaseGroupID; } public sealed class PlayerConditionRecord @@ -163,7 +163,7 @@ namespace Game.DataStorage public byte RangeIndex; public byte MinLevel; public byte MaxLevel; - public ushort MapID; + public uint MapID; // helpers public BattlegroundBracketId GetBracketId() diff --git a/Source/Game/DataStorage/Structs/S_Records.cs b/Source/Game/DataStorage/Structs/S_Records.cs index 114ba455e..b58f404fb 100644 --- a/Source/Game/DataStorage/Structs/S_Records.cs +++ b/Source/Game/DataStorage/Structs/S_Records.cs @@ -441,7 +441,7 @@ namespace Game.DataStorage public SpellProcsPerMinuteModType Type; public ushort Param; public float Coeff; - public ushort SpellProcsPerMinuteID; + public uint SpellProcsPerMinuteID; } public sealed class SpellRadiusRecord diff --git a/Source/Game/DataStorage/Structs/U_Records.cs b/Source/Game/DataStorage/Structs/U_Records.cs index f0409f687..b755cfd27 100644 --- a/Source/Game/DataStorage/Structs/U_Records.cs +++ b/Source/Game/DataStorage/Structs/U_Records.cs @@ -65,7 +65,7 @@ namespace Game.DataStorage public uint Id; public int PhaseID; public int UiMapArtID; - public int UiMapID; + public uint UiMapID; } public sealed class UnitPowerBarRecord diff --git a/Source/Game/Entities/Object/Update/UpdateMask.cs b/Source/Game/Entities/Object/Update/UpdateMask.cs index 18d8da9a8..1568a603a 100644 --- a/Source/Game/Entities/Object/Update/UpdateMask.cs +++ b/Source/Game/Entities/Object/Update/UpdateMask.cs @@ -82,13 +82,14 @@ namespace Game.Entities public void EncodeDynamicFieldChangeType(DynamicFieldChangeType changeType, UpdateType updateType) { + _updateType = updateType; DynamicFieldChangeType = (uint)(_blockCount | ((uint)(changeType & Entities.DynamicFieldChangeType.ValueAndSizeChanged) * ((3 - (int)updateType /*this part evaluates to 0 if update type is not VALUES*/) / 3))); } public override void AppendToPacket(ByteBuffer data) { data.WriteUInt16(DynamicFieldChangeType); - if (DynamicFieldChangeType.HasAnyFlag((uint)Entities.DynamicFieldChangeType.ValueAndSizeChanged)) + if (DynamicFieldChangeType.HasAnyFlag((uint)Entities.DynamicFieldChangeType.ValueAndSizeChanged) && _updateType == UpdateType.Values) data.WriteUInt32(_fieldCount); var maskArray = new byte[_blockCount << 2]; @@ -98,6 +99,7 @@ namespace Game.Entities } public uint DynamicFieldChangeType; + public UpdateType _updateType; } public enum DynamicFieldChangeType diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 8e43bd973..6c29e2031 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -155,8 +155,8 @@ namespace Game.Entities { flags.ThisIsYou = true; flags.ActivePlayer = true; - tempObjectType = TypeId.Player; - tempObjectTypeMask |= TypeMask.Player; + tempObjectType = TypeId.ActivePlayer; + tempObjectTypeMask |= TypeMask.ActivePlayer; } switch (GetGUID().GetHigh()) diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index be79160f2..2cb22cf42 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -2424,9 +2424,9 @@ namespace Game.Entities SetMoney(money); Array customDisplay = new Array(PlayerConst.CustomDisplaySize); - customDisplay.Add(result.Read(14)); - customDisplay.Add(result.Read(15)); - customDisplay.Add(result.Read(16)); + customDisplay[0] = result.Read(14); + customDisplay[1] = result.Read(15); + customDisplay[2] = result.Read(16); SetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetSkinId, result.Read(9)); SetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetFaceId, result.Read(10)); diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index ab423896f..ecbe9f775 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -320,7 +320,7 @@ namespace Game.Entities for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i) { Talents[i] = new Dictionary(); - PvpTalents[i] = new Array(PlayerConst.MaxPvpTalentSlots); + PvpTalents[i] = new Array(PlayerConst.MaxPvpTalentSlots, 0); Glyphs[i] = new List(); } } diff --git a/Source/Game/Entities/Taxi/TaxiPathGraph.cs b/Source/Game/Entities/Taxi/TaxiPathGraph.cs index 9bbdda55a..a7223e82b 100644 --- a/Source/Game/Entities/Taxi/TaxiPathGraph.cs +++ b/Source/Game/Entities/Taxi/TaxiPathGraph.cs @@ -35,7 +35,7 @@ namespace Game.Entities public void Initialize() { - if (m_graph.NumberOfVertices > 0) + if (m_graph != null) return; List, uint>> edges = new List, uint>>(); diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 8934bb5ad..65ba4c07e 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -1564,7 +1564,8 @@ namespace Game.Entities MoveTeleport moveTeleport = new MoveTeleport(); moveTeleport.MoverGUID = GetGUID(); moveTeleport.Pos = new Position(x, y, z, o); - moveTeleport.TransportGUID.Set(GetTransGUID()); + if (GetTransGUID() != ObjectGuid.Empty) + moveTeleport.TransportGUID.Set(GetTransGUID()); moveTeleport.Facing = o; moveTeleport.SequenceIndex = m_movementCounter++; playerMover.SendPacket(moveTeleport); diff --git a/Source/Game/Game.csproj b/Source/Game/Game.csproj index 2b50fae79..49d18cbac 100644 --- a/Source/Game/Game.csproj +++ b/Source/Game/Game.csproj @@ -4,8 +4,13 @@ netstandard2.0 x64 true + 7.3 + + + + diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index f4ec47ca7..53e1b9acb 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -3680,8 +3680,8 @@ namespace Game "Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, " + //21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, " + - //37 38 39 40 41 42 44 44 - "Data29, Data30, Data31, Data32 Data33, RequiredLevel, AIName, ScriptName FROM gameobject_template"); + //37 38 39 40 41 42 44 44 + "Data29, Data30, Data31, Data32, Data33, RequiredLevel, AIName, ScriptName FROM gameobject_template"); if (result.IsEmpty()) { diff --git a/Source/Game/Network/Packets/ArtifactPackets.cs b/Source/Game/Network/Packets/ArtifactPackets.cs index 9bc709115..fe640d00f 100644 --- a/Source/Game/Network/Packets/ArtifactPackets.cs +++ b/Source/Game/Network/Packets/ArtifactPackets.cs @@ -36,7 +36,7 @@ namespace Game.Network.Packets ArtifactPowerChoice artifactPowerChoice; artifactPowerChoice.ArtifactPowerID = _worldPacket.ReadUInt32(); artifactPowerChoice.Rank = _worldPacket.ReadUInt8(); - PowerChoices.Add(artifactPowerChoice); + PowerChoices[i] = artifactPowerChoice; } } diff --git a/Source/Game/Network/Packets/AuctionHousePackets.cs b/Source/Game/Network/Packets/AuctionHousePackets.cs index 28632449b..6feb1e0bf 100644 --- a/Source/Game/Network/Packets/AuctionHousePackets.cs +++ b/Source/Game/Network/Packets/AuctionHousePackets.cs @@ -102,7 +102,7 @@ namespace Game.Network.Packets AuctionItemForSale item; item.Guid = _worldPacket.ReadPackedGuid(); item.UseCount = _worldPacket.ReadUInt32(); - Items.Add(item); + Items[i] = item; } } @@ -304,9 +304,9 @@ namespace Game.Network.Packets ClassFilter.SubClassFilter subClassFilter; subClassFilter.ItemSubclass = _worldPacket.ReadInt32(); subClassFilter.InvTypeMask = _worldPacket.ReadUInt32(); - classFilter.SubClassFilters.Add(subClassFilter); + classFilter.SubClassFilters[x] = subClassFilter; } - ClassFilters.Add(classFilter); + ClassFilters[i] = classFilter; } _worldPacket.Skip(4); // DataSize = (SortCount * 2) diff --git a/Source/Game/Network/Packets/AuthenticationPackets.cs b/Source/Game/Network/Packets/AuthenticationPackets.cs index 719497d13..36002e628 100644 --- a/Source/Game/Network/Packets/AuthenticationPackets.cs +++ b/Source/Game/Network/Packets/AuthenticationPackets.cs @@ -83,7 +83,7 @@ namespace Game.Network.Packets RealmID = _worldPacket.ReadUInt32(); for (var i = 0; i < LocalChallenge.GetLimit(); ++i) - LocalChallenge.Add(_worldPacket.ReadUInt8()); + LocalChallenge[i] = _worldPacket.ReadUInt8(); Digest = _worldPacket.ReadBytes(24); diff --git a/Source/Game/Network/Packets/BattlenetPackets.cs b/Source/Game/Network/Packets/BattlenetPackets.cs index 9a4e9ae26..f31e834e1 100644 --- a/Source/Game/Network/Packets/BattlenetPackets.cs +++ b/Source/Game/Network/Packets/BattlenetPackets.cs @@ -106,7 +106,8 @@ namespace Game.Network.Packets public override void Read() { Token = _worldPacket.ReadUInt32(); - Secret.AddRange(_worldPacket.ReadBytes((uint)Secret.Capacity)); + for (var i = 0; i < Secret.GetLimit(); ++i) + Secret[i] = _worldPacket.ReadUInt8(); } public uint Token; diff --git a/Source/Game/Network/Packets/CharacterPackets.cs b/Source/Game/Network/Packets/CharacterPackets.cs index 3efaa805f..866cd26ca 100644 --- a/Source/Game/Network/Packets/CharacterPackets.cs +++ b/Source/Game/Network/Packets/CharacterPackets.cs @@ -182,6 +182,7 @@ namespace Game.Network.Packets public void Write(WorldPacket data) { data.WritePackedGuid(Guid); + data.WriteUInt64(GuildClubMemberID); data.WriteUInt8(ListPosition); data.WriteUInt8(RaceId); data.WriteUInt8(ClassId); @@ -228,6 +229,7 @@ namespace Game.Network.Packets } public ObjectGuid Guid; + public ulong GuildClubMemberID; // same as bgs.protocol.club.v1.MemberId.unique_id, guessed basing on SMSG_QUERY_PLAYER_NAME_RESPONSE (that one is known) public string Name; public byte ListPosition; // Order of the characters in list public byte RaceId; @@ -320,7 +322,7 @@ namespace Game.Network.Packets CreateInfo.OutfitId = _worldPacket.ReadUInt8(); for (var i = 0; i < CreateInfo.CustomDisplay.GetLimit(); ++i) - CreateInfo.CustomDisplay.Add(_worldPacket.ReadUInt8()); + CreateInfo.CustomDisplay[i] = _worldPacket.ReadUInt8(); CreateInfo.Name = _worldPacket.ReadString(nameLength); if (CreateInfo.TemplateSet.HasValue) @@ -423,7 +425,7 @@ namespace Game.Network.Packets CustomizeInfo.FaceID = _worldPacket.ReadUInt8(); for (var i = 0; i < CustomizeInfo.CustomDisplay.GetLimit(); ++i) - CustomizeInfo.CustomDisplay.Add(_worldPacket.ReadUInt8()); + CustomizeInfo.CustomDisplay[i] = _worldPacket.ReadUInt8(); CustomizeInfo.CharName = _worldPacket.ReadString(_worldPacket.ReadBits(6)); } @@ -456,7 +458,7 @@ namespace Game.Network.Packets RaceOrFactionChangeInfo.FaceID = _worldPacket.ReadUInt8(); for (var i = 0; i < RaceOrFactionChangeInfo.CustomDisplay.GetLimit(); ++i) - RaceOrFactionChangeInfo.CustomDisplay.Add(_worldPacket.ReadUInt8()); + RaceOrFactionChangeInfo.CustomDisplay[i] = _worldPacket.ReadUInt8(); RaceOrFactionChangeInfo.Name = _worldPacket.ReadString(nameLength); } @@ -809,7 +811,7 @@ namespace Game.Network.Packets NewFace = _worldPacket.ReadUInt32(); for (var i = 0; i < NewCustomDisplay.GetLimit(); ++i) - NewCustomDisplay.Add(_worldPacket.ReadUInt32()); + NewCustomDisplay[i] = _worldPacket.ReadUInt32(); } public uint NewHairStyle; diff --git a/Source/Game/Network/Packets/EquipmentPackets.cs b/Source/Game/Network/Packets/EquipmentPackets.cs index 2646aa6f0..461b23caa 100644 --- a/Source/Game/Network/Packets/EquipmentPackets.cs +++ b/Source/Game/Network/Packets/EquipmentPackets.cs @@ -93,12 +93,12 @@ namespace Game.Network.Packets for (byte i = 0; i < EquipmentSlot.End; ++i) { - Set.Pieces.Add(_worldPacket.ReadPackedGuid()); - Set.Appearances.Add(_worldPacket.ReadInt32()); + Set.Pieces[i] = _worldPacket.ReadPackedGuid(); + Set.Appearances[i] = _worldPacket.ReadInt32(); } - Set.Enchants.Add(_worldPacket.ReadInt32()); - Set.Enchants.Add(_worldPacket.ReadInt32()); + Set.Enchants[0] = _worldPacket.ReadInt32(); + Set.Enchants[1] = _worldPacket.ReadInt32(); bool hasSpecIndex = _worldPacket.HasBit(); diff --git a/Source/Game/Network/Packets/MovementPackets.cs b/Source/Game/Network/Packets/MovementPackets.cs index 125064b4a..384a6c7fd 100644 --- a/Source/Game/Network/Packets/MovementPackets.cs +++ b/Source/Game/Network/Packets/MovementPackets.cs @@ -204,12 +204,13 @@ namespace Game.Network.Packets data.WriteFloat(1.0f); // DurationModifier data.WriteFloat(1.0f); // NextDurationModifier data.WriteBits((byte)moveSpline.facing.type, 2); // Face - bool HasJumpGravity = data.WriteBit(moveSpline.splineflags.hasFlag(SplineFlag.Parabolic | SplineFlag.Animation)); // HasJumpGravity - bool HasSpecialTime = data.WriteBit(moveSpline.splineflags.hasFlag(SplineFlag.Parabolic) && moveSpline.effect_start_time < moveSpline.Duration()); // HasSpecialTime + bool hasFadeObjectTime = data.WriteBit(moveSpline.splineflags.hasFlag(SplineFlag.FadeObject) && moveSpline.effect_start_time < moveSpline.Duration()); data.WriteBits(moveSpline.getPath().Length, 16); data.WriteBits((byte)moveSpline.spline.m_mode, 2); // Mode data.WriteBit(0); // HasSplineFilter data.WriteBit(moveSpline.spell_effect_extra.HasValue); // HasSpellEffectExtraData + data.WriteBit(moveSpline.splineflags.hasFlag(SplineFlag.Parabolic)); // HasJumpExtraData + data.FlushBits(); //if (HasSplineFilterKey) //{ @@ -237,11 +238,8 @@ namespace Game.Network.Packets break; } - if (HasJumpGravity) - data.WriteFloat(moveSpline.vertical_acceleration); // JumpGravity - - if (HasSpecialTime) - data.WriteUInt32(moveSpline.effect_start_time); // SpecialTime + if (hasFadeObjectTime) + data.WriteUInt32(moveSpline.effect_start_time); // FadeObjectTime foreach (var vec in moveSpline.getPath()) data.WriteVector3(vec); @@ -253,6 +251,13 @@ namespace Game.Network.Packets data.WriteUInt32(moveSpline.spell_effect_extra.Value.ProgressCurveId); data.WriteUInt32(moveSpline.spell_effect_extra.Value.ParabolicCurveId); } + + if (moveSpline.splineflags.hasFlag(SplineFlag.Parabolic)) + { + data.WriteFloat(moveSpline.vertical_acceleration); + data.WriteUInt32(moveSpline.effect_start_time); + data.WriteUInt32(0); // Duration (override) + } } } diff --git a/Source/Game/Network/Packets/QueryPackets.cs b/Source/Game/Network/Packets/QueryPackets.cs index 1afc21e79..ec943c561 100644 --- a/Source/Game/Network/Packets/QueryPackets.cs +++ b/Source/Game/Network/Packets/QueryPackets.cs @@ -111,8 +111,6 @@ namespace Game.Network.Packets for (var i = 0; i < SharedConst.MaxCreatureKillCredit; ++i) _worldPacket.WriteUInt32(Stats.ProxyCreatureID[i]); - _worldPacket.WriteUInt32(Stats.Display.CreatureDisplay.Count); - _worldPacket.WriteFloat(Stats.Display.TotalProbability); _worldPacket.WriteUInt32(Stats.Display.CreatureDisplay.Count); _worldPacket.WriteFloat(Stats.Display.TotalProbability); @@ -760,7 +758,7 @@ namespace Game.Network.Packets public string UnkString; public uint Type; public uint DisplayID; - public int[] Data = new int[33]; + public int[] Data = new int[SharedConst.MaxGOData]; public float Size; public List QuestItems = new List(); public uint RequiredLevel; diff --git a/Source/Game/Network/Packets/ScenarioPackets.cs b/Source/Game/Network/Packets/ScenarioPackets.cs index 25d540b73..48b90ce28 100644 --- a/Source/Game/Network/Packets/ScenarioPackets.cs +++ b/Source/Game/Network/Packets/ScenarioPackets.cs @@ -119,7 +119,7 @@ namespace Game.Network.Packets { var count = _worldPacket.ReadUInt32(); for (var i = 0; i < count; ++i) - MissingScenarioPOIs.Add(_worldPacket.ReadInt32()); + MissingScenarioPOIs[i] = _worldPacket.ReadInt32(); } public Array MissingScenarioPOIs = new Array(35); diff --git a/Source/Game/Network/Packets/SystemPackets.cs b/Source/Game/Network/Packets/SystemPackets.cs index 83e7193fb..134178af2 100644 --- a/Source/Game/Network/Packets/SystemPackets.cs +++ b/Source/Game/Network/Packets/SystemPackets.cs @@ -79,6 +79,7 @@ namespace Game.Network.Packets _worldPacket.WriteBit(ClubsCharacterClubTypeAllowed); _worldPacket.WriteBit(VoiceChatDisabledByParentalControl); _worldPacket.WriteBit(VoiceChatMutedByParentalControl); + _worldPacket.FlushBits(); { _worldPacket.WriteBit(QuickJoinConfig.ToastsDisabled); diff --git a/Source/Game/Network/Packets/TalentPackets.cs b/Source/Game/Network/Packets/TalentPackets.cs index c6bf4930b..a0acbb260 100644 --- a/Source/Game/Network/Packets/TalentPackets.cs +++ b/Source/Game/Network/Packets/TalentPackets.cs @@ -71,9 +71,8 @@ namespace Game.Network.Packets public override void Read() { uint count = _worldPacket.ReadBits(6); - - for (uint i = 0; i < count; ++i) - Talents.Add(_worldPacket.ReadUInt16()); + for (int i = 0; i < count; ++i) + Talents[i] = _worldPacket.ReadUInt16(); } public Array Talents = new Array(PlayerConst.MaxTalentTiers); diff --git a/Source/Game/Network/Packets/TransmogrificationPackets.cs b/Source/Game/Network/Packets/TransmogrificationPackets.cs index d4bc5bdb1..47a45d430 100644 --- a/Source/Game/Network/Packets/TransmogrificationPackets.cs +++ b/Source/Game/Network/Packets/TransmogrificationPackets.cs @@ -34,7 +34,7 @@ namespace Game.Network.Packets { TransmogrifyItem item = new TransmogrifyItem(); item.Read(_worldPacket); - Items.Add(item); + Items[i] = item; } CurrentSpecOnly = _worldPacket.HasBit(); diff --git a/THANKS b/THANKS index de1088df5..65f13fd4d 100644 --- a/THANKS +++ b/THANKS @@ -6,6 +6,7 @@ Special Thanks To: For the base code, and tons of help and ideas. - TrinityCore (http://www.trinitycore.org) -For code and DB. As CypherCore is a full port of them. -We still add commits from them to keep CypherCore updated. -Much of CpherCore is from them, and we give them alots of thanks. \ No newline at end of file +For code and DB and updates. + +- Wow-Tools (https://github.com/WoW-Tools) +For CASC Ideas and ClientDB loading code. \ No newline at end of file diff --git a/sql/updates/world/master/2018_09_02_00_world.sql b/sql/updates/world/master/2018_09_02_00_world.sql index 7962a638d..82a406e83 100644 --- a/sql/updates/world/master/2018_09_02_00_world.sql +++ b/sql/updates/world/master/2018_09_02_00_world.sql @@ -14235,7 +14235,7 @@ UPDATE `creature_model_info` SET `BoundingRadius`=0.2700765 WHERE `DisplayID`=32 UPDATE `creature_model_info` SET `BoundingRadius`=5.458125 WHERE `DisplayID`=36753; UPDATE `creature_model_info` SET `BoundingRadius`=0.3828198 WHERE `DisplayID`=1141; -DELETE FROM `creature_equip_template` WHERE (`CreatureID`=68 AND `ID`=2) OR (`CreatureID`=45798 AND `ID`=3) OR (`CreatureID`=1976 AND `ID`=2) OR (`CreatureID`=1976 AND `ID`=3) OR (`CreatureID`=45798 AND `ID`=2) OR (`CreatureID`=45798 AND `ID`=1) OR (`CreatureID`=50602 AND `ID`=2) OR (`CreatureID`=49361 AND `ID`=1) OR (`CreatureID`=49364 AND `ID`=1) OR (`CreatureID`=48176 AND `ID`=1) OR (`CreatureID`=45334 AND `ID`=2) OR (`CreatureID`=47168 AND `ID`=2) OR (`CreatureID`=47168 AND `ID`=1) OR (`CreatureID`=46922 AND `ID`=1) OR (`CreatureID`=95928 AND `ID`=1) OR (`CreatureID`=46807 AND `ID`=1) OR (`CreatureID`=42775 AND `ID`=3) OR (`CreatureID`=42775 AND `ID`=2) OR (`CreatureID`=42775 AND `ID`=1) OR (`CreatureID`=61841 AND `ID`=1) OR (`CreatureID`=54218 AND `ID`=1) OR (`CreatureID`=54216 AND `ID`=1) OR (`CreatureID`=54217 AND `ID`=1) OR (`CreatureID`=61838 AND `ID`=1) OR (`CreatureID`=61836 AND `ID`=1) OR (`CreatureID`=61834 AND `ID`=1) OR (`CreatureID`=112912 AND `ID`=1) OR (`CreatureID`=68980 AND `ID`=1) OR (`CreatureID`=114246 AND `ID`=1) OR (`CreatureID`=113211 AND `ID`=1) OR (`CreatureID`=29016 AND `ID`=3) OR (`CreatureID`=24927 AND `ID`=1) OR (`CreatureID`=52809 AND `ID`=1) OR (`CreatureID`=51307 AND `ID`=1) OR (`CreatureID`=3296 AND `ID`=3); +DELETE FROM `creature_equip_template` WHERE (`CreatureID`=68 AND `ID`=2) OR (`CreatureID`=45798 AND `ID`=3) OR (`CreatureID`=1976 AND `ID`=2) OR (`CreatureID`=1976 AND `ID`=3) OR (`CreatureID`=45798 AND `ID`=2) OR (`CreatureID`=45798 AND `ID`=1) OR (`CreatureID`=50602 AND `ID`=2) OR (`CreatureID`=49361 AND `ID`=1) OR (`CreatureID`=49364 AND `ID`=1) OR (`CreatureID`=48176 AND `ID`=1) OR (`CreatureID`=45334 AND `ID`=2) OR (`CreatureID`=47168 AND `ID`=2) OR (`CreatureID`=47168 AND `ID`=1) OR (`CreatureID`=46922 AND `ID`=1) OR (`CreatureID`=95928 AND `ID`=1) OR (`CreatureID`=46807 AND `ID`=1) OR (`CreatureID`=42775 AND `ID`=3) OR (`CreatureID`=42775 AND `ID`=2) OR (`CreatureID`=42775 AND `ID`=1) OR (`CreatureID`=61841 AND `ID`=1) OR (`CreatureID`=54218 AND `ID`=1) OR (`CreatureID`=54216 AND `ID`=1) OR (`CreatureID`=54217 AND `ID`=1) OR (`CreatureID`=61838 AND `ID`=1) OR (`CreatureID`=61836 AND `ID`=1) OR (`CreatureID`=61834 AND `ID`=1) OR (`CreatureID`=112912 AND `ID`=1) OR (`CreatureID`=68980 AND `ID`=1) OR (`CreatureID`=114246 AND `ID`=1) OR (`CreatureID`=113211 AND `ID`=1) OR (`CreatureID`=29016 AND `ID`=3) OR (`CreatureID`=24927 AND `ID`=1) OR (`CreatureID`=52809 AND `ID`=1) OR (`CreatureID`=51307 AND `ID`=1) OR (`CreatureID`=3296 AND `ID`=3);; INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`) VALUES (45798, 3, 31604, 0, 0), -- Crushblow Warrior (45798, 2, 31601, 0, 0), -- Crushblow Warrior