From 939e96ab6c5052f23f7d4035cdfa3d78efe4d8f3 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Sat, 2 Jun 2018 14:23:49 -0500 Subject: [PATCH] Memory Values can now be obtained from Rabi-Ribi. --- RabiTracker/RabiTracker.jar | Bin 11826 -> 26051 bytes RabiTracker/memoryData | 111 ++++++++++ RabiTracker/src/RabiTracker/MemoryData.java | 79 +++++++- .../src/RabiTracker/MemoryManager.java | 88 ++++++++ RabiTracker/src/RabiTracker/MemoryType.java | 17 ++ RabiTracker/src/RabiTracker/Window.java | 6 + RabiTracker/src/sig/utils/DebugUtils.java | 55 +++++ RabiTracker/src/sig/utils/FileUtils.java | 189 ++++++++++++++++++ 8 files changed, 542 insertions(+), 3 deletions(-) create mode 100644 RabiTracker/memoryData create mode 100644 RabiTracker/src/RabiTracker/MemoryType.java create mode 100644 RabiTracker/src/sig/utils/DebugUtils.java create mode 100644 RabiTracker/src/sig/utils/FileUtils.java diff --git a/RabiTracker/RabiTracker.jar b/RabiTracker/RabiTracker.jar index 304237de4fa0efd4faf957888ba718a20e04310e..f79ed8b4e2368ca2924a19db949aa15f124aca89 100644 GIT binary patch delta 21181 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 E0URQFXaE2J delta 6871 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 memoryMap = new HashMap(); + + MemoryData(long baseAddress) { + memoryMap.put("1.75", baseAddress); + } + + public static void loadMemoryData() { + String[] contents = FileUtils.readFromFile("memoryData"); + for (int i=0;i map = MemoryData.valueOf(split[0]).memoryMap; + + String[] split_data = split[1].split(";"); + int j=0; + while (j memoryMap, String key) { + switch (key) { + case "1.851":{ + return memoryMap.get("1.75")+OffsetHelper.KEY_ITEM_OFFSET_V175_TO_V1851.getUpgradeAddress(); + } + case "1.881":{ + return memoryMap.get("1.851")+ + OffsetHelper.KEY_ITEM_OFFSET_V175_TO_V1881.getUpgradeAddress()- + OffsetHelper.KEY_ITEM_OFFSET_V175_TO_V1851.getUpgradeAddress(); + } + case "1.90":{ + return memoryMap.get("1.881")+ + OffsetHelper.KEY_ITEM_OFFSET_V175_TO_V190.getUpgradeAddress()- + OffsetHelper.KEY_ITEM_OFFSET_V175_TO_V1881.getUpgradeAddress(); + } + default:{ + System.out.println("WARNING! key value "+key+" does not exist! Returning -1, which is probably not what you want."); + DebugUtils.showStackTrace(); + return -1l; + } + } + } + + public Long getOffset() { + return memoryMap.get(Window.RABI_RIBI_VERSION); + } + + enum OffsetHelper{ + KEY_ITEM_OFFSET_V175_TO_V1851(0x5744D0), + KEY_ITEM_OFFSET_V175_TO_V1881(0x5754D0), + KEY_ITEM_OFFSET_V175_TO_V190(0x5994E8); + + long upgradeAddress; + + OffsetHelper(long baseAddr) { + this.upgradeAddress = baseAddr; + } + public long getUpgradeAddress() { + return upgradeAddress; + } } -} +} \ No newline at end of file diff --git a/RabiTracker/src/RabiTracker/MemoryManager.java b/RabiTracker/src/RabiTracker/MemoryManager.java index 8d1ec11..29c4990 100644 --- a/RabiTracker/src/RabiTracker/MemoryManager.java +++ b/RabiTracker/src/RabiTracker/MemoryManager.java @@ -9,6 +9,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import com.sun.jna.Memory; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinNT; @@ -48,6 +49,12 @@ public class MemoryManager { } }, 5000, 5000, TimeUnit.MILLISECONDS); } + + public void update() { + if (foundRabiRibi) { + System.out.println("Game difficulty: "+readIntFromMemory(MemoryData.GAME_DIFFICULTY)); + } + } private void CheckRabiRibiClient() { List pids; @@ -95,4 +102,85 @@ public class MemoryManager { e.printStackTrace(); } } + + public int readIntFromMemory(long offset) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(rabiRibiMemOffset+offset), mem, 4, null); + return mem.getInt(0); + } + + public float readFloatFromMemory(long offset) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(rabiRibiMemOffset+offset), mem, 4, null); + return mem.getFloat(0); + } + + public float readFloatFromMemoryOffset(MemoryData val, long pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(pointer+val.getOffset()), mem, 4, null); + return mem.getFloat(0); + } + + public int readIntFromMemoryOffset(MemoryData val, long pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(pointer+val.getOffset()), mem, 4, null); + return mem.getInt(0); + } + + public float readDirectFloatFromMemoryLocation(long pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(pointer), mem, 4, null); + return mem.getFloat(0); + } + + public int readDirectIntFromMemoryLocation(long pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(pointer), mem, 4, null); + return mem.getInt(0); + } + + public int readIntFromPointer(MemoryData val, MemoryData pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(readIntFromMemory(pointer.getOffset())+val.getOffset()), mem, 4, null); + return mem.getInt(0); + } + + public float readFloatFromPointer(MemoryData val, MemoryData pointer) { + Memory mem = new Memory(4); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(readIntFromMemory(pointer.getOffset())+val.getOffset()), mem, 4, null); + return mem.getFloat(0); + } + + public int readIntFromMemory(MemoryData val) { + return (int)readFromMemory(val,MemoryType.INTEGER); + } + + public float readFloatFromMemory(MemoryData val) { + return (float)readFromMemory(val,MemoryType.FLOAT); + } + + Object readFromMemory(MemoryData val, MemoryType type) { + Memory mem = new Memory(type.getSize()); + Kernel32.INSTANCE.ReadProcessMemory(rabiribiProcess, new Pointer(rabiRibiMemOffset+val.getOffset()), mem, type.getSize(), null); + switch (type) { + case FLOAT: + return mem.getFloat(0); + case INTEGER: + return mem.getInt(0); + default: + System.out.println("WARNING! Type "+type+" does not have a defined value."); + return -1; + } + } + + int readItemCountFromMemory(MemoryData start_range, + MemoryData end_range) { + int count=0; + for (long i=start_range.getOffset();i<=end_range.getOffset();i++) { + if (readIntFromMemory(i)==1) { + count++; + } + } + return count; + } } diff --git a/RabiTracker/src/RabiTracker/MemoryType.java b/RabiTracker/src/RabiTracker/MemoryType.java new file mode 100644 index 0000000..138ce23 --- /dev/null +++ b/RabiTracker/src/RabiTracker/MemoryType.java @@ -0,0 +1,17 @@ +package RabiTracker; + +public enum MemoryType { + INTEGER(4), + FLOAT(4), + ; + + int bytes; + + MemoryType(int bytes) { + this.bytes=bytes; + } + + public int getSize() { + return bytes; + } +} diff --git a/RabiTracker/src/RabiTracker/Window.java b/RabiTracker/src/RabiTracker/Window.java index 52e9e76..4959529 100644 --- a/RabiTracker/src/RabiTracker/Window.java +++ b/RabiTracker/src/RabiTracker/Window.java @@ -30,6 +30,8 @@ public class Window extends JFrame{ public static int TICK = 0; + public static String RABI_RIBI_VERSION = "1.90"; //TODO Make a way to detect the version of the game. + JFrame window = new JFrame("Rabi Tracker v1.0"); DrawingPanel panel = new DrawingPanel(this); @@ -57,11 +59,15 @@ public class Window extends JFrame{ window.getContentPane().add(panel); window.setVisible(true); + + MemoryData.loadMemoryData(); } private void runTick() { Window.TICK++; panel.repaint(); + + mem.update(); } public void update() { diff --git a/RabiTracker/src/sig/utils/DebugUtils.java b/RabiTracker/src/sig/utils/DebugUtils.java new file mode 100644 index 0000000..afa3d40 --- /dev/null +++ b/RabiTracker/src/sig/utils/DebugUtils.java @@ -0,0 +1,55 @@ +package sig.utils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DebugUtils { + public static void showStackTrace() { + System.out.println("Trace:"+getStackTrace()); + } + + public static String getStackTrace() { + StackTraceElement[] stacktrace = new Throwable().getStackTrace(); + StringBuilder stack = new StringBuilder("Mini stack tracer:"); + for (int i=0;i contents= new ArrayList(); + if (file.exists()) { + try( + FileReader fw = new FileReader(filename); + BufferedReader bw = new BufferedReader(fw);) + { + String readline = bw.readLine(); + do { + if (readline!=null) { + //System.out.println(readline); + contents.add(readline); + readline = bw.readLine(); + }} while (readline!=null); + fw.close(); + bw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return contents.toArray(new String[contents.size()]); + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } + + private static String readFilter(Reader rd, HashMap channel_ids) throws IOException { + StringBuilder sb = new StringBuilder(); + boolean allowed=false; + boolean quotation_mark=false; + boolean endquotation_mark=false; + boolean foundChannel=false; + boolean nextBrace=false; + boolean outputStuff=false; + String numb = ""; + int braceCount=0; + int channelCount=0; + int vals=0; + int cp; + while ((cp = rd.read()) != -1) { + if (braceCount==0) { + allowed=true; + } else + if (braceCount==1 && !quotation_mark){ + quotation_mark=true; + numb=""; + allowed=false; + } else + if (!endquotation_mark) { + if ((char)cp >= '0' && + (char)cp <= '9') { + allowed=false; + numb+=(char)cp; + } else { + allowed=false; + endquotation_mark=true; + try { + if (channel_ids.containsKey(Long.parseLong(numb))) { + if (channelCount>=1) { + sb.append(","); + } + sb.append("\""+numb+"\""); + foundChannel=true; + System.out.println("Found channel "+numb); + outputStuff=true; + } + } catch (NumberFormatException e) { + + } + } + } else + if (!nextBrace && foundChannel) { + allowed=true; + if ((char)cp == '{') { + nextBrace=true; + } + } else + if (foundChannel) { + allowed=true; + if (braceCount==1) { + allowed=false; + channelCount++; + quotation_mark=false; + endquotation_mark=false; + foundChannel=false; + nextBrace=false; + } + } else { + allowed=false; + if (braceCount==1) { + allowed=false; + quotation_mark=false; + endquotation_mark=false; + foundChannel=false; + nextBrace=false; + } + } + + /*if (outputStuff && vals++<1000) { + System.out.print((char)cp); + }*/ + if ((char)cp == '{') { + braceCount++; + //System.out.println("Brace count is "+braceCount+"."); + } else + if ((char)cp == '}') { + braceCount--; + //System.out.println("Brace count is "+braceCount+"."); + } + + if (allowed) { + sb.append((char) cp); + } + } + sb.append("}"); + //System.out.println("============="); + //System.out.println(sb.toString()); + return sb.toString(); + } + public static void writetoFile(String[] data, String filename) { + File file = new File(filename); + try { + + if (!file.exists()) { + file.createNewFile(); + } + + FileWriter fw = new FileWriter(file,false); + PrintWriter pw = new PrintWriter(fw); + + for (String s : data) { + pw.println(s); + } + pw.flush(); + pw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void copyFile(File source, File dest) throws IOException { + FileChannel sourceChannel = null; + FileChannel destChannel = null; + try { + sourceChannel = new FileInputStream(source).getChannel(); + destChannel = new FileOutputStream(dest).getChannel(); + destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); + }finally{ + sourceChannel.close(); + destChannel.close(); + } + } + + public static void deleteFile(String filename) { + File file = new File(filename); + if (file.exists()) { + file.delete(); + } + } +}