diff options
author | alemi <me@alemi.dev> | 2023-03-14 22:33:19 +0100 |
---|---|---|
committer | alemi <me@alemi.dev> | 2023-03-14 22:33:19 +0100 |
commit | c942c352639fc53b00741345f44ebb18ce0a4cc8 (patch) | |
tree | 06f1733f253b2194d8ac161be5bc719882dbbae2 /src/main/java/ftbsc | |
parent | 924601fc906ce3072db21b0abee8fb9ccfeea31d (diff) |
feat: added PacketLogger module
Diffstat (limited to 'src/main/java/ftbsc')
-rw-r--r-- | src/main/java/ftbsc/bscv/modules/network/PacketLogger.java | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/bscv/modules/network/PacketLogger.java b/src/main/java/ftbsc/bscv/modules/network/PacketLogger.java new file mode 100644 index 0000000..5709b75 --- /dev/null +++ b/src/main/java/ftbsc/bscv/modules/network/PacketLogger.java @@ -0,0 +1,207 @@ +package ftbsc.bscv.modules.network; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.google.auto.service.AutoService; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import ftbsc.bscv.Boscovicino; +import ftbsc.bscv.api.ILoadable; +import ftbsc.bscv.modules.QuickModule; +import ftbsc.bscv.patches.PacketPatch.PacketEvent; +import net.minecraft.network.IPacket; +import net.minecraft.util.math.vector.Vector2f; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +@AutoService(ILoadable.class) +public class PacketLogger extends QuickModule { + + public static final SimpleDateFormat CAPTURE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss"); + + @Override + public void enable() { + this.capture = new JsonArray(); + super.enable(); + } + + @Override + public void disable() { + super.disable(); + try { + this.store(); + } catch (IOException e) { + e.printStackTrace(); + Boscovicino.LOGGER.error("dumping capture into logs"); + Boscovicino.LOGGER.error(this.capture.toString()); + } + } + + private JsonArray capture; + + @SubscribeEvent + public void onPacketOutgoing(PacketEvent.Outgoing event) { + try { + this.capture.add(this.packet_to_json(event.packet, this.pretty_time())); // get send time here + } catch (IllegalAccessException e) { + Boscovicino.LOGGER.warn("Could not process fields of packet {}", event.packet.toString()); + } + } + + @SubscribeEvent + public void onPacketIncoming(PacketEvent.Incoming event) { + try { + this.capture.add(this.packet_to_json(event.packet, this.pretty_time())); // get recv time here + } catch (IllegalAccessException e) { + Boscovicino.LOGGER.warn("Could not process fields of packet {}", event.packet.toString()); + } + } + + private void store() throws IOException { + // TODO make sure this folder exists and don't check for it each time we save a capture + Path basePath = Paths.get("logs/packets/"); + if (!Files.isDirectory(basePath)) { + Files.createDirectories(basePath); + } + + String capturePath = String.format("logs/packets/%s.json", CAPTURE_DATE_FORMAT.format(new Date())); + try (Writer writer = new FileWriter(capturePath)) { + Gson gson = new GsonBuilder().create(); + gson.toJson(this.capture, writer); + } + } + + private JsonElement packet_to_json(IPacket<?> packet, double time) throws IllegalAccessException { + Class<?> clazz = packet.getClass(); + List<String> classNames = new ArrayList<>(); + JsonObject fields = new JsonObject(); + while (clazz != null && !clazz.equals(Object.class)) { + classNames.add(clazz.getSimpleName()); + for (Field field : clazz.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + fields.add(field.getName(), this.format_value(field.get(packet))); // TODO deobfuscate field.getName() + } + } + clazz = clazz.getSuperclass(); + } + + JsonObject json = new JsonObject(); + json.addProperty("time", time); + json.addProperty("name", this.compose_packet_name(classNames)); + json.add("fields", fields); + return json; + } + + private JsonElement format_value(Object value) { + if (value == null) return null; + if (value instanceof ITextComponent) { + ITextComponent component = (ITextComponent) value; + JsonObject obj = new JsonObject(); + obj.add(value.getClass().getSimpleName(), ITextComponent.Serializer.toJsonTree(component)); + return obj; + } + if (value.getClass().isArray()) { + return this.array_to_string(value); + } + if (value instanceof Number) { + return new JsonPrimitive((Number) value); + } + if (value instanceof Boolean) { + return new JsonPrimitive((Boolean) value); + } + if (value instanceof String) { + return new JsonPrimitive((String) value); + } + if (value instanceof Character) { + return new JsonPrimitive((Character) value); + } + if (value instanceof Vector3d) { + Vector3d vec = (Vector3d) value; + return this.array_to_string(new double[] { vec.x(), vec.y(), vec.z() }); + } + if (value instanceof Vector2f) { + Vector2f vec = (Vector2f) value; + return this.array_to_string(new float[] { vec.x, vec.y }); + } + // TODO pretty print some very noisy toStrings + return new JsonPrimitive(value.toString()); + } + + private JsonArray array_to_string(Object value) { + JsonArray out = new JsonArray(); + if (value instanceof byte[]) { + byte[] arr = (byte[]) value; + for (byte b : arr) out.add(b); + return out; + } + if (value instanceof short[]) { + short[] arr = (short[]) value; + for (short s : arr) out.add(s); + return out; + } + if (value instanceof int[]) { + int[] arr = (int[]) value; + for (int s : arr) out.add(s); + return out; + } + if (value instanceof long[]) { + long[] arr = (long[]) value; + for (long s : arr) out.add(s); + return out; + } + if (value instanceof float[]) { + float[] arr = (float[]) value; + for (float s : arr) out.add(s); + return out; + } + if (value instanceof double[]) { + double[] arr = (double[]) value; + for (double s : arr) out.add(s); + return out; + } + if (value instanceof boolean[]) { + boolean[] arr = (boolean[]) value; + for (boolean s : arr) out.add(s); + return out; + } + if (value instanceof char[]) { + char[] arr = (char[]) value; + for (char s : arr) out.add(s); + return out; + } + Object[] arr = (Object[]) value; + for (Object o : arr) out.add(o.toString()); + return out; + } + + private String compose_packet_name(List<String> classNames) { + StringBuilder builder = new StringBuilder(); + for (int i = classNames.size() - 1; i >= 0; i--) { + builder.append(classNames.get(i)); + if (i > 0) builder.append("."); + } + return builder.toString(); + } + + private double pretty_time() { + return (double) System.nanoTime() / 1000000000.; + } +} |