diff options
Diffstat (limited to 'src/main/java/org/challman/pantheon_parser/App.java')
| -rw-r--r-- | src/main/java/org/challman/pantheon_parser/App.java | 398 |
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 |