diff --git a/G-Earth/src/main/java/gearth/protocol/TrafficListener.java b/G-Earth/src/main/java/gearth/protocol/TrafficListener.java index da5a11c..7a843ff 100644 --- a/G-Earth/src/main/java/gearth/protocol/TrafficListener.java +++ b/G-Earth/src/main/java/gearth/protocol/TrafficListener.java @@ -2,6 +2,10 @@ package gearth.protocol; public interface TrafficListener { + int BEFORE_MODIFICATION = 0; + int MODIFICATION = 1; + int AFTER_MODIFICATION = 2; + void onCapture(HMessage message); } diff --git a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java index 616354c..8911632 100644 --- a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java +++ b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java @@ -6,9 +6,9 @@ import gearth.protocol.HMessage; import gearth.protocol.crypto.RC4; import gearth.protocol.memory.habboclient.HabboClient; import gearth.protocol.memory.habboclient.HabboClientFactory; +import gearth.protocol.packethandler.EncryptedPacketHandler; import gearth.protocol.packethandler.PayloadBuffer; import gearth.protocol.packethandler.flash.BufferChangeListener; -import gearth.protocol.packethandler.flash.FlashPacketHandler; import gearth.ui.titlebar.TitleBarController; import gearth.ui.translations.LanguageBundle; import javafx.application.Platform; @@ -28,32 +28,32 @@ public class Rc4Obtainer { public static final boolean DEBUG = false; private final HabboClient client; - private List flashPacketHandlers; + private List flashPacketHandlers; public Rc4Obtainer(HConnection hConnection) { client = HabboClientFactory.get(hConnection); } - public void setFlashPacketHandlers(FlashPacketHandler... flashPacketHandlers) { + public void setFlashPacketHandlers(EncryptedPacketHandler... flashPacketHandlers) { this.flashPacketHandlers = Arrays.asList(flashPacketHandlers); - for (FlashPacketHandler handler : flashPacketHandlers) { + for (EncryptedPacketHandler handler : flashPacketHandlers) { BufferChangeListener bufferChangeListener = new BufferChangeListener() { @Override - public void act() { + public void onPacket() { if (handler.isEncryptedStream()) { onSendFirstEncryptedMessage(handler); - handler.getBufferChangeObservable().removeListener(this); + handler.getPacketReceivedObservable().removeListener(this); } } }; - handler.getBufferChangeObservable().addListener(bufferChangeListener); + handler.getPacketReceivedObservable().addListener(bufferChangeListener); } } - private void onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler) { + private void onSendFirstEncryptedMessage(EncryptedPacketHandler flashPacketHandler) { if (!HConnection.DECRYPTPACKETS) return; - flashPacketHandlers.forEach(FlashPacketHandler::block); + flashPacketHandlers.forEach(EncryptedPacketHandler::block); new Thread(() -> { @@ -99,11 +99,11 @@ public class Rc4Obtainer { if (DEBUG) System.out.println("Cracked RC4 in " + (endTime - startTime) + "ms"); - flashPacketHandlers.forEach(FlashPacketHandler::unblock); + flashPacketHandlers.forEach(EncryptedPacketHandler::unblock); }).start(); } - private boolean onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler, List potentialRC4tables) { + private boolean onSendFirstEncryptedMessage(EncryptedPacketHandler flashPacketHandler, List potentialRC4tables) { for (byte[] possible : potentialRC4tables) if (isCorrectRC4Table(flashPacketHandler, possible)) @@ -112,7 +112,7 @@ public class Rc4Obtainer { return false; } - private boolean isCorrectRC4Table(FlashPacketHandler flashPacketHandler, byte[] possible) { + private boolean isCorrectRC4Table(EncryptedPacketHandler flashPacketHandler, byte[] possible) { try { @@ -127,7 +127,7 @@ public class Rc4Obtainer { final byte[] keycpy = Arrays.copyOf(possible, possible.length); final RC4 rc4Tryout = new RC4(keycpy, i, j); - if (flashPacketHandler.getMessageSide() == HMessage.Direction.TOSERVER) + if (flashPacketHandler.getDirection() == HMessage.Direction.TOSERVER) rc4Tryout.undoRc4(encBuffer); if (rc4Tryout.couldBeFresh()) { diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/EncryptedPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/EncryptedPacketHandler.java new file mode 100644 index 0000000..5495a3f --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/EncryptedPacketHandler.java @@ -0,0 +1,133 @@ +package gearth.protocol.packethandler; + +import gearth.misc.listenerpattern.Observable; +import gearth.protocol.HConnection; +import gearth.protocol.HMessage; +import gearth.protocol.TrafficListener; +import gearth.protocol.crypto.RC4; +import gearth.protocol.packethandler.flash.BufferChangeListener; +import gearth.services.extension_handler.ExtensionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public abstract class EncryptedPacketHandler extends PacketHandler { + + private static final Logger logger = LoggerFactory.getLogger(EncryptedPacketHandler.class); + + /** + * Fires when a packet is received. + */ + private final Observable packetReceivedObservable; + private final HMessage.Direction direction; + private volatile boolean isTempBlocked; + private volatile boolean isEncryptedStream; + private volatile List tempEncryptedBuffer; + + private RC4 encryptCipher; + private RC4 decryptCipher; + + protected EncryptedPacketHandler(ExtensionHandler extensionHandler, Observable[] trafficObservables, HMessage.Direction direction) { + super(extensionHandler, trafficObservables); + + this.packetReceivedObservable = new Observable<>(BufferChangeListener::onPacket); + this.direction = direction; + this.isTempBlocked = false; + this.isEncryptedStream = false; + this.tempEncryptedBuffer = new ArrayList<>(); + } + + public boolean isBlocked() { + return isTempBlocked; + } + + public void setEncryptedStream() { + isEncryptedStream = true; + } + + public boolean isEncryptedStream() { + return isEncryptedStream; + } + + public HMessage.Direction getDirection() { + return direction; + } + + public Observable getPacketReceivedObservable() { + return packetReceivedObservable; + } + + @Override + public void act(byte[] buffer) throws IOException { + packetReceivedObservable.fireEvent(); + + if (!isEncryptedStream()) { + writeBuffer(buffer); + } else if (!HConnection.DECRYPTPACKETS) { + writeOut(buffer); + } else if (decryptCipher == null) { + for (int i = 0; i < buffer.length; i++) { + tempEncryptedBuffer.add(buffer[i]); + } + } else { + writeBuffer(decryptCipher.rc4(buffer)); + } + } + + protected byte[] encrypt(byte[] buffer) { + return encryptCipher.rc4(buffer); + } + + protected byte[] decrypt(byte[] buffer) { + return decryptCipher.rc4(buffer); + } + + protected abstract void writeOut(byte[] buffer) throws IOException; + + protected abstract void writeBuffer(byte[] buffer) throws IOException; + + protected abstract void flush() throws IOException; + + public void block() { + isTempBlocked = true; + } + + public void unblock() { + try { + flush(); + } catch (IOException e) { + logger.error("Failed to flush buffer after unblocking packet handler", e); + } + + isTempBlocked = false; + } + + public void setRc4(RC4 rc4) { + this.decryptCipher = rc4.deepCopy(); + this.encryptCipher = rc4.deepCopy(); + + final byte[] buffer = new byte[tempEncryptedBuffer.size()]; + + for (int i = 0; i < tempEncryptedBuffer.size(); i++) { + buffer[i] = tempEncryptedBuffer.get(i); + } + + try { + // Write out all captured packets. + act(buffer); + } catch (IOException e) { + logger.error("Failed to write out captured encrypted buffer", e); + } + + this.tempEncryptedBuffer.clear(); + this.tempEncryptedBuffer = null; + } + + public List getEncryptedBuffer() { + return tempEncryptedBuffer; + } + +} diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java index 9748dd3..d034886 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java @@ -9,23 +9,23 @@ import java.io.IOException; public abstract class PacketHandler { - protected final ExtensionHandler extensionHandler; - private final Object[] trafficObservables; //get notified on packet send + private final ExtensionHandler extensionHandler; + private final Observable[] trafficObservables; //get notified on packet send protected volatile int currentIndex = 0; protected final Object sendLock = new Object(); + protected final Object flushLock = new Object(); - protected PacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables) { + protected PacketHandler(ExtensionHandler extensionHandler, Observable[] trafficObservables) { this.extensionHandler = extensionHandler; this.trafficObservables = trafficObservables; } - public abstract boolean sendToStream(byte[] buffer); public abstract void act(byte[] buffer) throws IOException; protected void notifyListeners(int i, HMessage message) { - ((Observable) trafficObservables[i]).fireEvent(trafficListener -> { + trafficObservables[i].fireEvent(trafficListener -> { message.getPacket().resetReadIndex(); trafficListener.onCapture(message); }); @@ -33,10 +33,10 @@ public abstract class PacketHandler { } protected void awaitListeners(HMessage message, PacketSender packetSender) { - notifyListeners(0, message); - notifyListeners(1, message); + notifyListeners(TrafficListener.BEFORE_MODIFICATION, message); + notifyListeners(TrafficListener.MODIFICATION, message); extensionHandler.handle(message, message2 -> { - notifyListeners(2, message2); + notifyListeners(TrafficListener.AFTER_MODIFICATION, message2); if (!message2.isBlocked()) { packetSender.send(message2); } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java index e39d6e7..7d1bbcd 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java @@ -3,6 +3,6 @@ package gearth.protocol.packethandler.flash; public interface BufferChangeListener { - void act(); + void onPacket(); } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java index 98b7ffe..4b00b1c 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java @@ -1,53 +1,37 @@ package gearth.protocol.packethandler.flash; import gearth.misc.listenerpattern.Observable; -import gearth.protocol.HConnection; import gearth.protocol.HMessage; import gearth.protocol.HPacket; -import gearth.protocol.crypto.RC4; -import gearth.protocol.packethandler.PacketHandler; +import gearth.protocol.TrafficListener; +import gearth.protocol.packethandler.EncryptedPacketHandler; import gearth.protocol.packethandler.PayloadBuffer; import gearth.services.extension_handler.ExtensionHandler; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -public abstract class FlashPacketHandler extends PacketHandler { - - protected static final boolean DEBUG = false; - - private volatile OutputStream out; - private volatile boolean isTempBlocked = false; - volatile boolean isDataStream = false; - - private final Object manipulationLock = new Object(); - - private RC4 decryptcipher = null; - private RC4 encryptcipher = null; - - private volatile List tempEncryptedBuffer = new ArrayList<>(); - volatile boolean isEncryptedStream = false; +public abstract class FlashPacketHandler extends EncryptedPacketHandler { + private final OutputStream out; private final PayloadBuffer payloadBuffer; + private volatile boolean isDataStream; - - FlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) { - super(extensionHandler, trafficObservables); - out = outputStream; + FlashPacketHandler(HMessage.Direction direction, OutputStream outputStream, Observable[] trafficObservables, ExtensionHandler extensionHandler) { + super(extensionHandler, trafficObservables, direction); + this.out = outputStream; this.payloadBuffer = new PayloadBuffer(); + this.isDataStream = false; + } + + public boolean isDataStream() { + return isDataStream; } - public boolean isDataStream() {return isDataStream;} public void setAsDataStream() { isDataStream = true; } - public boolean isEncryptedStream() { - return isEncryptedStream; - } - public void act(byte[] buffer) throws IOException { if (!isDataStream) { synchronized (sendLock) { @@ -56,76 +40,33 @@ public abstract class FlashPacketHandler extends PacketHandler { return; } - bufferChangeObservable.fireEvent(); + super.act(buffer); - if (!isEncryptedStream) { - payloadBuffer.push(buffer); - } - else if (!HConnection.DECRYPTPACKETS) { - synchronized (sendLock) { - out.write(buffer); - } - } - else if (decryptcipher == null) { - for (int i = 0; i < buffer.length; i++) { - tempEncryptedBuffer.add(buffer[i]); - } - } - else { - byte[] tm = decryptcipher.rc4(buffer); - if (DEBUG) { - printForDebugging(tm); - } - payloadBuffer.push(tm); - } - - if (!isTempBlocked) { + if (!isBlocked()) { flush(); } } - - public void setRc4(RC4 rc4) { - this.decryptcipher = rc4.deepCopy(); - this.encryptcipher = rc4.deepCopy(); - - byte[] encrbuffer = new byte[tempEncryptedBuffer.size()]; - for (int i = 0; i < tempEncryptedBuffer.size(); i++) { - encrbuffer[i] = tempEncryptedBuffer.get(i); + @Override + protected void writeOut(byte[] buffer) throws IOException { + synchronized (sendLock) { + out.write(buffer); } - - try { - act(encrbuffer); - } catch (IOException e) { - e.printStackTrace(); - } - tempEncryptedBuffer = null; } - public void block() { - isTempBlocked = true; - } - public void unblock() { - try { - flush(); - } catch (IOException e) { - e.printStackTrace(); - } - isTempBlocked = false; + @Override + protected void writeBuffer(byte[] buffer) { + payloadBuffer.push(buffer); } public boolean sendToStream(byte[] buffer) { - return sendToStream(buffer, isEncryptedStream); + return sendToStream(buffer, isEncryptedStream()); } private boolean sendToStream(byte[] buffer, boolean isEncrypted) { synchronized (sendLock) { try { - out.write( - (!isEncrypted) - ? buffer - : encryptcipher.rc4(buffer) - ); + out.write(isEncrypted ? encrypt(buffer) : buffer); return true; } catch (IOException e) { e.printStackTrace(); @@ -135,12 +76,12 @@ public abstract class FlashPacketHandler extends PacketHandler { } public void flush() throws IOException { - synchronized (manipulationLock) { + synchronized (flushLock) { HPacket[] hpackets = payloadBuffer.receive(); for (HPacket hpacket : hpackets){ - HMessage hMessage = new HMessage(hpacket, getMessageSide(), currentIndex); - boolean isencrypted = isEncryptedStream; + HMessage hMessage = new HMessage(hpacket, getDirection(), currentIndex); + boolean isencrypted = isEncryptedStream(); if (isDataStream) { awaitListeners(hMessage, hMessage1 -> sendToStream(hMessage1.getPacket().toBytes(), isencrypted)); @@ -153,21 +94,4 @@ public abstract class FlashPacketHandler extends PacketHandler { } } } - - public abstract HMessage.Direction getMessageSide(); - - public List getEncryptedBuffer() { - return tempEncryptedBuffer; - } - - protected abstract void printForDebugging(byte[] bytes); - - private Observable bufferChangeObservable = new Observable<>(BufferChangeListener::act); - public Observable getBufferChangeObservable() { - return bufferChangeObservable; - } - - public int getCurrentIndex() { - return currentIndex; - } } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java index d51935c..1fd8e2b 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java @@ -10,39 +10,29 @@ import java.io.OutputStream; public class IncomingFlashPacketHandler extends FlashPacketHandler { - public IncomingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, OutgoingFlashPacketHandler outgoingHandler, ExtensionHandler extensionHandler) { - super(outputStream, trafficObservables, extensionHandler); + public IncomingFlashPacketHandler(OutputStream outputStream, Observable[] trafficObservables, OutgoingFlashPacketHandler outgoingHandler, ExtensionHandler extensionHandler) { + super(HMessage.Direction.TOCLIENT, outputStream, trafficObservables, extensionHandler); TrafficListener listener = new TrafficListener() { @Override public void onCapture(HMessage message) { - if (isDataStream && message.getPacket().structureEquals("sb") && message.getPacket().length() > 500) { - ((Observable)trafficObservables[0]).removeListener(this); + if (isDataStream() && message.getPacket().structureEquals("sb") && message.getPacket().length() > 500) { + trafficObservables[TrafficListener.BEFORE_MODIFICATION].removeListener(this); HPacket packet = message.getPacket(); packet.readString(); - isEncryptedStream = packet.readBoolean(); - outgoingHandler.isEncryptedStream = true; - } - else if (isDataStream && message.getPacket().structureEquals("s") && message.getPacket().length() > 200) { - ((Observable)trafficObservables[0]).removeListener(this); - outgoingHandler.isEncryptedStream = true; - } - else if (message.getIndex() > 1) { - ((Observable)trafficObservables[0]).removeListener(this); + if (packet.readBoolean()) { + setEncryptedStream(); + } + outgoingHandler.setEncryptedStream(); + } else if (isDataStream() && message.getPacket().structureEquals("s") && message.getPacket().length() > 200) { + trafficObservables[TrafficListener.BEFORE_MODIFICATION].removeListener(this); + outgoingHandler.setEncryptedStream(); + } else if (message.getIndex() > 1) { + trafficObservables[TrafficListener.BEFORE_MODIFICATION].removeListener(this); } } }; - ((Observable)trafficObservables[0]).addListener(listener); - } - - @Override - public HMessage.Direction getMessageSide() { - return HMessage.Direction.TOCLIENT; - } - - @Override - protected void printForDebugging(byte[] bytes) { - System.out.println("-- DEBUG INCOMING -- " + new HPacket(bytes).toString() + " -- DEBUG --"); + trafficObservables[TrafficListener.BEFORE_MODIFICATION].addListener(listener); } } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java index ee7e823..be05e10 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java @@ -3,6 +3,7 @@ package gearth.protocol.packethandler.flash; import gearth.misc.listenerpattern.Observable; import gearth.protocol.HMessage; import gearth.protocol.HPacket; +import gearth.protocol.TrafficListener; import gearth.services.extension_handler.ExtensionHandler; import java.io.IOException; @@ -10,27 +11,34 @@ import java.io.OutputStream; public class OutgoingFlashPacketHandler extends FlashPacketHandler { - public OutgoingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) { - super(outputStream, trafficObservables, extensionHandler); + private final Observable datastreamConfirmedObservable; + + public OutgoingFlashPacketHandler(OutputStream outputStream, Observable[] trafficObservables, ExtensionHandler extensionHandler) { + super(HMessage.Direction.TOSERVER, outputStream, trafficObservables, extensionHandler); + + this.datastreamConfirmedObservable = new Observable<>(); } - - - private Observable datastreamConfirmedObservable = new Observable<>(); public void addOnDatastreamConfirmedListener(OnDatastreamConfirmedListener listener) { datastreamConfirmedObservable.addListener(listener); } private void dataStreamCheck(byte[] buffer) { - if (!isDataStream) { - HPacket hpacket = new HPacket(buffer); - isDataStream = (hpacket.getBytesLength() > 6 && hpacket.length() < 100); - if (isDataStream) { - String hotelVersion = hpacket.readString(); - String clientIdentifier = hpacket.readString(); - datastreamConfirmedObservable.fireEvent(l -> l.confirm(hotelVersion, clientIdentifier)); - } + if (isDataStream()) { + return; } + + final HPacket hpacket = new HPacket(buffer); + final boolean isValid = (hpacket.getBytesLength() > 6 && hpacket.length() < 100); + + if (!isValid) return; + + setAsDataStream(); + + final String hotelVersion = hpacket.readString(); + final String clientIdentifier = hpacket.readString(); + + datastreamConfirmedObservable.fireEvent(l -> l.confirm(hotelVersion, clientIdentifier)); } @Override @@ -38,15 +46,4 @@ public class OutgoingFlashPacketHandler extends FlashPacketHandler { dataStreamCheck(buffer); super.act(buffer); } - - @Override - public HMessage.Direction getMessageSide() { - return HMessage.Direction.TOSERVER; - } - - - @Override - protected void printForDebugging(byte[] bytes) { - System.out.println("-- DEBUG OUTGOING -- " + new HPacket(bytes).toString() + " -- DEBUG --"); - } } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/nitro/NitroPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/nitro/NitroPacketHandler.java index 853127b..3f845ad 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/nitro/NitroPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/nitro/NitroPacketHandler.java @@ -1,7 +1,9 @@ package gearth.protocol.packethandler.nitro; +import gearth.misc.listenerpattern.Observable; import gearth.protocol.HMessage; import gearth.protocol.HPacket; +import gearth.protocol.TrafficListener; import gearth.protocol.connection.proxy.nitro.websocket.NitroSession; import gearth.protocol.packethandler.PacketHandler; import gearth.protocol.packethandler.PayloadBuffer; @@ -22,7 +24,7 @@ public class NitroPacketHandler extends PacketHandler { private final PayloadBuffer payloadBuffer; private final Object payloadLock; - public NitroPacketHandler(HMessage.Direction direction, NitroSession session, ExtensionHandler extensionHandler, Object[] trafficObservables) { + public NitroPacketHandler(HMessage.Direction direction, NitroSession session, ExtensionHandler extensionHandler, Observable[] trafficObservables) { super(extensionHandler, trafficObservables); this.direction = direction; this.session = session; diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java index f85e55b..fa43095 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java @@ -1,7 +1,9 @@ package gearth.protocol.packethandler.unity; +import gearth.misc.listenerpattern.Observable; import gearth.protocol.HMessage; import gearth.protocol.HPacket; +import gearth.protocol.TrafficListener; import gearth.protocol.packethandler.ByteArrayUtils; import gearth.protocol.packethandler.PacketHandler; import gearth.services.extension_handler.ExtensionHandler; @@ -15,7 +17,7 @@ public class UnityPacketHandler extends PacketHandler { private final Session session; private final HMessage.Direction direction; - public UnityPacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables, Session session, HMessage.Direction direction) { + public UnityPacketHandler(ExtensionHandler extensionHandler, Observable[] trafficObservables, Session session, HMessage.Direction direction) { super(extensionHandler, trafficObservables); this.session = session; this.direction = direction;