feat: added PacketLogger module
This commit is contained in:
parent
924601fc90
commit
c942c35263
1 changed files with 207 additions and 0 deletions
207
src/main/java/ftbsc/bscv/modules/network/PacketLogger.java
Normal file
207
src/main/java/ftbsc/bscv/modules/network/PacketLogger.java
Normal file
|
@ -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.;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue