diff --git a/orebfuscator-plugin/pom.xml b/orebfuscator-plugin/pom.xml
index 6925b175..75b7dbba 100644
--- a/orebfuscator-plugin/pom.xml
+++ b/orebfuscator-plugin/pom.xml
@@ -67,6 +67,12 @@
${dependency.netty.version}
provided
+
+ io.netty
+ netty-transport
+ ${dependency.netty.version}
+ provided
+
org.spigotmc
spigot-api
diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java
index 6522c2c6..0660eab8 100644
--- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java
+++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java
@@ -13,6 +13,7 @@
import net.imprex.orebfuscator.api.OrebfuscatorService;
import net.imprex.orebfuscator.cache.ObfuscationCache;
import net.imprex.orebfuscator.config.OrebfuscatorConfig;
+import net.imprex.orebfuscator.injector.OrebfuscatorInjectorManager;
import net.imprex.orebfuscator.obfuscation.ObfuscationSystem;
import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap;
import net.imprex.orebfuscator.proximity.ProximityDirectorThread;
@@ -31,6 +32,7 @@ public class Orebfuscator extends JavaPlugin implements Listener {
private UpdateSystem updateSystem;
private ObfuscationCache obfuscationCache;
private ObfuscationSystem obfuscationSystem;
+ private OrebfuscatorInjectorManager injectorManager;
private ProximityDirectorThread proximityThread;
private ProximityPacketListener proximityPacketListener;
@@ -85,6 +87,7 @@ public void onEnable() {
// Load packet listener
this.obfuscationSystem.registerChunkListener();
+ this.injectorManager = new OrebfuscatorInjectorManager(this);
// Store formatted config
this.config.store();
@@ -120,6 +123,10 @@ public void onDisable() {
this.proximityThread.close();
}
+ if (this.injectorManager != null) {
+ this.injectorManager.close();
+ }
+
OrebfuscatorCompatibility.close();
OrebfuscatorNms.close();
diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java
index d786c008..fdff7044 100644
--- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java
+++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/OrebfuscatorStatistics.java
@@ -1,13 +1,18 @@
package net.imprex.orebfuscator;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.LongAdder;
+import java.util.function.DoubleSupplier;
import java.util.function.LongSupplier;
import com.google.gson.JsonObject;
public class OrebfuscatorStatistics {
+ private static final long MICRO_SCALE = 1000L;
+ private static final long MILLI_SCALE = 1000L * MICRO_SCALE;
+ private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
+
private static String formatPrecent(double percent) {
return String.format("%.2f%%", percent * 100);
}
@@ -34,32 +39,45 @@ private static String formatBytes(long bytes) {
}
}
- private final AtomicLong cacheHitCountMemory = new AtomicLong(0);
- private final AtomicLong cacheHitCountDisk = new AtomicLong(0);
- private final AtomicLong cacheMissCount = new AtomicLong(0);
- private final AtomicLong cacheEstimatedSize = new AtomicLong(0);
+ private static String formatNanos(double nanos) {
+ if (nanos > SECOND_SCALE) {
+ return String.format("%.2f s", nanos / SECOND_SCALE);
+ } else if (nanos > MILLI_SCALE) {
+ return String.format("%.2f ms", nanos / MILLI_SCALE);
+ } else if (nanos > MICRO_SCALE) {
+ return String.format("%.2f µs", nanos / MICRO_SCALE);
+ } else {
+ return String.format("%d ns", nanos);
+ }
+ }
+
+ private final LongAdder cacheHitCountMemory = new LongAdder();
+ private final LongAdder cacheHitCountDisk = new LongAdder();
+ private final LongAdder cacheMissCount = new LongAdder();
+ private final LongAdder cacheEstimatedSize = new LongAdder();
private LongSupplier memoryCacheSize = () -> 0;
private LongSupplier diskCacheQueueLength = () -> 0;
private LongSupplier obfuscationQueueLength = () -> 0;
+ private DoubleSupplier averagePacketDelay = () -> 0;
private LongSupplier obfuscationWaitTime = () -> 0;
private LongSupplier obfuscationProcessTime = () -> 0;
private LongSupplier proximityWaitTime = () -> 0;
private LongSupplier proximityProcessTime = () -> 0;
public void onCacheHitMemory() {
- this.cacheHitCountMemory.incrementAndGet();
+ this.cacheHitCountMemory.increment();
}
public void onCacheHitDisk() {
- this.cacheHitCountDisk.incrementAndGet();
+ this.cacheHitCountDisk.increment();
}
public void onCacheMiss() {
- this.cacheMissCount.incrementAndGet();
+ this.cacheMissCount.increment();
}
public void onCacheSizeChange(int delta) {
- this.cacheEstimatedSize.addAndGet(delta);
+ this.cacheEstimatedSize.add(delta);
}
public void setMemoryCacheSizeSupplier(LongSupplier supplier) {
@@ -74,6 +92,10 @@ public void setObfuscationQueueLengthSupplier(LongSupplier supplier) {
this.obfuscationQueueLength = Objects.requireNonNull(supplier);
}
+ public void setAveragePacketDelay(DoubleSupplier supplier) {
+ this.averagePacketDelay = Objects.requireNonNull(supplier);
+ }
+
public void setObfuscationWaitTime(LongSupplier supplier) {
this.obfuscationWaitTime = Objects.requireNonNull(supplier);
}
@@ -92,13 +114,14 @@ public void setProximityProcessTime(LongSupplier supplier) {
@Override
public String toString() {
- long cacheHitCountMemory = this.cacheHitCountMemory.get();
- long cacheHitCountDisk = this.cacheHitCountDisk.get();
- long cacheMissCount = this.cacheMissCount.get();
- long cacheEstimatedSize = this.cacheEstimatedSize.get();
+ long cacheHitCountMemory = this.cacheHitCountMemory.sum();
+ long cacheHitCountDisk = this.cacheHitCountDisk.sum();
+ long cacheMissCount = this.cacheMissCount.sum();
+ long cacheEstimatedSize = this.cacheEstimatedSize.sum();
long memoryCacheSize = this.memoryCacheSize.getAsLong();
long diskCacheQueueLength = this.diskCacheQueueLength.getAsLong();
long obfuscationQueueLength = this.obfuscationQueueLength.getAsLong();
+ double averagePacketDelay = this.averagePacketDelay.getAsDouble();
double totalCacheRequest = (double) (cacheHitCountMemory + cacheHitCountDisk + cacheMissCount);
@@ -123,6 +146,7 @@ public String toString() {
builder.append(" - memoryCacheEntries: ").append(memoryCacheSize).append('\n');
builder.append(" - diskCacheQueueLength: ").append(diskCacheQueueLength).append('\n');
builder.append(" - obfuscationQueueLength: ").append(obfuscationQueueLength).append('\n');
+ builder.append(" - averagePacketDelay: ").append(formatNanos(averagePacketDelay)).append('\n');
long obfuscationWaitTime = this.obfuscationWaitTime.getAsLong();
long obfuscationProcessTime = this.obfuscationProcessTime.getAsLong();
@@ -158,13 +182,14 @@ public String toString() {
public JsonObject toJson() {
JsonObject object = new JsonObject();
- object.addProperty("cacheHitCountMemory", this.cacheHitCountMemory.get());
- object.addProperty("cacheHitCountDisk", this.cacheHitCountDisk.get());
- object.addProperty("cacheMissCount", this.cacheMissCount.get());
- object.addProperty("cacheEstimatedSize", this.cacheEstimatedSize.get());
+ object.addProperty("cacheHitCountMemory", this.cacheHitCountMemory.sum());
+ object.addProperty("cacheHitCountDisk", this.cacheHitCountDisk.sum());
+ object.addProperty("cacheMissCount", this.cacheMissCount.sum());
+ object.addProperty("cacheEstimatedSize", this.cacheEstimatedSize.sum());
object.addProperty("memoryCacheSize", this.memoryCacheSize.getAsLong());
object.addProperty("diskCacheQueueLength", this.diskCacheQueueLength.getAsLong());
object.addProperty("obfuscationQueueLength", this.obfuscationQueueLength.getAsLong());
+ object.addProperty("averagePacketDelayNano", this.averagePacketDelay.getAsDouble());
object.addProperty("obfuscationWaitTime", this.obfuscationWaitTime.getAsLong());
object.addProperty("obfuscationProcessTime", this.obfuscationProcessTime.getAsLong());
object.addProperty("proximityWaitTime", this.proximityWaitTime.getAsLong());
diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/injector/AsyncOutboundPacketHandler.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/injector/AsyncOutboundPacketHandler.java
new file mode 100644
index 00000000..917d5f66
--- /dev/null
+++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/injector/AsyncOutboundPacketHandler.java
@@ -0,0 +1,146 @@
+package net.imprex.orebfuscator.injector;
+
+import java.util.ArrayDeque;
+import java.util.ConcurrentModificationException;
+import java.util.Queue;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.PacketType.Protocol;
+import com.comphenix.protocol.injector.packet.PacketRegistry;
+import com.comphenix.protocol.utility.MinecraftReflection;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.EventLoop;
+import io.netty.util.concurrent.Promise;
+import net.imprex.orebfuscator.util.OFCLogger;
+
+public class AsyncOutboundPacketHandler extends ChannelOutboundHandlerAdapter {
+
+ private final OrebfuscatorInjector injector;
+ private final Queue pendingWrites = new ArrayDeque<>();
+
+ private ChannelHandlerContext context;
+
+ public AsyncOutboundPacketHandler(OrebfuscatorInjector injector) {
+ this.injector = injector;
+ }
+
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ this.context = ctx;
+ }
+
+ @Override
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+ Promise