summaryrefslogtreecommitdiff
path: root/src/main/java/org/challman/pantheon_parser/App.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/challman/pantheon_parser/App.java')
-rw-r--r--src/main/java/org/challman/pantheon_parser/App.java398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/main/java/org/challman/pantheon_parser/App.java b/src/main/java/org/challman/pantheon_parser/App.java
new file mode 100644
index 0000000..4d6999f
--- /dev/null
+++ b/src/main/java/org/challman/pantheon_parser/App.java
@@ -0,0 +1,398 @@
+package org.challman.pantheon_parser;
+
+import org.challman.pantheon_parser.algorithm.BooyerMoore.MatchResult;
+import org.challman.pantheon_parser.algorithm.BooyerMoore;
+import org.jnetpcap.BpFilter;
+import org.jnetpcap.Pcap;
+import org.jnetpcap.PcapException;
+import org.jnetpcap.PcapHeader;
+import org.jnetpcap.PcapIf;
+
+import javax.swing.*;
+import java.awt.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+import java.sql.Time;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+public class App {
+ private static HashMap<String, String> entityDict = new HashMap<>();
+ private static EntityMap entityMap;
+ private static Entity player = new Entity();
+
+ private static void debugDuplicateCoordinates() {
+ System.out.println("=== DEBUG: Checking for duplicate coordinates ===");
+
+ // Get all entities from entityMap (you'll need to add a method to EntityMap)
+ Collection<Entity> allEntities = entityMap.getAllEntities(); // You'll need to implement this
+
+ if (allEntities == null || allEntities.isEmpty()) {
+ System.out.println("No entities found");
+ return;
+ }
+
+ // Group entities by coordinates
+ Map<String, List<Entity>> coordMap = new HashMap<>();
+
+ for (Entity entity : allEntities) {
+ String coordKey = String.format("%.2f,%.2f,%.2f", entity.x, entity.y, entity.z);
+ coordMap.computeIfAbsent(coordKey, k -> new ArrayList<>()).add(entity);
+ }
+
+ // Find and report duplicates
+ boolean foundDuplicates = false;
+ for (Map.Entry<String, List<Entity>> entry : coordMap.entrySet()) {
+ if (entry.getValue().size() > 1) {
+ foundDuplicates = true;
+ System.out.println("DUPLICATE COORDINATES: " + entry.getKey());
+ for (Entity entity : entry.getValue()) {
+ System.out.println(" - " + entity.name + " (ID: " + entity.id + ") " +
+ "lastUpdated: " + entity.lastUpdated);
+ }
+ }
+ }
+
+ if (!foundDuplicates) {
+ System.out.println("No duplicate coordinates found");
+ }
+
+ // Also check for entities with same ID but different objects
+ debugSameIdDifferentObjects();
+
+ System.out.println("Total entities: " + allEntities.size());
+ System.out.println("Unique coordinates: " + coordMap.size());
+ System.out.println("=== END DEBUG ===");
+ }
+
+ private static void debugSameIdDifferentObjects() {
+ System.out.println("=== DEBUG: Checking for same ID, different objects ===");
+
+ Collection<Entity> allEntities = entityMap.getAllEntities();
+ Map<String, Set<Integer>> idMap = new HashMap<>();
+
+ for (Entity entity : allEntities) {
+ String idHash = entity.id + "|" + System.identityHashCode(entity);
+ idMap.computeIfAbsent(entity.id, k -> new HashSet<>()).add(System.identityHashCode(entity));
+ }
+
+ boolean foundDuplicates = false;
+ for (Map.Entry<String, Set<Integer>> entry : idMap.entrySet()) {
+ if (entry.getValue().size() > 1) {
+ foundDuplicates = true;
+ System.out.println("DUPLICATE ENTITY ID WITH DIFFERENT OBJECTS: " + entry.getKey());
+ System.out.println(" Object hashes: " + entry.getValue());
+
+ // Show details of each duplicate
+ for (Entity entity : allEntities) {
+ if (entity.id.equals(entry.getKey())) {
+ System.out.println(" - " + entity.name + " @ " +
+ String.format("(%.2f,%.2f,%.2f)", entity.x, entity.y, entity.z) +
+ " lastUpdated: " + entity.lastUpdated +
+ " objHash: " + System.identityHashCode(entity));
+ }
+ }
+ }
+ }
+
+ if (!foundDuplicates) {
+ System.out.println("No duplicate entity objects found");
+ }
+ System.out.println("=== END DEBUG ===");
+ }
+
+ private static float bytesToHeading(byte[] headingBytes) {
+ // Convert 2 bytes to 16-bit unsigned integer
+ int headingInt = ((headingBytes[1] & 0xFF) << 8) | (headingBytes[0] & 0xFF);
+ // Convert to degrees (0-360)
+ return (headingInt / 65535.0f) * 360.0f;
+ }
+
+ private static void entityLocation(byte[] packet, Integer endIndex) {
+ byte[] entity_id = Arrays.copyOfRange(packet, endIndex + 1,endIndex + 6);
+ byte[] bytes_x = Arrays.copyOfRange(packet, endIndex + 21,endIndex + 25);
+ byte[] bytes_y = Arrays.copyOfRange(packet, endIndex + 26,endIndex + 30);
+ byte[] bytes_z = Arrays.copyOfRange(packet, endIndex + 31,endIndex + 35);
+
+ float value_x = ByteBuffer.wrap(bytes_x).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_y = ByteBuffer.wrap(bytes_y).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_z = ByteBuffer.wrap(bytes_z).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+
+ String entityIdHex = java.util.HexFormat.of().withUpperCase().formatHex(entity_id);
+ String name = entityDict.getOrDefault(entityIdHex, entityIdHex);
+
+ Entity entity = entityMap.getEntity(entityIdHex);
+ if (entity == null) {
+ entity = new Entity();
+ entity.id = entityIdHex;
+ entity.name = name;
+ }
+
+ if (!name.equals(entityIdHex)) {
+ entity.name = name;
+ }
+
+ entity.x = value_x;
+ entity.y = value_y;
+ entity.z = value_z;
+ entity.lastUpdated = System.currentTimeMillis();
+
+ entityMap.updateEntity(entity, player);
+
+ String output = String.format(
+ "entity location - entity id: %s x: %s %.2f y: %s %.2f z: %s %.2f",
+ name,
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_x), value_x,
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_y), value_y,
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_z), value_z
+ );
+// System.out.println(output);
+ }
+
+ private static void playerLocation(byte[] packet, Integer endIndex) {
+ byte[] entity_id = Arrays.copyOfRange(packet, endIndex + 1,endIndex + 6);
+ byte[] bytes_heading = Arrays.copyOfRange(packet, endIndex + 10,endIndex + 12);
+ byte[] bytes_x = Arrays.copyOfRange(packet, endIndex + 13,endIndex + 17);
+ byte[] bytes_y = Arrays.copyOfRange(packet, endIndex + 18,endIndex + 22);
+ byte[] bytes_z = Arrays.copyOfRange(packet, endIndex + 23,endIndex + 27);
+
+
+ float value_x = ByteBuffer.wrap(bytes_x).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_y = ByteBuffer.wrap(bytes_y).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_z = ByteBuffer.wrap(bytes_z).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float heading = bytesToHeading(bytes_heading);
+
+ player.id = java.util.HexFormat.of().withUpperCase().formatHex(entity_id);
+ player.name = java.util.HexFormat.of().withUpperCase().formatHex(entity_id);
+ player.x = value_x;
+ player.y = value_y;
+ player.z = value_z;
+ player.heading = heading;
+
+ String output = String.format(
+ "player location - entity id: %s x: %s %.2f y: %s %.2f z: %s %.2f",
+ java.util.HexFormat.of().withUpperCase().formatHex(entity_id),
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_x), value_x,
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_y), value_y,
+ java.util.HexFormat.of().withUpperCase().formatHex(bytes_z), value_z
+ );
+// System.out.println(output);
+ }
+
+ private static void entitySpawn(byte[] packet, Integer endIndex) {
+ if (packet[endIndex + 7] == (byte) 0x01 || packet[endIndex + 7] == (byte) 0x04) {
+ return;
+ }
+
+ Integer offset = 57;
+
+ Integer entityType = packet[endIndex + 7] & 0xFF;
+ byte[] entityId = Arrays.copyOfRange(packet, endIndex + 1, endIndex + 6);
+ Integer nameLength = (packet[endIndex + offset] & 0xFF) + ((packet[endIndex + offset + 1] & 0xFF) << 8);
+ byte[] nameBytes = Arrays.copyOfRange(packet, endIndex + offset + 2, endIndex + offset + 1 + nameLength);
+ String entityName = new String(nameBytes, StandardCharsets.US_ASCII);
+ String entityIdHex = java.util.HexFormat.of().withUpperCase().formatHex(entityId);
+
+ MatchResult result = subPacket("1c xx xx 00 02 00", packet, endIndex);
+
+ if (result == null) {
+ byte[] last = Arrays.copyOfRange(packet, endIndex, packet.length);
+ result = new MatchResult(last, null, 0, last.length);
+ }
+
+ byte[] subPacket = Arrays.copyOfRange(result.packet, 0, result.endIndex);
+
+ BooyerMoore matcher = new BooyerMoore();
+ matcher.addPattern("15 00 00 xx xx fb");
+
+ List<MatchResult> matches = matcher.search(subPacket);
+
+ if (!matches.isEmpty()) {
+ MatchResult locationResult = matches.getFirst();
+ Entity entity = entityMap.getEntity(entityIdHex);
+ if (entity == null) {
+ entity = new Entity();
+ entity.name = entityName;
+ entity.id = entityIdHex;
+ }
+
+ entity.lastUpdated = -1;
+ entity.type = entityType;
+
+ byte[] bytes_heading = Arrays.copyOfRange(locationResult.packet, locationResult.endIndex - 2,locationResult.endIndex);
+ byte[] bytes_x = Arrays.copyOfRange(locationResult.packet, locationResult.endIndex + 1,locationResult.endIndex + 5);
+ byte[] bytes_y = Arrays.copyOfRange(locationResult.packet, locationResult.endIndex + 6,locationResult.endIndex + 10);
+ byte[] bytes_z = Arrays.copyOfRange(locationResult.packet, locationResult.endIndex + 11,locationResult.endIndex + 15);
+
+ float value_x = ByteBuffer.wrap(bytes_x).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_y = ByteBuffer.wrap(bytes_y).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float value_z = ByteBuffer.wrap(bytes_z).order(ByteOrder.LITTLE_ENDIAN).getFloat();
+ float heading = bytesToHeading(bytes_heading);
+
+ entity.x = value_x;
+ entity.y = value_y;
+ entity.z = value_z;
+ entity.heading = heading;
+
+ entityMap.updateEntity(entity, player);
+
+// System.out.println("Spawn location: x - " + entity.x + " y: " + entity.y + " z: " + entity.z);
+ }
+
+ entityDict.put(java.util.HexFormat.of().withUpperCase().formatHex(entityId), entityName);
+
+// System.out.println("Entity Name: " + entityName + " Entity ID: " + entityIdHex);
+ }
+
+ private static void chatMessage(byte[] packet, Integer endIndex) {
+ if ((packet[endIndex + 1] & 0xFF) > 0x09) {
+ return;
+ }
+
+ Integer offset = 5;
+ Integer playerNameLength = (packet[endIndex + offset] & 0xFF) + ((packet[endIndex + offset + 1] & 0xFF) << 8);
+ byte[] playerNameBytes = Arrays.copyOfRange(packet, endIndex + offset + 2, endIndex + offset + 2 + playerNameLength);
+ String playerName = new String(playerNameBytes, StandardCharsets.US_ASCII);
+
+ offset = endIndex + offset + 1 + playerNameLength;
+ Integer playerMessageLength = (packet[offset] & 0xFF) + ((packet[offset + 1] & 0xFF) << 8);
+ byte[] playerMessageBytes = Arrays.copyOfRange(packet, offset + 2, offset + 1 + playerMessageLength);
+ String playerMessage = new String(playerMessageBytes, StandardCharsets.US_ASCII);
+
+// System.out.println(playerName + " says: " + playerMessage);
+ }
+
+ private static MatchResult subPacket(String pattern, byte[] packet, Integer start) {
+ BooyerMoore matcher = new BooyerMoore();
+ matcher.addPattern(pattern);
+
+ packet = Arrays.copyOfRange(packet, start, packet.length);
+
+ List<MatchResult> matches = matcher.search(packet);
+
+ if (!matches.isEmpty()) {
+ return matches.getFirst();
+ }
+
+ return null;
+ }
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(() -> {
+ entityMap = new EntityMap();
+
+ JFrame frame = new JFrame("Minimap");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setUndecorated(true);
+ frame.setAlwaysOnTop(true);
+ frame.setResizable(false);
+ frame.add(entityMap);
+ frame.pack();
+ frame.setLocation(50, 50);
+
+ // Make it square
+ Dimension size = entityMap.getPreferredSize();
+ frame.setSize(size.width, size.height);
+
+ frame.setVisible(true);
+ });
+
+ HashMap<String, BiConsumer<byte[], Integer>> dict = new HashMap<>();
+
+ BooyerMoore matcher = new BooyerMoore();
+// matcher.addPattern("00 00 d9 eb 00"); // pet mob
+ matcher.addPattern("00 75 5c 01"); // pet
+// matcher.addPattern("1c xx xx 00 02 00");
+// matcher.addPattern("1a e7 00");
+// matcher.addPattern("1a e1 00");
+// matcher.addPattern("00 ff 00 00 00");
+// dict.put("1c fe fe 00 02 00", App::entitySpawn);
+// dict.put("1c fe fe 00 02 00", App::entitySpawn);
+
+// dict.put("1a e7 00", App::entityLocation);
+// dict.put("1a e1 00", App::playerLocation);
+// dict.put("00 ff 00 00 00", App::chatMessage);
+
+ try {
+ List<PcapIf> devices = Pcap.findAllDevs();
+
+ if (devices.isEmpty()) {
+ System.out.println("No devices found");
+ return;
+ }
+
+ System.out.println("Available devices:");
+ for (int i = 0; i < devices.size(); i++) {
+ PcapIf device = devices.get(i);
+ System.out.println(i + ": " + device.name());
+ System.out.println(" Description: " + device.description());
+ System.out.println();
+ }
+
+ // Use the first device
+ String deviceName = devices.get(3).name();
+ System.out.println("Using device: " + deviceName);
+
+ try (Pcap pcap = Pcap.openOffline("pantheon-combat.pcapng")){
+// try (Pcap pcap = Pcap.create(deviceName)) {
+// pcap.setImmediateMode(true);
+// pcap.setBufferSize(64 * 1024);
+// pcap.activate();
+ BpFilter filter = pcap.compile("host 20.22.207.201", true, 0);
+ pcap.setFilter(filter);
+
+ System.out.println("opened");
+ pcap.loop(-1, (String user, PcapHeader header, byte[] packet) -> {
+ packet = Arrays.copyOfRange(packet, 42, packet.length);
+ List<MatchResult> matches = matcher.search(packet);
+
+// debugDuplicateCoordinates();
+
+ if (!matches.isEmpty()) {
+ System.out.println("Packet captured at: " + header.timestamp());
+ System.out.println("Packet length: " + header.captureLength());
+ long timestampLong = (long) header.timestamp();
+ if (timestampLong == 1764204961927760L) {
+ for (int i = 0; i < packet.length; i++) {
+ System.out.printf("%02X ", packet[i]);
+ if ((i + 1) % 16 == 0) System.out.println(); // New line every 16 bytes
+ }
+ System.out.println("\n");
+ }
+ }
+
+ for (MatchResult match : matches) {
+ BiConsumer<byte[], Integer> handler = dict.get(match.toString());
+ System.out.println(match.toString());
+ if (handler != null) {
+ handler.accept(packet, match.endIndex);
+ }
+ }
+
+ if (!matches.isEmpty()) {
+ for (int i = 0; i < packet.length; i++) {
+ System.out.printf("%02X ", packet[i]);
+ if ((i + 1) % 16 == 0) System.out.println(); // New line every 16 bytes
+ }
+ System.out.println("\n");
+ }
+
+ return;
+ }, "Packet data");
+ } catch (PcapException e) {
+ System.out.println(e);
+ }
+
+ } catch (PcapException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ }
+} \ No newline at end of file