/* Read Base Implementation */ /// <summary> /// Reads a generic type array from a specified memory address. /// </summary> /// <typeparam name="T">An individual struct type of a class with an explicit StructLayout.LayoutKind attribute.</typeparam> /// <param name="value">Local variable to receive the read in struct array.</param> /// <param name="memory"></param> /// <param name="memoryAddress">The memory address to read from.</param> /// <param name="arrayLength">The amount of array items to read.</param> /// <param name="marshal">Set this to true to enable struct marshalling.</param> public static void Read <T>(this IMemory memory, IntPtr memoryAddress, out T[] value, int arrayLength, bool marshal = false) { IMemory oldSource = Struct.Source; Struct.Source = memory; value = new T[arrayLength]; StructArray.FromPtr(memoryAddress, out value, arrayLength, marshal); Struct.Source = oldSource; }
/* Read Base Implementation */ /// <summary> /// Reads a generic type array from a specified memory address. /// </summary> /// <typeparam name="T">An individual struct type of a class with an explicit StructLayout.LayoutKind attribute.</typeparam> /// <param name="value">Local variable to receive the read in struct array.</param> /// <param name="memory"></param> /// <param name="memoryAddress">The memory address to read from.</param> /// <param name="arrayLength">The amount of array items to read.</param> /// <param name="marshal">Set this to true to enable struct marshalling.</param> public static void Read <T>(this IMemory memory, IntPtr memoryAddress, out T[] value, int arrayLength, bool marshal = false) { IMemory oldSource = Struct.Source; Struct.Source = memory; #if NET5_0_OR_GREATER value = GC.AllocateUninitializedArray <T>(arrayLength, false); #else value = new T[arrayLength]; #endif StructArray.FromPtr(memoryAddress, out value, arrayLength, marshal); Struct.Source = oldSource; }
/// <summary> /// Shows some functionality of the <see cref="Struct"/> and <see cref="StructArray"/> utility classes. /// </summary> /// <param name="memory">This object is used to perform memory read/write/free/allocate operations.</param> /// <param name="memoryLocation">Arbitrary location in memory where this tutorial will be held.</param> private static void StructUtilityExample(IMemory memory, IntPtr memoryLocation) { // Under the hood; the IMemory implementations may use a certain struct utility classes known as Struct // and StructArray which provide various methods for struct conversions and general work with structs. // Like earlier; let's load the adventure binary file. byte[] physicsData = File.ReadAllBytes($"phys.bin"); // But this time; do a direct conversion rather than reading from memory. // Note that you don't even need to specify item count this time arounnd. // This is auto-decided from array size, but can be manually overwritten. StructArray.FromArray(physicsData, out AdventurePhysics[] adventurePhysics); // Calculate total array size (in bytes). int arraySize = StructArray.GetSize <AdventurePhysics>(adventurePhysics.Length); // Get raw bytes for the struct. byte[] physicsDataBack = StructArray.GetBytes(adventurePhysics); // You can also read/write structures; as a shorthand to Memory class. StructArray.ToPtr(memoryLocation, adventurePhysics); StructArray.FromPtr(memoryLocation, out AdventurePhysics[] adventurePhysicsCopy, adventurePhysics.Length); // Beware of the double sided blade however. // A. Struct class allows you to change the source read/write source for FromPtr and ToPtr. // B. It affects both Struct and StructArray. // Note: There are also explicit overloads for FromPtr and ToPtr that let you use a source without modifying current source. Struct.Source = memory; // And of course the source is an implementation of IMemory. // Print details. if (physicsDataBack.SequenceEqual(physicsDataBack)) { Console.WriteLine($"Success: Original Physics Data and StructArray.GetBytes() are Equal"); } Console.WriteLine($"Struct Array Size: {arraySize}"); }
private void XpAdded(int esi) { // Get the xp address (has to be done after the game has initialised) if (_xpAddress == IntPtr.Zero) { _memory.SafeRead(_statsPtr, out _xpAddress); _xpAddress += 0xE0; _utils.LogDebug($"The xp info starts at 0x{_xpAddress:X}"); } // Get the in party address (has to be done after the game has initialised) if (_partyAddress == IntPtr.Zero) { _memory.SafeRead(_partyPtr, out _partyAddress); _partyAddress += 4; _utils.LogDebug($"The in party info starts at 0x{_partyAddress:X}"); } // Get the day address (has to be done after the game has initialised) if (_dayAddress == IntPtr.Zero) { _memory.SafeRead(_dayPtr, out _dayAddress); _utils.LogDebug($"The day is at 0x{_dayAddress:X}"); } try { _utils.LogDebug("Xp added starting"); // Get how much xp was added _memory.SafeRead((IntPtr)(esi + 120), out int amountAdded); _utils.LogDebug("The protagonist gained " + amountAdded + " xp"); int amountToAdd = (int)Math.Round(amountAdded * Math.Abs(Configuration.xpScale)); if (amountToAdd == 0) { return; } // Get who is in the party StructArray.FromPtr(_partyAddress, out short[] inParty, 3); _utils.LogDebug("These are in the party: " + MemberNames[inParty[0]] + ", " + MemberNames[inParty[1]] + ", " + MemberNames[inParty[2]]); // Get the current day and use that to determine who is unlocked _memory.SafeRead((IntPtr)_dayAddress, out short day); var unlockedParty = new List <short>(); // Yosuke if (day >= 17) { unlockedParty.Add(2); } // Chie if (day >= 18) { unlockedParty.Add(3); } // Yukiko if (day >= 30) { unlockedParty.Add(4); } // Kanji if (day >= 66) { unlockedParty.Add(6); } // Teddie if (day >= 101) { unlockedParty.Add(8); } // Naoto if (day >= 189) { unlockedParty.Add(7); } // Work out which members are therefore eligible to get xp short[] inactiveParty = unlockedParty.Except(inParty).ToArray(); // Add xp to them foreach (short member in inactiveParty) { // If there isn't a full party there will be zeroes instead of member ids so ignore them if (member <= 0) { continue; } // Get their current xp _memory.SafeRead(_xpAddress + (member - 2) * 132, out int currentXp); // Add the xp // Xp location is the location of Yosuke's so remove 2 (Yosuke's id) from id _memory.SafeWrite(_xpAddress + (member - 2) * 132, currentXp + amountToAdd); _utils.LogDebug("Added " + amountToAdd + " xp to " + MemberNames[member]); } } catch (Exception exception) { _utils.LogError("There was an error whilst trying to add xp", exception); } }
private void DumpPhysics <TGame>(out AdventurePhysics[] physics) where TGame : Enum { StructArray.FromPtr(PhysicsBaseAddress, out physics, Enum.GetValues(typeof(TGame)).Length, true); }