diff --git a/README.md b/README.md index 2a3b83d..e3899dc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # RaidExtractor -A tool made to extract information from the windows version of "Raid: Shadow Legends". Currently it supports v0.237 (as seen in Plarium Play launcher) and currently only extracts artifacts and current champions. +A tool made to extract information from the windows version of "Raid: Shadow Legends". Currently it supports v0.239 (as seen in Plarium Play launcher) and currently only extracts artifacts and current champions. This application has 2 Modes: * A Windows GUI application. The functionality is slim, but it works! diff --git a/RaidExtractor.Core/AccountDumpClient.cs b/RaidExtractor.Core/AccountDumpClient.cs index 8f0aa01..348fea9 100644 --- a/RaidExtractor.Core/AccountDumpClient.cs +++ b/RaidExtractor.Core/AccountDumpClient.cs @@ -456,6 +456,22 @@ public partial class Hero [Newtonsoft.Json.JsonProperty("masteries", Required = Newtonsoft.Json.Required.Always)] public List Masteries { get; set; } + + [Newtonsoft.Json.JsonProperty("skills", Required = Newtonsoft.Json.Required.Always)] + public List Skills { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.24.0 (Newtonsoft.Json v11.0.0.0)")] + public partial class Skill + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + public int Id { get; set; } + + [Newtonsoft.Json.JsonProperty("typeId", Required = Newtonsoft.Json.Required.Always)] + public int TypeId { get; set; } + + [Newtonsoft.Json.JsonProperty("level", Required = Newtonsoft.Json.Required.Always)] + public int Level { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.24.0 (Newtonsoft.Json v11.0.0.0)")] diff --git a/RaidExtractor.Core/Extractor.cs b/RaidExtractor.Core/Extractor.cs index f5143a7..c1d24fe 100644 --- a/RaidExtractor.Core/Extractor.cs +++ b/RaidExtractor.Core/Extractor.cs @@ -113,7 +113,7 @@ public AccountDump GetDump() NativeWrapper.ReadProcessMemory(handle, buckets + 0x18, ref bucketCount); var nodes = new IntPtr[bucketCount]; - if (bucketCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, buckets + 0x20, nodes); + if (bucketCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, buckets + RaidStaticInformation.ListElementPointerArray, nodes); for (var i = 0; i < nodes.Length; i++) { @@ -165,13 +165,13 @@ public AccountDump GetDump() var bonusesPointer = artifactStruct.SecondaryBonuses; var bonusCount = 0; - NativeWrapper.ReadProcessMemory(handle, bonusesPointer + 0x18, ref bonusCount); - NativeWrapper.ReadProcessMemory(handle, bonusesPointer + 0x10, ref bonusesPointer); + NativeWrapper.ReadProcessMemory(handle, bonusesPointer + RaidStaticInformation.ListCount, ref bonusCount); + NativeWrapper.ReadProcessMemory(handle, bonusesPointer + RaidStaticInformation.ListIndexArray, ref bonusesPointer); artifact.SecondaryBonuses = new List(); var bonuses = new IntPtr[bonusCount]; - if (bonusCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, bonusesPointer + 0x20, bonuses, 0, bonuses.Length); + if (bonusCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, bonusesPointer + RaidStaticInformation.ListElementPointerArray, bonuses, 0, bonuses.Length); foreach (var bonusPointer in bonuses) { @@ -208,6 +208,7 @@ public AccountDump GetDump() var heroStruct = new HeroStruct(); var heroMasteriesStruct = new HeroMasteryDataStruct(); + var skillStruct = new SkillStruct(); var heroesById = new Dictionary(); var heroes = new List(); for (var i = 0; i < count; i++) @@ -238,14 +239,40 @@ public AccountDump GetDump() var masteryCount = 0; if (heroStruct.MasteryData != IntPtr.Zero && masteriesPtr != IntPtr.Zero) { - NativeWrapper.ReadProcessMemory(handle, masteriesPtr + 0x18, ref masteryCount); - NativeWrapper.ReadProcessMemory(handle, masteriesPtr + 0x10, ref masteriesPtr); + NativeWrapper.ReadProcessMemory(handle, masteriesPtr + RaidStaticInformation.ListCount, ref masteryCount); + NativeWrapper.ReadProcessMemory(handle, masteriesPtr + RaidStaticInformation.ListIndexArray, ref masteriesPtr); } var masteries = new int[masteryCount]; - if (masteryCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, masteriesPtr + 0x20, masteries, 0, masteries.Length); + if (masteryCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, masteriesPtr + RaidStaticInformation.ListElementPointerArray, masteries, 0, masteries.Length); hero.Masteries.AddRange(masteries); + var skillsPtr = heroStruct.Skills; + var skillsCount = 0; + if (skillsPtr != IntPtr.Zero) + { + NativeWrapper.ReadProcessMemory(handle, heroStruct.Skills + RaidStaticInformation.ListCount, ref skillsCount); + NativeWrapper.ReadProcessMemory(handle, heroStruct.Skills + RaidStaticInformation.ListIndexArray, ref skillsPtr); + } + + hero.Skills = new List(); + var skills = new IntPtr[skillsCount]; + if (skillsCount > 0) NativeWrapper.ReadProcessMemoryArray(handle, skillsPtr + RaidStaticInformation.ListElementPointerArray, skills, 0, skills.Length); + + foreach (var skillPointer in skills) + { + NativeWrapper.ReadProcessMemory(handle, skillPointer, ref skillStruct); + + var skill = new Skill + { + Id = skillStruct.Id, + TypeId = skillStruct.TypeId, + Level = skillStruct.Level, + }; + + hero.Skills.Add(skill); + } + if (heroTypeById.TryGetValue(hero.TypeId, out var heroType)) { hero.Name = heroType.Name; diff --git a/RaidExtractor.Core/Native/SkillStruct.cs b/RaidExtractor.Core/Native/SkillStruct.cs new file mode 100644 index 0000000..b95ca9b --- /dev/null +++ b/RaidExtractor.Core/Native/SkillStruct.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.InteropServices; + +namespace RaidExtractor.Core.Native +{ + [StructLayout(LayoutKind.Explicit)] + public struct SkillStruct + { + [FieldOffset(0x18)] + public int Id; + [FieldOffset(0x1C)] + public int TypeId; + [FieldOffset(0x20)] + public int Level; + } +}