diff --git a/Server/Services/ItemObjectPoolService.cs b/Server/Services/ItemObjectPoolService.cs index 2bce29b..771ad27 100644 --- a/Server/Services/ItemObjectPoolService.cs +++ b/Server/Services/ItemObjectPoolService.cs @@ -37,11 +37,13 @@ public class ItemObjectPoolService : IHostedService }); _logger.LogInformation("A total of {AmountOfEntries} items have been added to the item object pool", _itemObjectPool.Count); + return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { + return Task.CompletedTask; } diff --git a/Wonderking/Game/Data/Item/ItemOptions.cs b/Wonderking/Game/Data/Item/ItemOptions.cs index 3b52fb1..9274e4f 100644 --- a/Wonderking/Game/Data/Item/ItemOptions.cs +++ b/Wonderking/Game/Data/Item/ItemOptions.cs @@ -2,6 +2,6 @@ namespace Wonderking.Game.Data.Item; public struct ItemOptions { - public ICollection OptionIDs { get; internal set; } + public uint[] OptionIDs { get; internal set; } public bool OptionAvailable { get; internal set; } } diff --git a/Wonderking/Game/DataReader.cs b/Wonderking/Game/DataReader.cs index 6563c85..b43c2b9 100644 --- a/Wonderking/Game/DataReader.cs +++ b/Wonderking/Game/DataReader.cs @@ -7,6 +7,9 @@ public abstract class DataReader protected DataReader(string path) { Path = path; + _xorKey = GetXorKey(); + SizeOfEntry = GetSizeOfEntry(); + _datFileName = GetDatFileName(); DatFileContent = GetDatFileContent(path).ToArray(); } @@ -15,7 +18,7 @@ public abstract class DataReader public abstract uint GetAmountOfEntries(); public abstract T GetEntry(uint entryId); - protected ushort GetSizeOfEntry() + private static ushort GetSizeOfEntry() { return typeof(T).GetCustomAttribute()?.DataEntrySize ?? throw new NotSupportedException("DataEntrySize is null"); @@ -33,16 +36,20 @@ public abstract class DataReader throw new NotSupportedException("XorKey is null"); } + private readonly byte _xorKey; + protected readonly ushort SizeOfEntry; + private readonly string _datFileName; + protected byte[] DatFileContent { get; } - private static Span GetDatFileContent(string path) + private Span GetDatFileContent(string path) { - var fileData = File.ReadAllBytes(path + GetDatFileName()); + var fileData = File.ReadAllBytes(path + this._datFileName); var data = new byte[fileData.Length]; for (var i = 0; i < fileData.Length; i++) { - data[i] = (byte)(fileData[i] ^ GetXorKey()); + data[i] = (byte)(fileData[i] ^ this._xorKey); } return data; diff --git a/Wonderking/Game/Reader/ItemReader.cs b/Wonderking/Game/Reader/ItemReader.cs index 8b00ff0..4bc4eef 100644 --- a/Wonderking/Game/Reader/ItemReader.cs +++ b/Wonderking/Game/Reader/ItemReader.cs @@ -1,4 +1,7 @@ +using System.Buffers.Binary; +using System.Text; using Wonderking.Game.Data; +using Wonderking.Game.Data.Item; namespace Wonderking.Game.Reader; @@ -6,98 +9,187 @@ public class ItemReader(string path) : DataReader(path) { public override uint GetAmountOfEntries() { - return (uint)((this.DatFileContent.Length - 9) / this.GetSizeOfEntry()); + return (uint)((this.DatFileContent.Length - 9) / this.SizeOfEntry); } public override ItemObject GetEntry(uint entryId) { var item = new ItemObject(); var arraySegment = new ArraySegment(DatFileContent, - 9 + (int)entryId * this.GetSizeOfEntry(), this.GetSizeOfEntry()); - var reader = new BinaryReader(new MemoryStream(arraySegment.ToArray())); - item.ItemID = reader.ReadUInt32(); //9 - item.Disabled = reader.ReadUInt32() == 1; //13 - item.ItemType = reader.ReadUInt32(); //17 - item.Unknown2 = reader.ReadBytes(4); //21 - item.Unknown3 = reader.ReadBytes(4); //25 - item.ClassNo1 = reader.ReadUInt32(); //29 - item.ClassNo2 = reader.ReadUInt32(); //33 - item.ClassNo3 = reader.ReadUInt32(); //37 - item.ClassNo4 = reader.ReadUInt32(); //41 - item.SlotNo1 = reader.ReadUInt32(); //45 - item.SlotNo2 = reader.ReadUInt32(); //49 - item.Unknown4 = reader.ReadBytes(4); //53 - item.IsCash = reader.ReadUInt32(); //57 - item.Unknown5 = reader.ReadBytes(4); //61 - item.Price = reader.ReadUInt32(); //65 - item.Unknown7 = reader.ReadBytes(4); //69 - item.MaxNumber = reader.ReadUInt32(); //73 - item.Unknown17 = reader.ReadBytes(12); //77 - item.MaximumLevelRequirement = reader.ReadUInt32(); //89 - item.SexNo = reader.ReadUInt32(); //93 - item.WeaponSomething = reader.ReadUInt32(); //97 - item.Unknown8 = reader.ReadBytes(4); //101 - item.R2C = reader.ReadBytes(16); //105 - item.Unknown9 = reader.ReadBytes(4); //121 - item.Stats = reader.ReadStats(); //125 - item.ElementalStats = reader.ReadElementalStats(); //149 - item.R7C = reader.ReadBytes(4); //213 - item.R8C = reader.ReadBytes(8); //217 - item.Speed = reader.ReadSingle(); //225 - item.Jump = reader.ReadSingle(); //229 - item.StatDefense = reader.ReadInt32(); //233 - item.MagicID = reader.ReadUInt32(); //237 - item.Unknown13 = reader.ReadBytes(4); //241 - item.Unknown14 = reader.ReadBytes(4); //245 - item.AdditionalHealthRecoveryVolume = reader.ReadInt32(); //249 - item.R9C_1 = reader.ReadBytes(4); //253 - item.AdditionalManaRecoveryVolume = reader.ReadInt32(); //257 - item.R9C_2 = reader.ReadBytes(4); //261 - item.R10C = reader.ReadBytes(8); //265 - item.AdditionalHealthPoints = reader.ReadInt32(); //273 - item.AdditionalManaPoints = reader.ReadInt32(); //277 - item.IsArrow = reader.ReadBoolean(); //281 - item.Unknown18 = reader.ReadBytes(7); //282 - item.AdditionalEvasionRate = reader.ReadInt32(); //289 - item.HitRate = reader.ReadInt32(); //293 - item.ChanceToHit = reader.ReadInt32(); //297 - item.MagicalDamage = reader.ReadInt32(); //301 - item.CriticalHitChance = reader.ReadInt32(); //305 - item.R12C = reader.ReadBytes(4); //309 - item.Unknown16 = reader.ReadBytes(4); //313 - item.MinimalAttackDamage = reader.ReadInt32(); //317 - item.MaximalAttackDamage = reader.ReadInt32(); //321 - item.PhysicalDamage = reader.ReadInt32(); //325 - item.CraftMaterial = reader.ReadCraftMaterial(); //329 - item.CraftResultAmount = reader.ReadUInt32(); //361 - item.R14C = reader.ReadBytes(4); //365 - item.CraftResultItem = reader.ReadUInt32(); //369 - item.R15C = reader.ReadBytes(4); //373 - item.R16C = reader.ReadBytes(20); //377 - item.InventoryX = reader.ReadInt32(); //397 - item.InventoryY = reader.ReadInt32(); //401 - item.InventoryWidth = reader.ReadInt32(); //405 - item.InventoryHeight = reader.ReadInt32(); //409 - item.SheetID = reader.ReadInt32(); //413 - item.Name = reader.ReadString(20); //417 - item.Description = reader.ReadString(85); //427 - item.Unknown1 = reader.ReadBytes(175); //493 - item.IsEnchantable = reader.ReadUInt32() == 1; //687 - item.Unknown1_2 = reader.ReadBytes(104); //687 - item.SetItems = reader.ReadArray(5); - item.SetID = reader.ReadUInt32(); //691 - item.Options = reader.ReadItemOptions(); //819 - item.Unknown19 = reader.ReadBytes(23); //835 - item.PetID = reader.ReadByte(); //858 - item.Unknown20 = reader.ReadBytes(20); //859 - item.HitBoxScaling = reader.ReadByte(); //879 - item.Unknown20_2 = reader.ReadBytes(13); //880 - item.ContainedItems = reader.ReadContainedItems(); //893 - item.IsQuestItem = reader.ReadBoolean(); //923 - item.MinimumLevelRequirement = reader.ReadByte(); //924 - item.Unknown21_2 = reader.ReadBytes(6); //925 - reader.Dispose(); //931 + 9 + (int)entryId * this.SizeOfEntry, this.SizeOfEntry); + var data = new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); + item.ItemID = BitConverter.ToUInt32(data.Slice(0, 4)); // 0 -> 4 + item.Disabled = BitConverter.ToBoolean(data.Slice(4, 4)); // 4 -> 8 + item.ItemType = BitConverter.ToUInt32(data.Slice(8, 4)); // 8 -> 12 + item.Unknown2 = data.Slice(12, 4).ToArray(); // 12 -> 16 + item.Unknown3 = data.Slice(16, 4).ToArray(); // 16 -> 20 + item.ClassNo1 = BitConverter.ToUInt32(data.Slice(20, 4)); // 20 -> 24 + item.ClassNo2 = BitConverter.ToUInt32(data.Slice(24, 4)); // 24 -> 28 + item.ClassNo3 = BitConverter.ToUInt32(data.Slice(28, 4)); // 28 -> 32 + item.ClassNo4 = BitConverter.ToUInt32(data.Slice(32, 4)); // 32 -> 36 + item.SlotNo1 = BitConverter.ToUInt32(data.Slice(36, 4)); // 36 -> 40 + item.SlotNo2 = BitConverter.ToUInt32(data.Slice(40, 4)); // 40 -> 44 + item.Unknown4 = data.Slice(44, 4).ToArray(); // 44 -> 48 + item.IsCash = BitConverter.ToUInt32(data.Slice(48, 4)); // 48 -> 52 + item.Unknown5 = data.Slice(52, 4).ToArray(); // 52 -> 56 + item.Price = BitConverter.ToUInt32(data.Slice(56, 4)); // 56 -> 60 + item.Unknown7 = data.Slice(60, 4).ToArray(); // 60 -> 64 + item.MaxNumber = BitConverter.ToUInt32(data.Slice(64, 4)); // 64 -> 68 + item.Unknown17 = data.Slice(68, 12).ToArray(); // 68 -> 80 + item.MaximumLevelRequirement = BitConverter.ToUInt32(data.Slice(80, 4)); // 80 -> 84 + item.SexNo = BitConverter.ToUInt32(data.Slice(84, 4)); // 84 -> 88 + item.WeaponSomething = BitConverter.ToUInt32(data.Slice(88, 4)); // 88 -> 92 + item.Unknown8 = data.Slice(92, 4).ToArray(); // 92 -> 96 + item.R2C = data.Slice(96, 16).ToArray(); // 96 -> 112 + item.Unknown9 = data.Slice(112, 4).ToArray(); // 112 -> 116 + item.Stats = new Stats + { + Strength = BitConverter.ToInt32(data.Slice(116, 4)), // 116 -> 120 + Dexterity = BitConverter.ToInt32(data.Slice(120, 4)), // 120 -> 124 + Intelligence = BitConverter.ToInt32(data.Slice(124, 4)), // 124 -> 128 + Vitality = BitConverter.ToInt32(data.Slice(128, 4)), // 128 -> 132 + Luck = BitConverter.ToInt32(data.Slice(132, 4)), // 132 -> 136 + Wisdom = BitConverter.ToInt32(data.Slice(136, 4)), // 136 -> 140 + }; // 116 -> 140 + item.ElementalStats = new ElementalStats + { + MinimumFireDamage = BitConverter.ToInt32(data.Slice(140, 4)), // 140 -> 144 + MinimumWaterDamage = BitConverter.ToInt32(data.Slice(144, 4)), // 144 -> 148 + MinimumDarkDamage = BitConverter.ToInt32(data.Slice(148, 4)), // 148 -> 152 + MinimumHolyDamage = BitConverter.ToInt32(data.Slice(152, 4)), // 152 -> 156 + MaximumFireDamage = BitConverter.ToInt32(data.Slice(156, 4)), // 156 -> 160 + MaximumWaterDamage = BitConverter.ToInt32(data.Slice(160, 4)), // 160 -> 164 + MaximumDarkDamage = BitConverter.ToInt32(data.Slice(164, 4)), // 164 -> 168 + MaximumHolyDamage = BitConverter.ToInt32(data.Slice(168, 4)), // 168 -> 172 + ElementFire = BitConverter.ToUInt32(data.Slice(172, 4)), // 172 -> 176 + ElementWater = BitConverter.ToUInt32(data.Slice(176, 4)), // 176 -> 180 + ElementDark = BitConverter.ToUInt32(data.Slice(180, 4)), // 180 -> 184 + ElementHoly = BitConverter.ToUInt32(data.Slice(184, 4)), // 184 -> 188 + FireResistance = BitConverter.ToInt32(data.Slice(188, 4)), // 188 -> 192 + WaterResistance = BitConverter.ToInt32(data.Slice(192, 4)), // 192 -> 196 + DarkResistance = BitConverter.ToInt32(data.Slice(196, 4)), // 196 -> 200 + HolyResistance = BitConverter.ToInt32(data.Slice(200, 4)), // 200 -> 204 + }; // 140 -> 204 + item.R7C = data.Slice(204, 4).ToArray(); // 204 -> 208 + item.R8C = data.Slice(208, 8).ToArray(); // 208 -> 216 + item.Speed = BinaryPrimitives.ReadSingleLittleEndian(data.Slice(216, 4)); // 216 -> 220 + item.Jump = BinaryPrimitives.ReadSingleLittleEndian(data.Slice(220, 4)); // 220 -> 224 + item.StatDefense = BitConverter.ToInt32(data.Slice(224, 4)); // 224 -> 228 + item.MagicID = BitConverter.ToUInt32(data.Slice(228, 4)); // 228 -> 232 + item.Unknown13 = data.Slice(232, 4).ToArray(); // 232 -> 236 + item.Unknown14 = data.Slice(236, 4).ToArray(); // 236 -> 240 + item.AdditionalHealthRecoveryVolume = BitConverter.ToInt32(data.Slice(240, 4)); // 240 -> 244 + item.R9C_1 = data.Slice(244, 4).ToArray(); // 244 -> 248 + item.AdditionalManaRecoveryVolume = BitConverter.ToInt32(data.Slice(248, 4)); // 248 -> 252 + item.R9C_2 = data.Slice(252, 4).ToArray(); // 252 -> 256 + item.R10C = data.Slice(256, 8).ToArray(); // 256 -> 264 + item.AdditionalHealthPoints = BitConverter.ToInt32(data.Slice(264, 4)); // 264 -> 268 + item.AdditionalManaPoints = BitConverter.ToInt32(data.Slice(268, 4)); // 268 -> 272 + item.IsArrow = BitConverter.ToBoolean(data.Slice(272, 1)); // 272 -> 273 + item.Unknown18 = data.Slice(273, 7).ToArray(); // 273 -> 280 + item.AdditionalEvasionRate = BitConverter.ToInt32(data.Slice(280, 4)); // 280 -> 284 + item.HitRate = BitConverter.ToInt32(data.Slice(284, 4)); // 284 -> 288 + item.ChanceToHit = BitConverter.ToInt32(data.Slice(288, 4)); // 288 -> 292 + item.MagicalDamage = BitConverter.ToInt32(data.Slice(292, 4)); // 292 -> 296 + item.CriticalHitChance = BitConverter.ToInt32(data.Slice(296, 4)); // 296 -> 300 + item.R12C = data.Slice(300, 4).ToArray(); // 300 -> 304 + item.Unknown16 = data.Slice(304, 4).ToArray(); // 304 -> 308 + item.MinimalAttackDamage = BitConverter.ToInt32(data.Slice(308, 4)); // 308 -> 312 + item.MaximalAttackDamage = BitConverter.ToInt32(data.Slice(312, 4)); // 312 -> 316 + item.PhysicalDamage = BitConverter.ToInt32(data.Slice(316, 4)); // 316 -> 320 + item.CraftMaterial = new CraftMaterial[] + { + new() + { + ID = BitConverter.ToUInt32(data.Slice(320, 4)), // 320 -> 324 + Amount = BitConverter.ToUInt32(data.Slice(336, 4)) // 336 -> 340 + }, + new() + { + ID = BitConverter.ToUInt32(data.Slice(324, 4)), // 324 -> 328 + Amount = BitConverter.ToUInt32(data.Slice(340, 4)) // 340 -> 344 + }, + new() + { + ID = BitConverter.ToUInt32(data.Slice(328, 4)), // 328 -> 332 + Amount = BitConverter.ToUInt32(data.Slice(344, 4)) // 344 -> 348 + }, + new() + { + ID = BitConverter.ToUInt32(data.Slice(332, 4)), // 332 -> 336 + Amount = BitConverter.ToUInt32(data.Slice(348, 4)) // 348 -> 352 + }, + }; // 320 -> 352 + item.CraftResultAmount = BitConverter.ToUInt32(data.Slice(352, 4)); // 352 -> 356 + item.R14C = data.Slice(356, 4).ToArray(); // 356 -> 360 + item.CraftResultItem = BitConverter.ToUInt32(data.Slice(360, 4)); // 360 -> 364 + item.R15C = data.Slice(364, 4).ToArray(); // 364 -> 368 + item.R16C = data.Slice(368, 20).ToArray(); // 368 -> 388 + item.InventoryX = BitConverter.ToInt32(data.Slice(388, 4)); // 388 -> 392 + item.InventoryY = BitConverter.ToInt32(data.Slice(392, 4)); // 392 -> 396 + item.InventoryWidth = BitConverter.ToInt32(data.Slice(396, 4)); // 396 -> 400 + item.InventoryHeight = BitConverter.ToInt32(data.Slice(400, 4)); // 400 -> 404 + item.SheetID = BitConverter.ToInt32(data.Slice(404, 4)); // 404 -> 408 + item.Name = Encoding.ASCII.GetString(data.Slice(408, 20)); // 408 -> 428 + item.Description = Encoding.ASCII.GetString(data.Slice(428, 85)); // 428 -> 513 + item.Unknown1 = data.Slice(513, 175).ToArray(); // 513 -> 688 + item.IsEnchantable = BitConverter.ToBoolean(data.Slice(688, 4)); // 688 -> 672 + item.Unknown1_2 = data.Slice(692, 104).ToArray(); // 692 -> 796 + item.SetItems = new[] + { + BitConverter.ToUInt32(data.Slice(796, 4)), // 796 -> 800 + BitConverter.ToUInt32(data.Slice(800, 4)), // 800 -> 804 + BitConverter.ToUInt32(data.Slice(804, 4)), // 804 -> 808 + BitConverter.ToUInt32(data.Slice(808, 4)), // 808 -> 812 + BitConverter.ToUInt32(data.Slice(812, 4)), // 812 -> 816 + }; // 796 -> 816 + item.SetID = BitConverter.ToUInt32(data.Slice(816, 4)); // 816 -> 820 + item.Options = new ItemOptions + { + OptionIDs = new[] + { + BitConverter.ToUInt32(data.Slice(824, 4)), // 824 -> 828 + BitConverter.ToUInt32(data.Slice(828, 4)), // 828 -> 832 + BitConverter.ToUInt32(data.Slice(832, 4)), // 832 -> 836 + BitConverter.ToUInt32(data.Slice(836, 4)), // 836 -> 840 + }, + OptionAvailable = BitConverter.ToBoolean(data.Slice(820, 4)), // 820 -> 824 + }; // 820 -> 840 + item.Unknown19 = data.Slice(840, 23).ToArray(); // 840 -> 863 + item.PetID = data[863]; // 863 -> 864 + item.Unknown20 = data.Slice(864, 20).ToArray(); // 864 -> 884 + item.HitBoxScaling = data[884]; // 884 -> 885 + item.Unknown20_2 = data.Slice(885, 13).ToArray(); // 885 -> 898 + item.ContainedItems = new[] + { + new ContainedItem + { + ID = BitConverter.ToInt16(data.Slice(898, 2)), // 898 -> 900 + ObtainChance = BitConverter.ToSingle(data.Slice(908, 4)) // 908 -> 912 + }, + new ContainedItem + { + ID = BitConverter.ToInt16(data.Slice(900, 2)), // 900 -> 902 + ObtainChance = BitConverter.ToSingle(data.Slice(912, 4)) // 912 -> 916 + }, + new ContainedItem + { + ID = BitConverter.ToInt16(data.Slice(902, 2)), // 902 -> 904 + ObtainChance = BitConverter.ToSingle(data.Slice(916, 4)) // 916 -> 920 + }, + new ContainedItem + { + ID = BitConverter.ToInt16(data.Slice(904, 2)), // 904 -> 906 + ObtainChance = BitConverter.ToSingle(data.Slice(920, 4)) // 920 -> 924 + }, + new ContainedItem + { + ID = BitConverter.ToInt16(data.Slice(906, 2)), // 906 -> 908 + ObtainChance = BitConverter.ToSingle(data.Slice(924, 4)) // 924 -> 928 + }, + }; + item.MinimumLevelRequirement = data[928]; // 928 -> 929 + item.Unknown21_2 = data.Slice(929, 3).ToArray(); // 929 -> 932 return item; } - } diff --git a/Wonderking/Game/Reader/ItemReaderExtensions.cs b/Wonderking/Game/Reader/ItemReaderExtensions.cs index 97a8b72..6fe699c 100644 --- a/Wonderking/Game/Reader/ItemReaderExtensions.cs +++ b/Wonderking/Game/Reader/ItemReaderExtensions.cs @@ -82,14 +82,14 @@ public static class ItemReaderExtensions options.OptionAvailable = reader.ReadInt32() == 1; //819 - var optionIDs = new List(4); + var optionIDs = new List(4); //823 for (var i = 0; i < 3; i++) { - optionIDs.Add((byte)reader.ReadUInt32()); + optionIDs.Add(reader.ReadUInt32()); } - options.OptionIDs = optionIDs; + options.OptionIDs = optionIDs.ToArray(); return options; }