diff --git a/ProcessMemoryDataFinder.sln b/ProcessMemoryDataFinder.sln
index ef8ea57..dc5c10e 100644
--- a/ProcessMemoryDataFinder.sln
+++ b/ProcessMemoryDataFinder.sln
@@ -11,6 +11,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OsuMemoryDataProviderTester
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "osu!", "osu!", "{FD3B44E6-66B3-4C58-B590-FB11B9CF6FF7}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{B3F7447F-5C4F-48B5-B711-D5D9CBF59AAF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{ECAB19BA-FB9B-4264-A353-43839E87C5B5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestReader", "TestReader\TestReader.csproj", "{90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -39,6 +45,22 @@ Global
{2450525D-627D-4ABA-ACF0-FA1AA76CE4A0}.Release|x64.ActiveCfg = Release|x86
{2450525D-627D-4ABA-ACF0-FA1AA76CE4A0}.Release|x86.ActiveCfg = Release|x86
{2450525D-627D-4ABA-ACF0-FA1AA76CE4A0}.Release|x86.Build.0 = Release|x86
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Debug|x64.ActiveCfg = Debug|x64
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Debug|x64.Build.0 = Debug|x64
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Debug|x86.ActiveCfg = Debug|x86
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Debug|x86.Build.0 = Debug|x86
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Release|x64.ActiveCfg = Release|x64
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Release|x64.Build.0 = Release|x64
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Release|x86.ActiveCfg = Release|x86
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}.Release|x86.Build.0 = Release|x86
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Debug|x64.ActiveCfg = Debug|x64
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Debug|x64.Build.0 = Debug|x64
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Debug|x86.ActiveCfg = Debug|x86
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Debug|x86.Build.0 = Debug|x86
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Release|x64.ActiveCfg = Release|x64
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Release|x64.Build.0 = Release|x64
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Release|x86.ActiveCfg = Release|x86
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -46,6 +68,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{D117800F-072D-4AE4-9679-3E2A129A1A3C} = {FD3B44E6-66B3-4C58-B590-FB11B9CF6FF7}
{2450525D-627D-4ABA-ACF0-FA1AA76CE4A0} = {FD3B44E6-66B3-4C58-B590-FB11B9CF6FF7}
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5} = {B3F7447F-5C4F-48B5-B711-D5D9CBF59AAF}
+ {90FD5E98-D0E0-4482-AA2A-5B97F694F5EC} = {B3F7447F-5C4F-48B5-B711-D5D9CBF59AAF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2FBAFFCF-2E42-43DD-B5D2-EFB906701CBF}
diff --git a/TestApp/App.config b/TestApp/App.config
new file mode 100644
index 0000000..193aecc
--- /dev/null
+++ b/TestApp/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TestApp/Program.cs b/TestApp/Program.cs
new file mode 100644
index 0000000..a1cfe16
--- /dev/null
+++ b/TestApp/Program.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+
+namespace TestApp
+{
+ internal static class Program
+ {
+ internal static string IntArrToString(IEnumerable arr) =>
+ arr == null ? "NULL" : $"[{string.Join(",", arr)}]";
+
+ internal static void Main(string[] args)
+ {
+ Console.WriteLine("bruh");
+
+ // [[A6ADEB393E0370C0]]-0x20 on 64bit
+ // [[A6ADEB393E0370C0]]-0x04 on 32bit
+ // random attempt at creating a Thing with a predictable signature but also making sure that number doesnt show up somewhere else
+ var thing = new Thing(-4580157255241192026L - 2000);
+
+ // supper shitty commandline app that accepts commands to change values
+ while (true)
+ {
+ Console.WriteLine(
+ $"i: {thing.Int} | s: {thing.String} | a: {IntArrToString(thing.IntArr)} | l: {IntArrToString(thing.IntList)}");
+ var cmd = Console.ReadLine()?.Trim();
+ if (cmd == null || cmd.Equals("exit")) break;
+
+ if (cmd.StartsWith("ia")) // int add
+ {
+ if (int.TryParse(cmd.Substring(2), out var add))
+ {
+ Console.WriteLine($"adding {add} to int");
+ thing.Int += add;
+ }
+ else
+ {
+ Console.WriteLine("not a valid number");
+ }
+ }
+ else if (cmd.StartsWith("is")) // int subtract
+ {
+ if (int.TryParse(cmd.Substring(2), out var add))
+ {
+ Console.WriteLine($"subtracting {add} to int");
+ thing.Int -= add;
+ }
+ else
+ {
+ Console.WriteLine("not a valid number");
+ }
+ }
+ else if (cmd.StartsWith("ss")) // string set
+ {
+ var newString = cmd.Substring(2);
+ Console.WriteLine("updating string");
+ thing.String = newString;
+ }
+ else if (cmd.StartsWith("an")) // array set null
+ {
+ Console.WriteLine("set array to null");
+ thing.IntArr = null;
+ }
+ else if (cmd.StartsWith("ae")) // array set to empty
+ {
+ Console.WriteLine("set array to empty");
+ thing.IntArr = Array.Empty();
+ }
+ else if (cmd.StartsWith("aa")) // array append
+ {
+ if (thing.IntArr == null)
+ {
+ Console.WriteLine("array is null, invalid operation");
+ }
+ else
+ {
+ if (int.TryParse(cmd.Substring(2), out var add))
+ {
+ Console.WriteLine($"appending {add} to array");
+ var newArr = new int[thing.IntArr.Length + 1];
+ Array.Copy(thing.IntArr, newArr, thing.IntArr.Length);
+ newArr[thing.IntArr.Length] = add;
+ thing.IntArr = newArr;
+ }
+ else
+ {
+ Console.WriteLine("not a valid number");
+ }
+ }
+ }
+ else if (cmd.StartsWith("ln")) // list set null
+ {
+ Console.WriteLine("set list to null");
+ thing.IntList = null;
+ }
+ else if (cmd.StartsWith("le")) // list set to empty
+ {
+ Console.WriteLine("set array to empty");
+ thing.IntList = new List();
+ }
+ else if (cmd.StartsWith("la")) // l append
+ {
+ if (thing.IntList == null)
+ {
+ Console.WriteLine("list is null, invalid operation");
+ }
+ else
+ {
+ if (int.TryParse(cmd.Substring(2), out var add))
+ {
+ Console.WriteLine($"appending {add} to list");
+ thing.IntList.Add(add);
+ }
+ else
+ {
+ Console.WriteLine("not a valid number");
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("invalid cmd");
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/TestApp/Properties/AssemblyInfo.cs b/TestApp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c5cf4f1
--- /dev/null
+++ b/TestApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("PlatformSpecific")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PlatformSpecific")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ce033895-9c7f-4105-ad0b-4ae985848dea")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj
new file mode 100644
index 0000000..37af05d
--- /dev/null
+++ b/TestApp/TestApp.csproj
@@ -0,0 +1,98 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {ECAB19BA-FB9B-4264-A353-43839E87C5B5}
+ Exe
+ TestApp
+ TestApp
+ v4.8
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TestApp/Thing.cs b/TestApp/Thing.cs
new file mode 100644
index 0000000..a4e1b11
--- /dev/null
+++ b/TestApp/Thing.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace TestApp
+{
+ public class Thing
+ {
+ public long Pattern { get; set; }
+ public int Int { get; set; }
+ public int[] IntArr { get; set; }
+ public List IntList { get; set; }
+ public string String { get; set; }
+
+ public Thing(long lMin2000)
+ {
+ Pattern = lMin2000 + 2000;
+ Int = 0;
+ IntArr = null;
+ IntList = null;
+ String = "I Am A String";
+ }
+ }
+}
\ No newline at end of file
diff --git a/TestReader/Program.cs b/TestReader/Program.cs
new file mode 100644
index 0000000..f184962
--- /dev/null
+++ b/TestReader/Program.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using ProcessMemoryDataFinder.API;
+
+namespace Test
+{
+ class Program
+ {
+ internal static string IntArrToString(IEnumerable arr) => arr == null ? "NULL" : $"[{string.Join(",", arr)}]";
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World!");
+ var reader = new ThingReader();
+ while (true)
+ {
+ Thread.Sleep(100);
+ var i = reader.GetThingInt();
+ var s = reader.GetThingString();
+ var list = reader.GetThingIntList();
+ var arr = reader.GetThingIntArray();
+ Console.WriteLine($"i: {i} | s: {s} | a: {IntArrToString(arr)} | l: {IntArrToString(list)}");
+ }
+ }
+ }
+
+ public class ThingReader : MemoryReaderEx
+ {
+ private readonly object _lockingObject = new object();
+
+ public ThingReader() : base("TestApp")
+ {
+ CreateSignatures();
+ }
+
+ private void CreateSignatures()
+ {
+ Signatures.Add((int)SignatureNames.ThingBase, new SigEx
+ {
+ Name = "ThingBase",
+ Pattern = UnpackStr("A6ADEB393E0370C0"),
+#if x64
+ Offset = -0x20,
+#else
+ Offset = -0x04,
+#endif
+ UseMask = false
+ });
+ Signatures.Add((int)SignatureNames.ThingInt, new SigEx
+ {
+ Name = "ThingInt",
+ ParentSig = Signatures[(int)SignatureNames.ThingBase],
+#if x64
+ Offset = 0x28,
+#else
+ Offset = 0x18,
+#endif
+ UseMask = false
+ });
+ Signatures.Add((int)SignatureNames.ThingIntList, new SigEx
+ {
+ Name = "ThingIntList",
+ ParentSig = Signatures[(int)SignatureNames.ThingBase],
+#if x64
+ Offset = 0x10,
+#else
+ Offset = 0x10,
+#endif
+ UseMask = false
+ });
+ Signatures.Add((int)SignatureNames.ThingIntArray, new SigEx
+ {
+ Name = "ThingIntArray",
+ ParentSig = Signatures[(int)SignatureNames.ThingBase],
+#if x64
+ Offset = 0x08,
+#else
+ Offset = 0x0C,
+#endif
+ UseMask = false
+ });
+ Signatures.Add((int)SignatureNames.ThingString, new SigEx
+ {
+ Name = "ThingString",
+ ParentSig = Signatures[(int)SignatureNames.ThingBase],
+#if x64
+ Offset = 0x18,
+#else
+ Offset = 0x14,
+#endif
+ UseMask = false
+ });
+ }
+
+
+ public int GetThingInt() => GetInt((int) SignatureNames.ThingInt);
+ public List GetThingIntList() => GetIntList((int)SignatureNames.ThingIntList);
+ public int[] GetThingIntArray() => GetIntArray((int)SignatureNames.ThingIntArray);
+ public string GetThingString() => GetString((int) SignatureNames.ThingString);
+
+ protected override int GetInt(int signatureId)
+ {
+ lock (_lockingObject)
+ {
+ ResetPointer(signatureId);
+ return base.GetInt(signatureId);
+ }
+ }
+ protected override string GetString(int signatureId)
+ {
+ lock (_lockingObject)
+ {
+ ResetPointer(signatureId);
+ return base.GetString(signatureId);
+ }
+ }
+ protected override List GetIntList(int signatureId)
+ {
+ lock (_lockingObject)
+ {
+ ResetPointer(signatureId);
+ return base.GetIntList(signatureId);
+ }
+ }
+ protected override int[] GetIntArray(int signatureId)
+ {
+ lock (_lockingObject)
+ {
+ ResetPointer(signatureId);
+ return base.GetIntArray(signatureId);
+ }
+ }
+ }
+
+ internal enum SignatureNames
+ {
+ ThingBase,
+ ThingInt,
+ ThingIntArray,
+ ThingIntList,
+ ThingString
+ }
+}
diff --git a/TestReader/TestReader.csproj b/TestReader/TestReader.csproj
new file mode 100644
index 0000000..fc36bab
--- /dev/null
+++ b/TestReader/TestReader.csproj
@@ -0,0 +1,43 @@
+
+
+
+ Exe
+ netcoreapp3.1;net472;net471
+ x64;x86
+
+
+
+ bin\x64\Debug\
+ TRACE;DEBUG;x64
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x64\Release\
+ TRACE;x64
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x86\Debug\
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x86\Release\
+ MinimumRecommendedRules.ruleset
+
+
+ DEBUG;TRACE;x64
+
+
+ TRACE;x64
+
+
+ DEBUG;TRACE
+
+
+ TRACE
+
+
+
+
+
+
\ No newline at end of file