Merge branch 'development'

This commit is contained in:
sirjonasxx 2021-04-27 16:28:24 +02:00
commit 36f844d6dc
93 changed files with 2826 additions and 1438 deletions

View File

@ -13,7 +13,7 @@
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.3.4</version>
<version>1.4</version>
<relativePath>../../</relativePath>
</parent>
@ -106,7 +106,7 @@
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.3.4</version>
<version>1.4</version>
<!--<scope>provided</scope>-->
</dependency>
</dependencies>

View File

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>BlockReplacePackets</artifactId>
<packaging>jar</packaging>
<version>0.0.1-beta</version>
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.3.4</version>
<relativePath>../../</relativePath>
</parent>
<build>
<resources>
<!-- Embedded FXML and CSS resources -->
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**/*.fxml</include>
<include>**/*.css</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<outputDirectory>${project.build.directory}/bin</outputDirectory>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addClasspath>true</addClasspath>
<mainClass>extensions.blockreplacepackets.BlockAndReplacePackets</mainClass>
<useUniqueVersions>false</useUniqueVersions>
<classpathPrefix>lib/</classpathPrefix>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
<finalName>${project.artifactId}</finalName>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/bin</outputDirectory>
<archive>
<manifest>
<mainClass>extensions.blockreplacepackets.BlockAndReplacePackets</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
<!-- global build folder -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<configuration>
<target name="copy to extensions folder">
<copy file="target/bin/BlockReplacePackets.jar" todir="../../Build/Linux/Extensions"/>
<copy file="target/bin/BlockReplacePackets.jar" todir="../../Build/Mac/Extensions"/>
<copy file="target/bin/BlockReplacePackets.jar" todir="../../Build/Windows_32bit/Extensions"/>
<copy file="target/bin/BlockReplacePackets.jar" todir="../../Build/Windows_64bit/Extensions"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.3.4</version>
<!--<scope>provided</scope>-->
</dependency>
</dependencies>
</project>

View File

@ -8,7 +8,7 @@
<packaging>jar</packaging>
<version>1.3.4</version>
<version>1.4</version>
<properties>
<javafx.version>1.8</javafx.version>
@ -18,7 +18,7 @@
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.3.4</version>
<version>1.4</version>
</parent>
<build>

View File

@ -28,7 +28,7 @@ import java.util.Set;
public class Main extends Application {
public static Application main;
public static String version = "1.3.4";
public static String version = "1.4";
private static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest";
@Override
@ -45,7 +45,7 @@ public class Main extends Application {
primaryStage.setResizable(false);
primaryStage.setTitle("G-Earth " + version);
primaryStage.setScene(new Scene(root, 650, 295));
primaryStage.setScene(new Scene(root, 650, 290));
primaryStage.show();
primaryStage.getScene().getStylesheets().add(getClass().getResource("ui/bootstrap3.css").toExternalForm());

View File

@ -1,32 +1,22 @@
package gearth.extensions;
import gearth.misc.listenerpattern.Observable;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.HClient;
import gearth.services.Constants;
import gearth.services.extensionhandler.extensions.implementations.network.NetworkExtensionInfo;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Jonas on 23/06/18.
*/
public abstract class Extension implements IExtension {
public abstract class Extension extends ExtensionBase {
public interface MessageListener {
void act(HMessage message);
}
public interface FlagsCheckListener {
void act(String[] args);
}
protected boolean canLeave; // can you disconnect the ext
protected boolean canDelete; // can you delete the ext (will be false for some built-in extensions)
protected FlagsCheckListener flagRequestCallback = null;
private String[] args;
private boolean isCorrupted = false;
@ -34,10 +24,9 @@ public abstract class Extension implements IExtension {
private static final String[] FILE_FLAG = {"--filename", "-f"};
private static final String[] COOKIE_FLAG = {"--auth-token", "-c"}; // don't add a cookie or filename when debugging
protected PacketInfoManager packetInfoManager = new PacketInfoManager(new ArrayList<>()); // empty
private OutputStream out = null;
private final Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
private final Map<Integer, List<MessageListener>> outgoingMessageListeners = new HashMap<>();
private FlagsCheckListener flagRequestCallback = null;
private String getArgument(String[] args, String... arg) {
for (int i = 0; i < args.length - 1; i++) {
@ -55,8 +44,7 @@ public abstract class Extension implements IExtension {
* @param args arguments
*/
public Extension(String[] args) {
canLeave = canLeave();
canDelete = canDelete();
super();
//obtain port
this.args = args;
@ -132,18 +120,23 @@ public abstract class Extension implements IExtension {
.appendBoolean(file != null)
.appendString(file == null ? "": file)
.appendString(cookie == null ? "" : cookie)
.appendBoolean(canLeave)
.appendBoolean(canDelete);
.appendBoolean(canLeave())
.appendBoolean(canDelete());
writeToStream(response.toBytes());
}
else if (packet.headerId() == NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.CONNECTIONSTART) {
String host = packet.readString();
int connectionPort = packet.readInteger();
String hotelVersion = packet.readString();
String harbleMessagesPath = packet.readString();
String clientType = packet.readString();
Constants.UNITY_PACKETS = clientType.toLowerCase().contains("unity");
onConnectionObservable.fireEvent(l -> l.onConnection(host, connectionPort, hotelVersion, clientType, harbleMessagesPath));
String clientIdentifier = packet.readString();
HClient clientType = HClient.valueOf(packet.readString());
packetInfoManager = PacketInfoManager.readFromPacket(packet);
Constants.UNITY_PACKETS = clientType == HClient.UNITY;
getOnConnectionObservable().fireEvent(l -> l.onConnection(
host, connectionPort, hotelVersion,
clientIdentifier, clientType, packetInfoManager)
);
onStartConnection();
}
else if (packet.headerId() == NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.CONNECTIONEND) {
@ -171,36 +164,8 @@ public abstract class Extension implements IExtension {
else if (packet.headerId() == NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.PACKETINTERCEPT) {
String stringifiedMessage = packet.readLongString();
HMessage habboMessage = new HMessage(stringifiedMessage);
HPacket habboPacket = habboMessage.getPacket();
Map<Integer, List<MessageListener>> listeners =
habboMessage.getDestination() == HMessage.Direction.TOCLIENT ?
incomingMessageListeners :
outgoingMessageListeners;
List<MessageListener> correctListeners = new ArrayList<>();
synchronized (incomingMessageListeners) {
synchronized (outgoingMessageListeners) {
if (listeners.containsKey(-1)) { // registered on all packets
for (int i = listeners.get(-1).size() - 1; i >= 0; i--) {
correctListeners.add(listeners.get(-1).get(i));
}
}
if (listeners.containsKey(habboPacket.headerId())) {
for (int i = listeners.get(habboPacket.headerId()).size() - 1; i >= 0; i--) {
correctListeners.add(listeners.get(habboPacket.headerId()).get(i));
}
}
}
}
for(MessageListener listener : correctListeners) {
habboMessage.getPacket().resetReadIndex();
listener.act(habboMessage);
}
habboMessage.getPacket().resetReadIndex();
modifyMessage(habboMessage);
HPacket response = new HPacket(NetworkExtensionInfo.INCOMING_MESSAGES_IDS.MANIPULATEDPACKET);
response.appendLongString(habboMessage.stringify());
@ -249,6 +214,11 @@ public abstract class Extension implements IExtension {
return send(packet, HMessage.Direction.TOSERVER);
}
private boolean send(HPacket packet, HMessage.Direction direction) {
if (packet.isCorrupted()) return false;
if (!packet.isPacketComplete()) packet.completePacket(direction, packetInfoManager);
if (!packet.isPacketComplete()) return false;
HPacket packet1 = new HPacket(NetworkExtensionInfo.INCOMING_MESSAGES_IDS.SENDMESSAGE);
packet1.appendByte(direction == HMessage.Direction.TOCLIENT ? (byte)0 : (byte)1);
packet1.appendInt(packet.getBytesLength());
@ -261,37 +231,6 @@ public abstract class Extension implements IExtension {
}
}
/**
* Register a listener on a specific packet Type
* @param direction ToClient or ToServer
* @param headerId the packet header ID
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, int headerId, MessageListener messageListener) {
Map<Integer, List<MessageListener>> listeners =
direction == HMessage.Direction.TOCLIENT ?
incomingMessageListeners :
outgoingMessageListeners;
synchronized (listeners) {
if (!listeners.containsKey(headerId)) {
listeners.put(headerId, new ArrayList<>());
}
}
listeners.get(headerId).add(messageListener);
}
/**
* Register a listener on all packets
* @param direction ToClient or ToServer
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, MessageListener messageListener) {
intercept(direction, -1, messageListener);
}
/**
* Requests the flags which have been given to G-Earth when it got executed
* For example, you might want this extension to do a specific thing if the flag "-e" was given
@ -310,15 +249,6 @@ public abstract class Extension implements IExtension {
}
}
/**
* Write to the console in G-Earth
* @param s the text to be written
*/
public void writeToConsole(String s) {
writeToConsole("black", s, true);
}
/**
* Write to the console in G-Earth
* @param s the text to be written
@ -346,37 +276,12 @@ public abstract class Extension implements IExtension {
}
}
private boolean isOnClickMethodUsed() {
Class<? extends Extension> c = getClass();
while (c != Extension.class) {
try {
c.getDeclaredMethod("onClick");
// if it didnt error, onClick exists
return true;
} catch (NoSuchMethodException e) {
// e.printStackTrace();
}
c = (Class<? extends Extension>) c.getSuperclass();
}
return false;
}
/**
* Gets called when a connection has been established with G-Earth.
* This does not imply a connection with Habbo is setup.
*/
protected void initExtension(){}
/**
* The application got doubleclicked from the G-Earth interface. Doing something here is optional
*/
protected void onClick(){}
/**
* A connection with Habbo has been started
*/
@ -395,14 +300,4 @@ public abstract class Extension implements IExtension {
return true;
}
ExtensionInfo getInfoAnnotations() {
return getClass().getAnnotation(ExtensionInfo.class);
}
private Observable<OnConnectionListener> onConnectionObservable = new Observable<>();
public void onConnect(OnConnectionListener listener){
onConnectionObservable.addListener(listener);
}
}

View File

@ -0,0 +1,130 @@
package gearth.extensions;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ExtensionBase extends IExtension {
public interface MessageListener {
void act(HMessage message);
}
public interface FlagsCheckListener {
void act(String[] args);
}
protected final Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
protected final Map<Integer, List<MessageListener>> outgoingMessageListeners = new HashMap<>();
/**
* Register a listener on a specific packet Type
* @param direction ToClient or ToServer
* @param headerId the packet header ID
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, int headerId, MessageListener messageListener) {
Map<Integer, List<MessageListener>> listeners =
direction == HMessage.Direction.TOCLIENT ?
incomingMessageListeners :
outgoingMessageListeners;
synchronized (listeners) {
if (!listeners.containsKey(headerId)) {
listeners.put(headerId, new ArrayList<>());
}
}
listeners.get(headerId).add(messageListener);
}
/**
* Register a listener on all packets
* @param direction ToClient or ToServer
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, MessageListener messageListener) {
intercept(direction, -1, messageListener);
}
@Override
public void writeToConsole(String s) {
writeToConsole("black", s);
}
protected boolean isOnClickMethodUsed() {
Class<? extends ExtensionBase> c = getClass();
while (c != Extension.class) {
try {
c.getDeclaredMethod("onClick");
// if it didnt error, onClick exists
return true;
} catch (NoSuchMethodException e) {
// e.printStackTrace();
}
c = (Class<? extends ExtensionBase>) c.getSuperclass();
}
return false;
}
public void modifyMessage(HMessage habboMessage) {
HPacket habboPacket = habboMessage.getPacket();
Map<Integer, List<MessageListener>> listeners =
habboMessage.getDestination() == HMessage.Direction.TOCLIENT ?
incomingMessageListeners :
outgoingMessageListeners;
List<MessageListener> correctListeners = new ArrayList<>();
synchronized (incomingMessageListeners) {
synchronized (outgoingMessageListeners) {
if (listeners.containsKey(-1)) { // registered on all packets
for (int i = listeners.get(-1).size() - 1; i >= 0; i--) {
correctListeners.add(listeners.get(-1).get(i));
}
}
if (listeners.containsKey(habboPacket.headerId())) {
for (int i = listeners.get(habboPacket.headerId()).size() - 1; i >= 0; i--) {
correctListeners.add(listeners.get(habboPacket.headerId()).get(i));
}
}
}
}
for(MessageListener listener : correctListeners) {
habboMessage.getPacket().resetReadIndex();
listener.act(habboMessage);
}
habboMessage.getPacket().resetReadIndex();
}
/**
* The application got doubleclicked from the G-Earth interface. Doing something here is optional
*/
@Override
void onClick() {
}
@Override
protected ExtensionInfo getInfoAnnotations() {
return getClass().getAnnotation(ExtensionInfo.class);
}
private Observable<OnConnectionListener> onConnectionObservable = new Observable<>();
public void onConnect(OnConnectionListener listener){
onConnectionObservable.addListener(listener);
}
Observable<OnConnectionListener> getOnConnectionObservable() {
return onConnectionObservable;
}
}

View File

@ -8,9 +8,9 @@ import gearth.protocol.HPacket;
/**
* Created by Jonas on 22/09/18.
*/
public abstract class ExtensionForm implements IExtension {
public abstract class ExtensionForm extends ExtensionBase {
volatile Extension extension;
volatile ExtensionBase extension;
protected volatile Stage primaryStage;
protected static void runExtensionForm(String[] args, Class<? extends ExtensionForm> extension) {
@ -59,7 +59,7 @@ public abstract class ExtensionForm implements IExtension {
/**
* The application got doubleclicked from the G-Earth interface. Doing something here is optional
*/
protected void onClick(){
public void onClick(){
Platform.runLater(() -> {
primaryStage.show();
primaryStage.requestFocus();

View File

@ -5,7 +5,7 @@ import javafx.application.Platform;
import javafx.stage.Stage;
/**
* Created by Jeunez on 6/11/2018.
* Created by Jonas on 6/11/2018.
*/
public class ExtensionFormLauncher extends Application {
@ -19,7 +19,7 @@ public class ExtensionFormLauncher extends Application {
ExtensionForm creator = extension.newInstance();
ExtensionForm extensionForm = creator.launchForm(primaryStage);
extensionForm.extension = new Extension(args) {
Extension extension = new Extension(args) {
@Override
protected void initExtension() {
extensionForm.initExtension();
@ -41,7 +41,7 @@ public class ExtensionFormLauncher extends Application {
}
@Override
ExtensionInfo getInfoAnnotations() {
protected ExtensionInfo getInfoAnnotations() {
return extInfo;
}
@ -55,9 +55,11 @@ public class ExtensionFormLauncher extends Application {
return extensionForm.canDelete();
}
};
extensionForm.extension = extension;
extensionForm.primaryStage = primaryStage;
Thread t = new Thread(() -> {
extensionForm.extension.run();
extension.run();
//when the extension has ended, close this process
System.exit(0);
});

View File

@ -3,15 +3,22 @@ package gearth.extensions;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
public interface IExtension {
public abstract class IExtension {
boolean sendToClient(HPacket packet);
boolean sendToServer(HPacket packet);
void intercept(HMessage.Direction direction, int headerId, Extension.MessageListener messageListener);
void intercept(HMessage.Direction direction, Extension.MessageListener messageListener);
boolean requestFlags(Extension.FlagsCheckListener flagRequestCallback);
void writeToConsole(String colorClass, String s);
void writeToConsole(String s);
void onConnect(OnConnectionListener listener);
public abstract boolean sendToClient(HPacket packet);
public abstract boolean sendToServer(HPacket packet);
public abstract void intercept(HMessage.Direction direction, int headerId, Extension.MessageListener messageListener);
public abstract void intercept(HMessage.Direction direction, Extension.MessageListener messageListener);
public abstract boolean requestFlags(Extension.FlagsCheckListener flagRequestCallback);
public abstract void writeToConsole(String colorClass, String s);
public abstract void writeToConsole(String s);
public abstract void onConnect(OnConnectionListener listener);
abstract void initExtension();
abstract void onClick();
abstract void onStartConnection();
abstract void onEndConnection();
abstract ExtensionInfo getInfoAnnotations();
abstract boolean canLeave();
abstract boolean canDelete();
}

View File

@ -0,0 +1,68 @@
package gearth.extensions;
import gearth.Main;
import gearth.extensions.ExtensionBase;
import gearth.extensions.IExtension;
import gearth.protocol.HPacket;
public class InternalExtension extends ExtensionBase {
public interface InternalExtensionCommunicator {
void sendToClient(HPacket packet);
void sendToServer(HPacket packet);
void writeToConsole(String s);
}
private InternalExtensionCommunicator communicator = null;
public void setCommunicator(InternalExtensionCommunicator communicator) {
this.communicator = communicator;
}
@Override
public boolean sendToClient(HPacket packet) {
communicator.sendToClient(packet);
return true;
}
@Override
public boolean sendToServer(HPacket packet) {
communicator.sendToServer(packet);
return true;
}
@Override
public boolean requestFlags(FlagsCheckListener flagRequestCallback) {
flagRequestCallback.act(Main.args);
return true;
}
@Override
public void writeToConsole(String colorClass, String s) {
String text = "[" + colorClass + "]" + getInfoAnnotations().Title() + " --> " + s;
communicator.writeToConsole(text);
}
// to be maybe overwritten
@Override
protected void initExtension() { }
// to be maybe overwritten
@Override
protected void onStartConnection() {}
// to be maybe overwritten
@Override
protected void onEndConnection() {}
@Override
protected boolean canLeave() {
return false;
}
@Override
protected boolean canDelete() {
return false;
}
}

View File

@ -0,0 +1,145 @@
package gearth.extensions;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.HClient;
import gearth.services.extensionhandler.extensions.ExtensionType;
import gearth.services.extensionhandler.extensions.GEarthExtension;
// wraps internal GEarthExtension class to IExtension interface
// to allow internal extensions that follow the same remote-extensions interface
public class InternalExtensionBuilder extends GEarthExtension {
private final InternalExtension extension;
public InternalExtensionBuilder(InternalExtension extension) {
this.extension = extension;
extension.setCommunicator(new InternalExtension.InternalExtensionCommunicator() {
@Override
public void sendToClient(HPacket packet) {
sendMessage(HMessage.Direction.TOCLIENT, packet);
}
@Override
public void sendToServer(HPacket packet) {
sendMessage(HMessage.Direction.TOSERVER, packet);
}
@Override
public void writeToConsole(String s) {
log(s);
}
});
}
@Override
public String getAuthor() {
return extension.getInfoAnnotations().Author();
}
@Override
public String getDescription() {
return extension.getInfoAnnotations().Description();
}
@Override
public String getTitle() {
return extension.getInfoAnnotations().Title();
}
@Override
public String getVersion() {
return extension.getInfoAnnotations().Version();
}
@Override
public boolean isFireButtonUsed() {
Class<? extends InternalExtension > c = extension.getClass();
while (c != InternalExtension.class) {
try {
c.getDeclaredMethod("onClick");
return true;
} catch (NoSuchMethodException e) {
// e.printStackTrace();
}
c = (Class<? extends InternalExtension>) c.getSuperclass();
}
return false;
}
@Override
public boolean isDeleteButtonVisible() {
return extension.canDelete();
}
@Override
public boolean isLeaveButtonVisible() {
return extension.canLeave();
}
@Override
public boolean isInstalledExtension() {
return false;
}
@Override
public void doubleclick() {
extension.onClick();
}
@Override
public void packetIntercept(HMessage hMessage) {
extension.modifyMessage(hMessage);
sendManipulatedPacket(hMessage);
}
@Override
public void provideFlags(String[] flags) {
// no need
}
@Override
public void connectionStart(String host, int port, String hotelVersion, String clientIdentifier, HClient clientType, PacketInfoManager packetInfoManager) {
extension.getOnConnectionObservable().fireEvent(l -> l.onConnection(
host, port, hotelVersion,
clientIdentifier, clientType, packetInfoManager)
);
extension.onStartConnection();
}
@Override
public void connectionEnd() {
extension.onEndConnection();
}
@Override
public void init() {
extension.initExtension();
}
@Override
public void close() {
// no need in internal ext
}
@Override
public void packetToStringResponse(String string, String expression) {
// no need in java ext
}
@Override
public void stringToPacketResponse(HPacket packet) {
// no need in java ext
}
@Override
public ExtensionType extensionType() {
return ExtensionType.INTERNAL;
}
}

View File

@ -0,0 +1,78 @@
package gearth.extensions;
import gearth.services.extensionhandler.extensions.GEarthExtension;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducerObserver;
import javafx.application.Platform;
import javafx.stage.Stage;
public class InternalExtensionFormBuilder<T extends ExtensionForm> {
public T launch(Class<T> extensionClass, ExtensionProducerObserver observer) {
try {
ExtensionInfo extInfo = extensionClass.getAnnotation(ExtensionInfo.class);
T creator = extensionClass.newInstance();
Stage stage = new Stage();
T extensionForm = (T)(creator.launchForm(stage));
InternalExtension internalExtension = new InternalExtension() {
@Override
protected void initExtension() {
extensionForm.initExtension();
}
@Override
protected void onClick() {
extensionForm.onClick();
}
@Override
protected void onStartConnection() {
extensionForm.onStartConnection();
}
@Override
protected void onEndConnection() {
extensionForm.onEndConnection();
}
@Override
protected ExtensionInfo getInfoAnnotations() {
return extInfo;
}
@Override
protected boolean canLeave() {
return extensionForm.canLeave();
}
@Override
protected boolean canDelete() {
return extensionForm.canDelete();
}
};
extensionForm.extension = internalExtension;
extensionForm.primaryStage = stage;
GEarthExtension gEarthExtension = new InternalExtensionBuilder(internalExtension);
observer.onExtensionProduced(gEarthExtension);
Platform.setImplicitExit(false);
stage.setOnCloseRequest(event -> {
event.consume();
Platform.runLater(() -> {
stage.hide();
extensionForm.onHide();
});
});
return extensionForm;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -1,5 +1,8 @@
package gearth.extensions;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.connection.HClient;
public interface OnConnectionListener {
void onConnection(String host, int port, String hotelversion, String clientType, String harbleMessagesPath);
void onConnection(String host, int port, String hotelversion, String clientIdentifier, HClient clientType, PacketInfoManager packetInfoManager);
}

View File

@ -1,135 +0,0 @@
package gearth.extensions.extra.harble;
import gearth.extensions.Extension;
import gearth.extensions.IExtension;
import gearth.misc.harble_api.HarbleAPI;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.io.File;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Jonas on 10/11/2018.
*/
public class HashSupport {
private final Object lock = new Object();
private HarbleAPI harbleAPI = new HarbleAPI(""); //empty
private Map<String, List<Extension.MessageListener>> incomingMessageListeners = new HashMap<>();
private Map<String, List<Extension.MessageListener>> outgoingMessageListeners = new HashMap<>();
private IExtension extension;
public HashSupport(IExtension extension) {
this.extension = extension;
extension.onConnect((host, port, hotelversion, clientType, cachePath) -> {
// synchronized (lock) {
harbleAPI = new HarbleAPI(new File(cachePath));
// }
});
extension.intercept(HMessage.Direction.TOSERVER, message -> {
// synchronized (lock) {
HarbleAPI.HarbleMessage haMessage = harbleAPI.getHarbleMessageFromHeaderId(HMessage.Direction.TOSERVER, message.getPacket().headerId());
if (haMessage != null) {
List<Extension.MessageListener> listeners_hash = outgoingMessageListeners.get(haMessage.getHash());
List<Extension.MessageListener> listeners_name = outgoingMessageListeners.get(haMessage.getName());
if (listeners_hash != null) {
for (Extension.MessageListener listener : listeners_hash) {
listener.act(message);
message.getPacket().resetReadIndex();
}
}
if (listeners_name != null) {
for (Extension.MessageListener listener : listeners_name) {
listener.act(message);
message.getPacket().resetReadIndex();
}
}
}
// }
});
extension.intercept(HMessage.Direction.TOCLIENT, message -> {
// synchronized (lock) {
HarbleAPI.HarbleMessage haMessage = harbleAPI.getHarbleMessageFromHeaderId(HMessage.Direction.TOCLIENT, message.getPacket().headerId());
if (haMessage != null) {
List<Extension.MessageListener> listeners_hash = incomingMessageListeners.get(haMessage.getHash());
List<Extension.MessageListener> listeners_name = incomingMessageListeners.get(haMessage.getName());
if (listeners_hash != null) {
for (Extension.MessageListener listener : listeners_hash) {
listener.act(message);
message.getPacket().resetReadIndex();
}
}
if (listeners_name != null) {
for (Extension.MessageListener listener : listeners_name) {
listener.act(message);
message.getPacket().resetReadIndex();
}
}
}
// }
});
}
public void intercept(HMessage.Direction direction, String hashOrName, Extension.MessageListener messageListener) {
Map<String, List<Extension.MessageListener>> messageListeners =
(direction == HMessage.Direction.TOSERVER
? outgoingMessageListeners
: incomingMessageListeners);
messageListeners.computeIfAbsent(hashOrName, k -> new ArrayList<>());
messageListeners.get(hashOrName).add(messageListener);
}
private boolean send(HMessage.Direction direction, String hashOrName, Object... objects) {
int headerId;
HarbleAPI.HarbleMessage fromname = harbleAPI.getHarbleMessageFromName(direction, hashOrName);
if (fromname != null) {
headerId = fromname.getHeaderId();
}
else {
List<HarbleAPI.HarbleMessage> possibilities = harbleAPI.getHarbleMessagesFromHash(direction, hashOrName);
if (possibilities.size() == 0) return false;
headerId = possibilities.get(0).getHeaderId();
}
try {
HPacket packetToSend = new HPacket(headerId, objects);
return (direction == HMessage.Direction.TOCLIENT
? extension.sendToClient(packetToSend)
: extension.sendToServer(packetToSend));
}
catch (InvalidParameterException e) {
return false;
}
}
/**
*
* @return if no errors occurred (invalid hash/invalid parameters/connection error)
*/
public boolean sendToClient(String hashOrName, Object... objects) {
return send(HMessage.Direction.TOCLIENT, hashOrName, objects);
}
/**
*
* @return if no errors occurred (invalid hash/invalid parameters/connection error)
*/
public boolean sendToServer(String hashOrName, Object... objects) {
return send(HMessage.Direction.TOSERVER, hashOrName, objects);
}
public HarbleAPI getHarbleAPI() {
return harbleAPI;
}
}

View File

@ -1,8 +1,7 @@
package gearth.extensions.extra.harble;
package gearth.extensions.extra.tools;
import gearth.extensions.ExtensionInfo;
import gearth.extensions.IExtension;
import gearth.extensions.OnConnectionListener;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
@ -18,31 +17,33 @@ public class ChatConsole {
private volatile int chatid;
private volatile String name;
private volatile HashSupport hashSupport;
private volatile PacketInfoSupport packetInfoSupport;
private volatile String infoMessage;
private volatile boolean firstTime = true;
private volatile Observable<ChatInputListener> chatInputObservable = new Observable<>();
public ChatConsole(final HashSupport hashSupport, IExtension extension) {
this(hashSupport, extension, null);
public ChatConsole(final PacketInfoSupport packetInfoSupport, IExtension extension) {
this(packetInfoSupport, extension, null);
}
/**
* infomessage will be used as response for :info and for initialize
* @param hashSupport
* @param packetInfoSupport
* @param extension
* @param infoMessage
*/
public ChatConsole(final HashSupport hashSupport, IExtension extension, String infoMessage) {
this.hashSupport = hashSupport;
public ChatConsole(final PacketInfoSupport packetInfoSupport, IExtension extension, String infoMessage) {
this.packetInfoSupport = packetInfoSupport;
this.name = extension.getClass().getAnnotation(ExtensionInfo.class).Title();
chatid = (this.name.hashCode() % 300000000) + 300000000;
this.infoMessage = infoMessage;
final boolean[] doOncePerConnection = {false};
extension.onConnect((s, i, s1, ct, h1) -> doOncePerConnection[0] = true);
extension.onConnect((host, port, hotelversion, clientIdentifier, clientType, packetInfoManager) ->
doOncePerConnection[0] = true
);
extension.intercept(HMessage.Direction.TOSERVER, hMessage -> {
// if the first packet on init is not 4000, the extension was already running, so we open the chat instantly
@ -55,7 +56,7 @@ public class ChatConsole {
}
});
hashSupport.intercept(HMessage.Direction.TOCLIENT, "FriendListFragment", hMessage -> {
packetInfoSupport.intercept(HMessage.Direction.TOCLIENT, "FriendListFragment", hMessage -> {
if (doOncePerConnection[0]) {
doOncePerConnection[0] = false;
@ -71,7 +72,7 @@ public class ChatConsole {
}
});
hashSupport.intercept(HMessage.Direction.TOSERVER, "SendMsg", hMessage -> {
packetInfoSupport.intercept(HMessage.Direction.TOSERVER, "SendMsg", hMessage -> {
HPacket packet = hMessage.getPacket();
if (packet.readInteger() == chatid) {
hMessage.setBlocked(true);
@ -87,7 +88,7 @@ public class ChatConsole {
}
private void createChat() {
hashSupport.sendToClient("FriendListUpdate",
packetInfoSupport.sendToClient("FriendListUpdate",
0, 1, 0, chatid, " [G-Earth] - " + name,
1, true, false, "ha-1015-64.hd-209-30.cc-260-64.ch-235-64.sh-305-64.lg-285-64",
0, "", 0, true, false, true, ""
@ -100,10 +101,10 @@ public class ChatConsole {
public void writeOutput(String string, boolean asInvite) {
if (asInvite) {
hashSupport.sendToClient("RoomInvite", chatid, string);
packetInfoSupport.sendToClient("RoomInvite", chatid, string);
}
else {
hashSupport.sendToClient("NewConsole", chatid, string, 0, "");
packetInfoSupport.sendToClient("NewConsole", chatid, string, 0, "");
}
}

View File

@ -1,4 +1,4 @@
package gearth.extensions.extra.harble;
package gearth.extensions.extra.tools;
public interface ChatInputListener {
void inputEntered(String input);

View File

@ -0,0 +1,116 @@
package gearth.extensions.extra.tools;
import gearth.extensions.Extension;
import gearth.extensions.IExtension;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.security.InvalidParameterException;
import java.util.*;
/**
* Created by Jonas on 10/11/2018.
*/
public class PacketInfoSupport {
private final Object lock = new Object();
private PacketInfoManager packetInfoManager = new PacketInfoManager(new ArrayList<>()); //empty
private Map<String, List<Extension.MessageListener>> incomingMessageListeners = new HashMap<>();
private Map<String, List<Extension.MessageListener>> outgoingMessageListeners = new HashMap<>();
private IExtension extension;
public PacketInfoSupport(IExtension extension) {
this.extension = extension;
extension.onConnect((host, port, hotelversion, clientIdentifier, clientType, packetInfoManager) ->
this.packetInfoManager = packetInfoManager
);
extension.intercept(HMessage.Direction.TOSERVER, message -> onReceivePacket(HMessage.Direction.TOSERVER, message));
extension.intercept(HMessage.Direction.TOCLIENT, message -> onReceivePacket(HMessage.Direction.TOCLIENT, message));
}
private void onReceivePacket(HMessage.Direction direction, HMessage message) {
Set<Extension.MessageListener> callbacks = new HashSet<>();
Map<String, List<Extension.MessageListener>> messageListeners =
(direction == HMessage.Direction.TOSERVER
? outgoingMessageListeners
: incomingMessageListeners);
List<PacketInfo> packetInfos = packetInfoManager.getAllPacketInfoFromHeaderId(HMessage.Direction.TOCLIENT, message.getPacket().headerId());
for (PacketInfo packetInfo : packetInfos) {
List<Extension.MessageListener> listeners_hash = messageListeners.get(packetInfo.getHash());
List<Extension.MessageListener> listeners_name = messageListeners.get(packetInfo.getName());
if (listeners_hash != null) {
callbacks.addAll(listeners_hash);
}
if (listeners_name != null) {
callbacks.addAll(listeners_name);
}
}
for (Extension.MessageListener listener : callbacks) {
listener.act(message);
message.getPacket().resetReadIndex();
}
}
public void intercept(HMessage.Direction direction, String hashOrName, Extension.MessageListener messageListener) {
Map<String, List<Extension.MessageListener>> messageListeners =
(direction == HMessage.Direction.TOSERVER
? outgoingMessageListeners
: incomingMessageListeners);
messageListeners.computeIfAbsent(hashOrName, k -> new ArrayList<>());
messageListeners.get(hashOrName).add(messageListener);
}
private boolean send(HMessage.Direction direction, String hashOrName, Object... objects) {
int headerId;
PacketInfo fromname = packetInfoManager.getPacketInfoFromName(direction, hashOrName);
if (fromname != null) {
headerId = fromname.getHeaderId();
}
else {
PacketInfo fromHash = packetInfoManager.getPacketInfoFromHash(direction, hashOrName);
if (fromHash == null) return false;
headerId = fromHash.getHeaderId();
}
try {
HPacket packetToSend = new HPacket(headerId, objects);
return (direction == HMessage.Direction.TOCLIENT
? extension.sendToClient(packetToSend)
: extension.sendToServer(packetToSend));
}
catch (InvalidParameterException e) {
return false;
}
}
/**
*
* @return if no errors occurred (invalid hash/invalid parameters/connection error)
*/
public boolean sendToClient(String hashOrName, Object... objects) {
return send(HMessage.Direction.TOCLIENT, hashOrName, objects);
}
/**
*
* @return if no errors occurred (invalid hash/invalid parameters/connection error)
*/
public boolean sendToServer(String hashOrName, Object... objects) {
return send(HMessage.Direction.TOSERVER, hashOrName, objects);
}
public PacketInfoManager getPacketInfoManager() {
return packetInfoManager;
}
}

View File

@ -1,224 +0,0 @@
package gearth.misc.harble_api;
import gearth.misc.Cacher;
import gearth.protocol.HMessage;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Jonas on 10/11/2018.
*/
public class HarbleAPI {
public class HarbleMessage {
private HMessage.Direction destination;
private int headerId;
private String hash;
private String name;
private String structure;
//name can be NULL
public HarbleMessage(HMessage.Direction destination, int headerId, String hash, String name, String structure) {
this.destination = destination;
this.headerId = headerId;
this.hash = hash;
this.name = (name == null || name.equals("null") ? null : name);
this.structure = (structure == null || structure.equals("null") ? null : structure);
}
public String getName() {
return name;
}
public int getHeaderId() {
return headerId;
}
public HMessage.Direction getDestination() {
return destination;
}
public String getHash() {
return hash;
}
public String getStructure() {
return structure;
}
public String toString() {
String s = (headerId + ": " + "[" + hash + "][" + name + "][" + structure + "]");
return s;
}
}
private Map<Integer, HarbleMessage> headerIdToMessage_incoming = new HashMap<>();
private Map<Integer, HarbleMessage> headerIdToMessage_outgoing = new HashMap<>();
private Map<String, List<HarbleMessage>> hashToMessage_incoming = new HashMap<>();
private Map<String, List<HarbleMessage>> hashToMessage_outgoing = new HashMap<>();
private Map<String, HarbleMessage> nameToMessage_incoming = new HashMap<>();
private Map<String, HarbleMessage> nameToMessage_outgoing = new HashMap<>();
private boolean success = false;
private String fullPath = null;
/**
* cache file must be generated first within G-Earth, inb4 20 extensions requesting it at the same time
*
* @param hotelversion
*/
public static HarbleAPI get(String hotelversion) {
HarbleAPI wannabe = new HarbleAPI(hotelversion);
if (!wannabe.success) {
return null;
}
return wannabe;
}
public HarbleAPI(String hotelversion) {
String possibleCachedMessagesPath = HarbleAPIFetcher.CACHE_PREFIX + hotelversion;
if (Cacher.cacheFileExists(possibleCachedMessagesPath)) {
JSONObject object = Cacher.getCacheContents(possibleCachedMessagesPath);
success = true;
fullPath = Cacher.getCacheDir() + File.separator + possibleCachedMessagesPath;
parse(object);
}
}
public HarbleAPI(File f) {
if (f.exists() && !f.isDirectory()) {
try {
String contents = String.join("\n", Files.readAllLines(f.toPath()));
JSONObject object = new JSONObject(contents);
success = true;
fullPath = f.getAbsolutePath();
parse(object);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void addMessage(HMessage.Direction direction, JSONObject object) {
String name;
String hash;
try { name = object.getString("Name"); }
catch (Exception e) { name = null; }
try { hash = object.getString("Hash"); }
catch (Exception e) { hash = null; }
int headerId = object.getInt("Id");
String structure;
try {
structure = object.getString("Structure");
} catch (Exception e) {
structure = null;
}
HarbleMessage message = new HarbleMessage(direction, headerId, hash, name, structure);
Map<Integer, HarbleMessage> headerIdToMessage =
message.getDestination() == HMessage.Direction.TOCLIENT
? headerIdToMessage_incoming :
headerIdToMessage_outgoing;
Map<String, List<HarbleMessage>> hashToMessage =
message.getDestination() == HMessage.Direction.TOCLIENT
? hashToMessage_incoming
: hashToMessage_outgoing;
Map<String, HarbleMessage> nameToMessag =
message.getDestination() == HMessage.Direction.TOCLIENT
? nameToMessage_incoming
: nameToMessage_outgoing;
headerIdToMessage.put(message.getHeaderId(), message);
hashToMessage.computeIfAbsent(message.getHash(), k -> new ArrayList<>());
hashToMessage.get(message.getHash()).add(message);
if (message.getName() != null && !message.getName().equals("null")) {
nameToMessag.put(message.getName(), message);
}
}
private void parse(JSONObject object) {
try {
JSONArray incoming = object.getJSONArray("Incoming");
JSONArray outgoing = object.getJSONArray("Outgoing");
if (incoming != null && outgoing != null) {
for (int i = 0; i < incoming.length(); i++) {
try {
JSONObject message = incoming.getJSONObject(i);
addMessage(HMessage.Direction.TOCLIENT, message);
}
catch (Exception e){
e.printStackTrace();
}
}
for (int i = 0; i < outgoing.length(); i++) {
try{
JSONObject message = outgoing.getJSONObject(i);
addMessage(HMessage.Direction.TOSERVER, message);
}
catch (Exception e){
e.printStackTrace();
}
}
}
} catch (Exception e) {
success = false;
}
}
public HarbleMessage getHarbleMessageFromHeaderId(HMessage.Direction direction, int headerId) {
Map<Integer, HarbleMessage> headerIdToMessage =
(direction == HMessage.Direction.TOSERVER
? headerIdToMessage_outgoing
: headerIdToMessage_incoming);
return headerIdToMessage.get(headerId);
}
public List<HarbleMessage> getHarbleMessagesFromHash(HMessage.Direction direction, String hash) {
Map<String, List<HarbleMessage>> hashToMessage =
(direction == HMessage.Direction.TOSERVER
? hashToMessage_outgoing
: hashToMessage_incoming);
List<HarbleMessage> result = hashToMessage.get(hash);
return result == null ? new ArrayList<>() : result;
}
public HarbleMessage getHarbleMessageFromName(HMessage.Direction direction, String name) {
Map<String, HarbleMessage> nameToMessage =
(direction == HMessage.Direction.TOSERVER
? nameToMessage_outgoing
: nameToMessage_incoming);
return nameToMessage.get(name);
}
public String getPath() {
if (success) {
return fullPath;
}
return "null";
}
}

View File

@ -1,80 +0,0 @@
package gearth.misc.harble_api;
import gearth.Main;
import gearth.misc.Cacher;
import gearth.protocol.HMessage;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
/**
* Created by Jonas on 10/11/2018.
*/
/**
* Ok the usage of this class is pretty shitty so I'm just gonna add some documentation here
*
* What this class does is fetching the revision (if needed) from the API, this is the only class with communication with the
* actual API. Then the result (if any) gets cached.
*
* The method "fetch(xxx);" needs to be called exactly once at the moment a new connection has been made.
*
* However, at that same moment the Extension class needs to send the "startConnection" signal to the extensions, and we want to make sure
* that the cached revision is already available at the moment the extensions get initialized with a new connection. That's why the
* fetch() method here only gets called by the extension class as that's the only way to ensure this method gets called BEFORE the extensions
* start. (bc im lazy and dont wanna rewrite code too)
*
*
* the "HARBLEAPI" object contains the latest fetched object and is ensured to be up-to-date with the current connection
*/
public class HarbleAPIFetcher {
public static final String CACHE_PREFIX = "HARBLE_API-";
public static final String HARBLE_API_URL = "https://api.harble.net/messages/$hotelversion$.json";
//latest fetched
public static HarbleAPI HARBLEAPI = null;
public synchronized static void fetch(String hotelversion, String clientType) {
// if unity
if (clientType.toLowerCase().contains("unity")) {
try {
HARBLEAPI = new HarbleAPI(
new File(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI())
.getParentFile(), "messages.json"
)
);
} catch (URISyntaxException e) {
HARBLEAPI = null;
}
return;
}
String cacheName = CACHE_PREFIX + hotelversion;
if (Cacher.cacheFileExists(cacheName)) {
HARBLEAPI = new HarbleAPI(hotelversion);
}
else {
Connection connection = Jsoup.connect(HARBLE_API_URL.replace("$hotelversion$", hotelversion)).ignoreContentType(true);
try {
connection.timeout(3000);
Connection.Response response = connection.execute();
if (response.statusCode() == 200) {
String messagesBodyJson = response.body();
Cacher.updateCache(messagesBodyJson, cacheName);
HARBLEAPI = new HarbleAPI(hotelversion);
}
else {
HARBLEAPI = null;
}
} catch (IOException e) {
HARBLEAPI = null;
}
}
}
}

View File

@ -1,10 +1,11 @@
package gearth.protocol;
import gearth.misc.listenerpattern.Observable;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.connection.HClient;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import gearth.protocol.connection.proxy.unity.UnityProxyProvider;
@ -137,16 +138,28 @@ public class HConnection {
public boolean sendToClientAsync(HPacket message) {
if (proxy == null) {
return false;
if (proxy == null) return false;
if (!message.isPacketComplete()) {
PacketInfoManager packetInfoManager = getPacketInfoManager();
message.completePacket(HMessage.Direction.TOCLIENT, packetInfoManager);
if (!message.isPacketComplete()) return false;
}
proxy.getAsyncPacketSender().sendToClientAsync(message);
return true;
}
public boolean sendToServerAsync(HPacket message) {
if (proxy == null) {
return false;
if (proxy == null) return false;
if (!message.isPacketComplete()) {
PacketInfoManager packetInfoManager = getPacketInfoManager();
message.completePacket(HMessage.Direction.TOSERVER, packetInfoManager);
if (!message.isPacketComplete()) return false;
}
proxy.getAsyncPacketSender().sendToServerAsync(message);
return true;
}
@ -172,11 +185,25 @@ public class HConnection {
return proxy.getHotelVersion();
}
public String getClientType() {
public String getClientIdentifier() {
if (proxy == null) {
return "";
}
return proxy.getClientType();
return proxy.getClientIdentifier();
}
public HClient getClientType() {
if (proxy == null) {
return null;
}
return proxy.gethClient();
}
public PacketInfoManager getPacketInfoManager() {
if (proxy == null) {
return null;
}
return proxy.getPacketInfoManager();
}
public boolean isRawIpMode() {

View File

@ -1,17 +1,17 @@
package gearth.protocol;
import gearth.misc.StringifyAble;
import gearth.misc.harble_api.HarbleAPI;
import gearth.misc.harble_api.HarbleAPIFetcher;
import gearth.misc.packetrepresentation.InvalidPacketException;
import gearth.misc.packetrepresentation.PacketStringUtils;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.services.packetrepresentation.InvalidPacketException;
import gearth.services.packetrepresentation.PacketStringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Optional;
public class HPacket implements StringifyAble {
@ -19,6 +19,9 @@ public class HPacket implements StringifyAble {
private byte[] packetInBytes;
private int readIndex = 6;
// if identifier != null, this is a placeholder name for the type of packet, headerId will be "-1"
private String identifier = null;
public HPacket(byte[] packet) {
packetInBytes = packet.clone();
}
@ -28,11 +31,11 @@ public class HPacket implements StringifyAble {
}
public HPacket(String packet) {
try {
packetInBytes = PacketStringUtils.fromString(packet).packetInBytes;
HPacket packetFromString = PacketStringUtils.fromString(packet);
packetInBytes = packetFromString.packetInBytes;
identifier = packetFromString.identifier;
} catch (InvalidPacketException e) {
packetInBytes = new byte[0];
// will be corrupted
// e.printStackTrace();
}
}
public HPacket(int header) {
@ -40,6 +43,7 @@ public class HPacket implements StringifyAble {
replaceShort(4, (short)header);
isEdited = false;
}
public HPacket(int header, byte[] bytes) {
this(header);
appendBytes(bytes);
@ -53,14 +57,19 @@ public class HPacket implements StringifyAble {
*/
public HPacket(int header, Object... objects) throws InvalidParameterException {
this(header);
for (int i = 0; i < objects.length; i++) {
Object o = objects[i];
appendObject(o);
}
appendObjects(objects);
isEdited = false;
}
public HPacket(String identifier, Object... objects) throws InvalidParameterException {
packetInBytes = new byte[]{0,0,0,2,-1,-1};
this.identifier = identifier;
appendObjects(objects);
isEdited = false;
}
public String toString() {
return PacketStringUtils.toString(packetInBytes);
}
@ -75,6 +84,46 @@ public class HPacket implements StringifyAble {
return 2;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
public void completePacket(HMessage.Direction direction, PacketInfoManager packetInfoManager) {
if (isCorrupted() || identifier == null) return;
PacketInfo packetInfo = packetInfoManager.getPacketInfoFromName(direction, identifier);
if (packetInfo == null) {
packetInfo = packetInfoManager.getPacketInfoFromHash(direction, identifier);
if (packetInfo == null) return;
}
boolean wasEdited = isEdited;
replaceShort(4, (short)(packetInfo.getHeaderId()));
identifier = null;
isEdited = wasEdited;
}
public boolean canComplete(HMessage.Direction direction, PacketInfoManager packetInfoManager) {
if (isCorrupted() || identifier == null) return false;
PacketInfo packetInfo = packetInfoManager.getPacketInfoFromName(direction, identifier);
if (packetInfo == null) {
packetInfo = packetInfoManager.getPacketInfoFromHash(direction, identifier);
return packetInfo != null;
}
return true;
}
public boolean isPacketComplete() {
return identifier == null;
}
public byte[] toBytes() {
return packetInBytes;
}
@ -532,6 +581,14 @@ public class HPacket implements StringifyAble {
return appendLongString(s, StandardCharsets.ISO_8859_1);
}
public HPacket appendObjects(Object... objects) {
for (Object object : objects) {
appendObject(object);
}
return this;
}
public HPacket appendObject(Object o) throws InvalidParameterException {
isEdited = true;
@ -580,45 +637,52 @@ public class HPacket implements StringifyAble {
isEdited = edited;
}
private String getHarbleStructure(HMessage.Direction direction) {
HarbleAPI.HarbleMessage msg;
if (HarbleAPIFetcher.HARBLEAPI != null &&
((msg = HarbleAPIFetcher.HARBLEAPI.getHarbleMessageFromHeaderId(direction, headerId())) != null)) {
if (msg.getStructure() != null && structureEquals(msg.getStructure())) {
return msg.getStructure();
}
}
private PacketInfo getPacketInfo(HMessage.Direction direction, PacketInfoManager packetInfoManager) {
if (packetInfoManager == null) return null;
return null;
// prefer packetinfo with structure information (not available in at time of writing)
Optional<PacketInfo> packetInfoMaybe = packetInfoManager.getAllPacketInfoFromHeaderId(direction, headerId())
.stream().filter(packetInfo -> packetInfo.getStructure() != null).findFirst();
return packetInfoMaybe.orElseGet(() -> packetInfoManager.getPacketInfoFromHeaderId(direction, headerId()));
}
public String toExpression(HMessage.Direction direction) {
public String toExpression(HMessage.Direction direction, PacketInfoManager packetInfoManager, boolean removeShuffle) {
if (isCorrupted()) return "";
String structure = getHarbleStructure(direction);
if (structure != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure);
PacketInfo packetInfo = getPacketInfo(direction, packetInfoManager);
if (packetInfo != null && packetInfo.getStructure() != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, packetInfo.getStructure(), removeShuffle ? packetInfo : null);
}
return PacketStringUtils.predictedExpression(this);
return PacketStringUtils.predictedExpression(this, removeShuffle ? packetInfo : null);
}
/**
* returns "" if not found or not sure enough
*/
public String toExpression() {
public String toExpression(PacketInfoManager packetInfoManager, boolean removeShuffle) {
if (isCorrupted()) return "";
String structure1 = getHarbleStructure(HMessage.Direction.TOCLIENT);
String structure2 = getHarbleStructure(HMessage.Direction.TOSERVER);
if (structure1 != null && structure2 == null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure1);
PacketInfo maybe1 = getPacketInfo(HMessage.Direction.TOCLIENT, packetInfoManager);
PacketInfo maybe2 = getPacketInfo(HMessage.Direction.TOSERVER, packetInfoManager);
PacketInfo packetInfo = null;
if (maybe1 != null && maybe2 == null) {
packetInfo = maybe1;
}
else if (structure1 == null && structure2 != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure2);
else if (maybe1 == null && maybe2 != null) {
packetInfo = maybe2;
}
return PacketStringUtils.predictedExpression(this);
if (packetInfo != null && packetInfo.getStructure() != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, packetInfo.getStructure(), removeShuffle ? packetInfo : null);
}
return PacketStringUtils.predictedExpression(this, removeShuffle ? packetInfo : null);
}
public String toExpression() {
if (isCorrupted()) return "";
return PacketStringUtils.predictedExpression(this, null);
}
@Override

View File

@ -1,5 +1,6 @@
package gearth.protocol.connection;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.packethandler.PacketHandler;
import java.net.ServerSocket;
@ -21,7 +22,9 @@ public class HProxy {
private volatile PacketHandler outHandler = null; //connection with server (only initialized when verified habbo connection)
private volatile String hotelVersion = "";
private volatile String clientType = "";
private volatile String clientIdentifier = "";
private volatile PacketInfoManager packetInfoManager = null;
private volatile AsyncPacketSender asyncPacketSender = null;
public HProxy(HClient hClient, String input_domain, String actual_domain, int actual_port, int intercept_port, String intercept_host) {
@ -37,16 +40,17 @@ public class HProxy {
this.proxy_server = socket;
}
public void verifyProxy(PacketHandler incomingHandler, PacketHandler outgoingHandler, String hotelVersion, String clientType) {
public void verifyProxy(PacketHandler incomingHandler, PacketHandler outgoingHandler, String hotelVersion, String clientIdentifier) {
this.inHandler = incomingHandler;
this.outHandler = outgoingHandler;
this.hotelVersion = hotelVersion;
this.clientType = clientType;
this.clientIdentifier = clientIdentifier;
this.packetInfoManager = PacketInfoManager.fromHotelVersion(hotelVersion, hClient);
this.asyncPacketSender = new AsyncPacketSender(this);
}
public String getClientType() {
return clientType;
public String getClientIdentifier() {
return clientIdentifier;
}
public int getActual_port() {
@ -92,4 +96,8 @@ public class HProxy {
public HClient gethClient() {
return hClient;
}
public PacketInfoManager getPacketInfoManager() {
return packetInfoManager;
}
}

View File

@ -51,9 +51,9 @@ public abstract class FlashProxyProvider implements ProxyProvider {
Semaphore abort = new Semaphore(0);
outgoingHandler.addOnDatastreamConfirmedListener((hotelVersion, clientType) -> {
outgoingHandler.addOnDatastreamConfirmedListener((hotelVersion, clientIdentifier) -> {
incomingHandler.setAsDataStream();
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion, clientType);
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion, clientIdentifier);
proxySetter.setProxy(proxy);
datastream[0] = true;
abortSemaphore = abort;

View File

@ -59,12 +59,12 @@ public class UnityCommunicator {
if (maybe.getBytesLength() > 6 && maybe.headerId() == 4000) {
hProxy = new HProxy(HClient.UNITY, "", "", -1, -1, "");
String ignore = maybe.readString();
String clientType = maybe.readString();
String clientIdentifier = maybe.readString();
hProxy.verifyProxy(
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOCLIENT),
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOSERVER),
revision,
clientType
clientIdentifier
);
proxySetter.setProxy(hProxy);
stateSetter.setState(HState.CONNECTED);

View File

@ -15,7 +15,7 @@ import java.net.URISyntaxException;
import java.util.*;
/**
* Created by Jeunez on 27/06/2018.
* Created by Jonas on 27/06/2018.
*/
public class WindowsHabboClient extends HabboClient {

View File

@ -2,6 +2,6 @@ package gearth.protocol.packethandler.flash;
public interface OnDatastreamConfirmedListener {
void confirm(String hotelVersion, String clientType);
void confirm(String hotelVersion, String clientIdentifier);
}

View File

@ -26,9 +26,9 @@ public class OutgoingFlashPacketHandler extends FlashPacketHandler {
HPacket hpacket = new HPacket(buffer);
isDataStream = (hpacket.getBytesLength() > 6 && hpacket.length() < 100);
if (isDataStream) {
String version = hpacket.readString();
String clientType = hpacket.readString();
datastreamConfirmedObservable.fireEvent(l -> l.confirm(version, clientType));
String hotelVersion = hpacket.readString();
String clientIdentifier = hpacket.readString();
datastreamConfirmedObservable.fireEvent(l -> l.confirm(hotelVersion, clientIdentifier));
}
}
}

View File

@ -1,7 +1,6 @@
package gearth.services.extensionhandler;
import gearth.Main;
import gearth.misc.harble_api.HarbleAPIFetcher;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
@ -12,6 +11,7 @@ import gearth.services.extensionhandler.extensions.GEarthExtension;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducerFactory;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducerObserver;
import gearth.services.packet_info.PacketInfoManager;
import javafx.util.Pair;
import java.io.IOException;
@ -45,18 +45,17 @@ public class ExtensionHandler {
}
private void initialize() {
hConnection.getStateObservable().addListener((oldState, newState) -> {
if (newState == HState.CONNECTED) {
HarbleAPIFetcher.fetch(hConnection.getHotelVersion(), hConnection.getClientType());
synchronized (gEarthExtensions) {
for (GEarthExtension extension : gEarthExtensions) {
extension.connectionStart(
hConnection.getDomain(),
hConnection.getServerPort(),
hConnection.getHotelVersion(),
hConnection.getClientIdentifier(),
hConnection.getClientType(),
HarbleAPIFetcher.HARBLEAPI == null ? "null" : HarbleAPIFetcher.HARBLEAPI.getPath()
hConnection.getPacketInfoManager()
);
}
}
@ -71,7 +70,7 @@ public class ExtensionHandler {
});
extensionProducers = ExtensionProducerFactory.getAll();
extensionProducers.forEach(this::initializeExtensionProducer);
extensionProducers.forEach(extensionProducer -> extensionProducer.startProducing(createExtensionProducerObserver()));
}
@ -174,8 +173,8 @@ public class ExtensionHandler {
private void initializeExtensionProducer(ExtensionProducer producer) {
producer.startProducing(new ExtensionProducerObserver() {
private ExtensionProducerObserver createExtensionProducerObserver() {
return new ExtensionProducerObserver() {
@Override
public void onExtensionProduced(GEarthExtension extension) {
synchronized (gEarthExtensions) {
@ -221,7 +220,7 @@ public class ExtensionHandler {
try {
s = packet.toString();
if (packet.length() < 3000) {
expression = packet.toExpression();
expression = packet.toExpression(hConnection.getPacketInfoManager(), true);
}
}
finally {
@ -232,6 +231,13 @@ public class ExtensionHandler {
@Override
protected void stringToPacketRequest(String string) {
HPacket packet = new HPacket(string);
PacketInfoManager packetInfoManager = hConnection.getPacketInfoManager();
if (packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && !packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOCLIENT, packetInfoManager);
}
else if (!packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOSERVER, packetInfoManager);
}
extension.stringToPacketResponse(packet);
}
};
@ -244,8 +250,9 @@ public class ExtensionHandler {
hConnection.getDomain(),
hConnection.getServerPort(),
hConnection.getHotelVersion(),
hConnection.getClientIdentifier(),
hConnection.getClientType(),
HarbleAPIFetcher.HARBLEAPI == null ? "null" : HarbleAPIFetcher.HARBLEAPI.getPath()
hConnection.getPacketInfoManager()
);
}
@ -254,7 +261,7 @@ public class ExtensionHandler {
observable.fireEvent(l -> l.onExtensionConnect(extension));
}
});
};
}
public List<ExtensionProducer> getExtensionProducers() {
@ -264,5 +271,10 @@ public class ExtensionHandler {
return observable;
}
public void addExtensionProducer(ExtensionProducer producer) {
producer.startProducing(createExtensionProducerObserver());
extensionProducers.add(producer);
}
}

View File

@ -0,0 +1,6 @@
package gearth.services.extensionhandler.extensions;
public enum ExtensionType {
INTERNAL,
EXTERNAL
}

View File

@ -2,14 +2,14 @@ package gearth.services.extensionhandler.extensions;
import gearth.misc.listenerpattern.Observable;
import gearth.misc.listenerpattern.SynchronizedObservable;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.HClient;
import gearth.services.extensionhandler.extensions.listeners.OmRemoveClickListener;
import gearth.services.extensionhandler.extensions.listeners.OnClickListener;
import gearth.services.extensionhandler.extensions.listeners.OnDeleteListener;
import java.util.function.Consumer;
public abstract class GEarthExtension {
@ -38,7 +38,7 @@ public abstract class GEarthExtension {
public abstract void doubleclick();
public abstract void packetIntercept(HMessage hMessage);
public abstract void provideFlags(String[] flags);
public abstract void connectionStart(String host, int port, String hotelVersion, String clientType, String harbleMessagesPath);
public abstract void connectionStart(String host, int port, String hotelVersion, String clientIdentifier, HClient clientType, PacketInfoManager packetInfoManager);
public abstract void connectionEnd();
public abstract void init();
public abstract void close();
@ -51,7 +51,6 @@ public abstract class GEarthExtension {
// ----------------- listen to the extension ---------------------
protected final Observable<ExtensionListener> extensionObservable = new SynchronizedObservable<>();
public Observable<ExtensionListener> getExtensionObservable() {
return extensionObservable;
@ -121,4 +120,7 @@ public abstract class GEarthExtension {
}
// ----------------------------------------------------------------------------------------
public abstract ExtensionType extensionType();
}

View File

@ -3,6 +3,7 @@ package gearth.services.extensionhandler.extensions.extensionproducers;
import gearth.services.extensionhandler.extensions.implementations.network.NetworkExtensionsProducer;
import gearth.services.extensionhandler.extensions.implementations.simple.SimpleExtensionProducer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -10,10 +11,11 @@ public class ExtensionProducerFactory {
// returns one of every ExtensionProducer class we have created, to support all types of extensions
public static List<ExtensionProducer> getAll() {
return Arrays.asList(
new NetworkExtensionsProducer(),
new SimpleExtensionProducer()
);
List<ExtensionProducer> all = new ArrayList<>();
all.add(new NetworkExtensionsProducer());
all.add(new SimpleExtensionProducer());
return all;
}

View File

@ -1,6 +1,9 @@
package gearth.services.extensionhandler.extensions.implementations.network;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.connection.HClient;
import gearth.services.extensionhandler.extensions.ExtensionType;
import gearth.services.extensionhandler.extensions.GEarthExtension;
import gearth.protocol.HPacket;
@ -190,15 +193,16 @@ public class NetworkExtension extends GEarthExtension {
}
@Override
public void connectionStart(String host, int port, String hotelVersion, String clientType, String harbleMessagesPath) {
sendMessage(
new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.CONNECTIONSTART)
.appendString(host)
.appendInt(port)
.appendString(hotelVersion)
.appendString(harbleMessagesPath)
.appendString(clientType)
);
public void connectionStart(String host, int port, String hotelVersion, String clientIdentifier, HClient clientType, PacketInfoManager packetInfoManager) {
HPacket connectionStartPacket = new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.CONNECTIONSTART)
.appendString(host)
.appendInt(port)
.appendString(hotelVersion)
.appendString(clientIdentifier)
.appendString(clientType.name());
packetInfoManager.appendToPacket(connectionStartPacket);
sendMessage(connectionStartPacket);
}
@Override
@ -236,4 +240,9 @@ public class NetworkExtension extends GEarthExtension {
packet.appendLongString(packetFromString.stringify());
sendMessage(packet);
}
@Override
public ExtensionType extensionType() {
return ExtensionType.EXTERNAL;
}
}

View File

@ -1,7 +1,10 @@
package gearth.services.extensionhandler.extensions.implementations.simple;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.HClient;
import gearth.services.extensionhandler.extensions.ExtensionType;
import gearth.services.extensionhandler.extensions.GEarthExtension;
public class ExampleExtension extends GEarthExtension {
@ -83,7 +86,7 @@ public class ExampleExtension extends GEarthExtension {
}
@Override
public void connectionStart(String host, int port, String hotelVersion, String clientType, String harbleMessagesPath) {
public void connectionStart(String host, int port, String hotelVersion, String clientIdentifier, HClient clientType, PacketInfoManager packetInfoManager) {
// a new habbo client has connected
System.out.println("Connected to " + host);
}
@ -120,4 +123,9 @@ public class ExampleExtension extends GEarthExtension {
public void stringToPacketResponse(HPacket packet) {
}
@Override
public ExtensionType extensionType() {
return ExtensionType.INTERNAL;
}
}

View File

@ -1,7 +1,10 @@
package gearth.services.extensionhandler.extensions.implementations.simple;
import gearth.extensions.InternalExtensionFormBuilder;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducerObserver;
import gearth.services.internal_extensions.blockreplacepackets.BlockAndReplacePackets;
import gearth.services.internal_extensions.packetinfoexplorer.PacketInfoExplorer;
public class SimpleExtensionProducer implements ExtensionProducer {
@ -9,7 +12,12 @@ public class SimpleExtensionProducer implements ExtensionProducer {
public void startProducing(ExtensionProducerObserver observer) {
// uncomment the next line if you want to see an embedded example extension in G-Earth
// observer.onExtensionConnect(new ExampleExtension());
// observer.onExtensionProduced(new ExampleExtension());
new InternalExtensionFormBuilder<BlockAndReplacePackets>()
.launch(BlockAndReplacePackets.class, observer);
new InternalExtensionFormBuilder<PacketInfoExplorer>()
.launch(PacketInfoExplorer.class, observer);
}
}

View File

@ -10,7 +10,7 @@ import java.util.List;
public class GPythonVersionUtils {
private static final String MIN_GPYTHON_VERSION = "0.1.3";
private static final String MIN_GPYTHON_VERSION = "0.1.4";
private static final String MIN_PYTHON_VERSION = "3.2";
// returns null if python not installed

View File

@ -1,10 +1,14 @@
package extensions.blockreplacepackets;
package gearth.services.internal_extensions.blockreplacepackets;
import extensions.blockreplacepackets.rules.BlockReplaceRule;
import extensions.blockreplacepackets.rules.RuleFactory;
import gearth.extensions.Extension;
import gearth.Main;
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.internal_extensions.blockreplacepackets.rules.BlockReplaceRule;
import gearth.services.internal_extensions.blockreplacepackets.rules.RuleFactory;
import gearth.ui.GEarthController;
import javafx.application.Platform;
import javafx.event.ActionEvent;
@ -15,11 +19,10 @@ import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
import java.util.ArrayList;
import java.util.List;
@ -32,7 +35,7 @@ import java.util.List;
@ExtensionInfo(
Title = "G-Manipulate",
Description = "Block &/ replace packets",
Version = "0.1",
Version = "0.2",
Author = "sirjonasxx"
)
public class BlockAndReplacePackets extends ExtensionForm {
@ -48,9 +51,11 @@ public class BlockAndReplacePackets extends ExtensionForm {
List<BlockReplaceRule> rules = new ArrayList<>();
public static void main(String[] args) {
runExtensionForm(args, BlockAndReplacePackets.class);
}
private PacketInfoManager packetInfoManager = PacketInfoManager.EMPTY;
// public static void main(String[] args) {
// runExtensionForm(args, BlockAndReplacePackets.class);
// }
//initialize javaFX elements
public void initialize() {
@ -70,6 +75,26 @@ public class BlockAndReplacePackets extends ExtensionForm {
}
private String getVal() {
String val = txt_value.getText();
String type = cmb_type.getSelectionModel().getSelectedItem();
String side = cmb_side.getSelectionModel().getSelectedItem();
if (type.endsWith("packet")) {
HMessage.Direction dir = side.equals("Outgoing") ? HMessage.Direction.TOSERVER : HMessage.Direction.TOCLIENT;
PacketInfo fromName = packetInfoManager.getPacketInfoFromName(dir, val);
PacketInfo fromHash = packetInfoManager.getPacketInfoFromHash(dir, val);
if (fromName != null) {
val = fromName.getHeaderId() +"";
}
else if (fromHash != null) {
val = fromHash.getHeaderId() +"";
}
}
return val;
}
private void refreshOptions() {
txt_replacement.setDisable(cmb_type.getSelectionModel().getSelectedItem().startsWith("Block"));
if (cmb_side.getItems().size() == 2 && !cmb_type.getSelectionModel().getSelectedItem().endsWith("packet")) {
@ -83,7 +108,7 @@ public class BlockAndReplacePackets extends ExtensionForm {
}
boolean isValid = false;
String val = txt_value.getText();
String val = getVal();
String repl = txt_replacement.getText();
String type = cmb_type.getSelectionModel().getSelectedItem();
String side = cmb_side.getSelectionModel().getSelectedItem();
@ -154,7 +179,7 @@ public class BlockAndReplacePackets extends ExtensionForm {
if (val.equals("")) {
if (spl[1].equals("packet")) {
txt_value.setPromptText("Enter the headerID");
txt_value.setPromptText("Enter headerID/name");
}
else if (spl[1].equals("integer")) {
txt_value.setPromptText("Enter an integer");
@ -177,7 +202,7 @@ public class BlockAndReplacePackets extends ExtensionForm {
@Override
protected void initExtension() {
Extension.MessageListener messageListener = message -> {
MessageListener messageListener = message -> {
for (BlockReplaceRule rule : rules) {
rule.appendRuleToMessage(message);
}
@ -185,6 +210,10 @@ public class BlockAndReplacePackets extends ExtensionForm {
intercept(HMessage.Direction.TOSERVER, messageListener);
intercept(HMessage.Direction.TOCLIENT, messageListener);
onConnect((host, port, hotelversion, clientIdentifier, clientType, packetInfoManager) -> {
this.packetInfoManager = packetInfoManager;
});
}
@Override
@ -196,6 +225,7 @@ public class BlockAndReplacePackets extends ExtensionForm {
primaryStage.setScene(new Scene(root));
primaryStage.setResizable(false);
primaryStage.getScene().getStylesheets().add(GEarthController.class.getResource("/gearth/ui/bootstrap3.css").toExternalForm());
primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream("G-EarthLogoSmaller.png")));
return loader.getController();
}
@ -206,7 +236,8 @@ public class BlockAndReplacePackets extends ExtensionForm {
}
public void click_btnAddRule(ActionEvent actionEvent) {
BlockReplaceRule rule = RuleFactory.getRule(cmb_type.getSelectionModel().getSelectedItem(), cmb_side.getSelectionModel().getSelectedItem(), txt_value.getText(), txt_replacement.getText());
BlockReplaceRule rule = RuleFactory.getRule(cmb_type.getSelectionModel().getSelectedItem(),
cmb_side.getSelectionModel().getSelectedItem(), getVal(), txt_replacement.getText(), packetInfoManager);
rules.add(rule);
rule.onDelete(observable -> rules.remove(rule));
new RuleContainer(rule, vbox);
@ -215,6 +246,11 @@ public class BlockAndReplacePackets extends ExtensionForm {
clearInput();
}
@Override
protected boolean canLeave() {
return false;
}
@Override
protected boolean canDelete() {
return false;

View File

@ -1,6 +1,6 @@
package extensions.blockreplacepackets;
package gearth.services.internal_extensions.blockreplacepackets;
import extensions.blockreplacepackets.rules.BlockReplaceRule;
import gearth.services.internal_extensions.blockreplacepackets.rules.BlockReplaceRule;
import gearth.ui.buttons.DeleteButton;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@ -13,7 +13,7 @@ import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
/**
* Created by Jeunez on 6/11/2018.
* Created by Jonas on 6/11/2018.
*/
public class RuleContainer extends GridPane {

View File

@ -1,4 +1,4 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;

View File

@ -1,4 +1,4 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;
import javafx.beans.InvalidationListener;

View File

@ -1,4 +1,4 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;

View File

@ -1,10 +1,10 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
/**
* Created by Jeunez on 6/11/2018.
* Created by Jonas on 6/11/2018.
*/
public class ReplacePacketRule extends BlockReplaceRule {

View File

@ -1,4 +1,4 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;

View File

@ -1,4 +1,4 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.protocol.HMessage;

View File

@ -1,5 +1,7 @@
package extensions.blockreplacepackets.rules;
package gearth.services.internal_extensions.blockreplacepackets.rules;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
/**
@ -7,7 +9,7 @@ import gearth.protocol.HPacket;
*/
public class RuleFactory {
public static BlockReplaceRule getRule(String type, String side, String value, String replacement) {
public static BlockReplaceRule getRule(String type, String side, String value, String replacement, PacketInfoManager packetInfoManager) {
BlockReplaceRule.Option rOption = BlockReplaceRule.Option.valueOf(type.split(" ")[0].toUpperCase());
BlockReplaceRule.Type rType = BlockReplaceRule.Type.valueOf(type.split(" ")[1].toUpperCase());
BlockReplaceRule.Side rSide = BlockReplaceRule.Side.valueOf(side.toUpperCase());
@ -24,7 +26,11 @@ public class RuleFactory {
return new ReplaceIntegerRule(rSide, Integer.parseInt(value), Integer.parseInt(replacement));
}
if (rType == BlockReplaceRule.Type.PACKET) {
return new ReplacePacketRule(rSide, Integer.parseInt(value), new HPacket(replacement));
HPacket packet = new HPacket(replacement);
if (!packet.isPacketComplete()) {
packet.completePacket(rSide == BlockReplaceRule.Side.INCOMING ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, packetInfoManager);
}
return new ReplacePacketRule(rSide, Integer.parseInt(value), packet);
}
if (rType == BlockReplaceRule.Type.STRING) {
return new ReplaceStringRule(rSide, value, replacement);

View File

@ -0,0 +1,189 @@
package gearth.services.internal_extensions.packetinfoexplorer;
import gearth.Main;
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.ui.GEarthController;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
@ExtensionInfo(
Title = "Packet Info",
Description = "Packet info explorer",
Version = "0.1",
Author = "sirjonasxx"
)
public class PacketInfoExplorer extends ExtensionForm {
public TextField txt_filterHeaderId;
public TextField txt_filterNameHash;
public GridPane source_grid;
public CheckBox chk_toClient;
public CheckBox chk_toServer;
private Map<String, CheckBox> chk_sources = new HashMap<>();
private List<PacketInfo> packetInfoList = new ArrayList<>();
private TableView<PacketInfo> tableView;
public GridPane grid;
@Override
public ExtensionForm launchForm(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(PacketInfoExplorer.class.getResource("PacketInfoExplorer.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Packet info explorer");
primaryStage.setScene(new Scene(root));
primaryStage.setMinWidth(430);
primaryStage.setMinHeight(260);
primaryStage.getScene().getStylesheets().add(GEarthController.class.getResource("/gearth/ui/bootstrap3.css").toExternalForm());
primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream("G-EarthLogoSmaller.png")));
return loader.getController();
}
public void initialize() {
Platform.runLater( () -> grid.requestFocus() );
tableView = new TableView<>();
tableView.setTableMenuButtonVisible(true);
tableView.setStyle("-fx-focus-color: white;");
tableView.focusedProperty().addListener(observable -> {
if (tableView.isFocused()) {
grid.requestFocus();
}
});
TableColumn<PacketInfo, Integer> headerIdColumn = new TableColumn<>("Header ID");
headerIdColumn.setCellValueFactory(new PropertyValueFactory<>("headerId"));
TableColumn<PacketInfo, HMessage.Direction> directionColumn = new TableColumn<>("Direction");
directionColumn.setCellValueFactory(new PropertyValueFactory<>("destination"));
directionColumn.setPrefWidth(96);
TableColumn<PacketInfo, String> packetNameColumn = new TableColumn<>("Name");
packetNameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
packetNameColumn.setPrefWidth(220);
TableColumn<PacketInfo, String> packetHashColumn = new TableColumn<>("Hash");
packetHashColumn.setVisible(false);
packetHashColumn.setCellValueFactory(new PropertyValueFactory<>("hash"));
packetHashColumn.setPrefWidth(220);
TableColumn<PacketInfo, String> structureColumn = new TableColumn<>("Structure");
structureColumn.setCellValueFactory(new PropertyValueFactory<>("structure"));
structureColumn.setPrefWidth(115);
TableColumn<PacketInfo, String> sourceColumn = new TableColumn<>("Source");
sourceColumn.setCellValueFactory(new PropertyValueFactory<>("source"));
tableView.getColumns().addAll(Arrays.asList(headerIdColumn, directionColumn, packetNameColumn,
packetHashColumn, structureColumn, sourceColumn));
grid.add(tableView, 0, 1);
InvalidationListener filterValues = observable -> updateTableValues();
txt_filterHeaderId.textProperty().addListener(filterValues);
txt_filterNameHash.textProperty().addListener(filterValues);
chk_toClient.selectedProperty().addListener(filterValues);
chk_toClient.selectedProperty().addListener(filterValues);
}
@Override
protected void initExtension() {
onConnect((host, port, hotelversion, clientIdentifier, clientType, packetInfoManager) -> {
setPacketInfoManager(packetInfoManager);
});
}
@Override
protected void onEndConnection() {
setPacketInfoManager(PacketInfoManager.EMPTY);
}
private void setPacketInfoManager(PacketInfoManager packetInfoManager) {
packetInfoList = packetInfoManager.getPacketInfoList();
packetInfoList.sort(Comparator.comparingInt(PacketInfo::getHeaderId));
Platform.runLater(() -> {
source_grid.getChildren().clear();
chk_sources.clear();
for (PacketInfo packetInfo : packetInfoList) {
if (!chk_sources.containsKey(packetInfo.getSource())) {
CheckBox checkBox = new CheckBox(packetInfo.getSource());
checkBox.setSelected(true);
checkBox.selectedProperty().addListener(observable -> updateTableValues());
source_grid.add(checkBox, 0, chk_sources.size());
chk_sources.put(packetInfo.getSource(), checkBox);
}
}
primaryStage.setTitle("Packet info explorer | " + packetInfoList.size() + " packets");
updateTableValues();
});
}
private void updateTableValues() {
tableView.getItems().clear();
IntegerProperty doHeaderIdFilter = new SimpleIntegerProperty(-1);
if (!txt_filterHeaderId.getText().equals("")) {
try {
doHeaderIdFilter.setValue(Integer.parseInt(txt_filterHeaderId.getText()));
}
catch (Exception ignore) {}
}
List<PacketInfo> allPacketInfos = packetInfoList.stream()
.filter(packetInfo -> {
if (doHeaderIdFilter.get() != -1 && packetInfo.getHeaderId() != doHeaderIdFilter.get()) return false;
String filterNameHashLower = txt_filterNameHash.getText().toLowerCase();
if (!filterNameHashLower.equals("")
&& (packetInfo.getName() == null || !packetInfo.getName().toLowerCase().contains(filterNameHashLower))
&& (packetInfo.getHash() == null || !packetInfo.getHash().toLowerCase().contains(filterNameHashLower))) {
return false;
}
if ((!chk_toClient.isSelected() && packetInfo.getDestination() == HMessage.Direction.TOCLIENT)
|| (!chk_toServer.isSelected() && packetInfo.getDestination() == HMessage.Direction.TOSERVER)) {
return false;
}
if (!chk_sources.get(packetInfo.getSource()).isSelected()) return false;
return true;
}).collect(Collectors.toList());
tableView.getItems().addAll(allPacketInfos);
}
@Override
protected boolean canLeave() {
return false;
}
@Override
protected boolean canDelete() {
return false;
}
}

View File

@ -1,4 +1,4 @@
package gearth.ui.logger.loggerdisplays.uilogger;
package gearth.services.internal_extensions.uilogger;
/**
* Created by Jonas on 17/11/2018.

View File

@ -0,0 +1,108 @@
package gearth.services.internal_extensions.uilogger;
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.ui.logger.loggerdisplays.PacketLogger;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
@ExtensionInfo(
Title = "Packet Logger",
Description = "",
Version = "1.0",
Author = "sirjonasxx & Scott"
)
public class UiLogger extends ExtensionForm implements PacketLogger {
private UiLoggerController controller = null;
@Override
public void start(HConnection hConnection) {
// // don't let the user close this window on their own
// stage.setOnCloseRequest(Event::consume);
// primaryStage.show();
}
@Override
public void stop() {
// primaryStage.hide();
// if (stage != null)
// stage.close();
}
@Override
public void appendSplitLine() {
// don't use this, we can't discern incoming/outgoing
//Platform.runLater(() -> controller.appendSplitLine());
}
@Override
protected void initExtension() {
onConnect((host, port, hotelversion, clientIdentifier, clientType, packetInfoManager) -> {
controller.setPacketInfoManager(packetInfoManager);
controller.onConnect();
});
}
@Override
protected void onEndConnection() {
controller.onDisconnect();
controller.setPacketInfoManager(PacketInfoManager.EMPTY);
}
@Override
public ExtensionForm launchForm(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(UiLogger.class.getResource("UiLogger.fxml"));
Parent root = loader.load();
stage.setTitle("G-Earth | Packet Logger");
stage.initModality(Modality.NONE);
stage.getIcons().add(new Image(getClass().getResourceAsStream("/gearth/G-EarthLogoSmaller.png")));
Scene scene = new Scene(root);
scene.getStylesheets().add("/gearth/ui/bootstrap3.css");
scene.getStylesheets().add("/gearth/services/internal_extensions/uilogger/logger.css");
controller = loader.getController();
controller.setStage(stage);
stage.setScene(scene);
return this;
}
private class Elem {
HPacket packet;
int types;
Elem(HPacket packet, int types) {
this.packet = packet;
this.types = types;
}
}
@Override
public void appendMessage(HPacket packet, int types) {
controller.appendMessage(packet, types);
}
@Override
public void appendStructure(HPacket packet, HMessage.Direction direction) {
}
@Override
protected boolean canLeave() {
return false;
}
@Override
protected boolean canDelete() {
return false;
}
}

View File

@ -0,0 +1,400 @@
package gearth.services.internal_extensions.uilogger;
import gearth.misc.Cacher;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.ui.logger.loggerdisplays.PacketLogger;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;
public class UiLoggerController implements Initializable {
private static final String LOGGER_SETTINGS_CACHE = "LOGGER_SETTINGS";
public FlowPane flowPane;
public BorderPane borderPane;
public Label lblViewIncoming;
public Label lblViewOutgoing;
public CheckMenuItem chkViewIncoming;
public CheckMenuItem chkViewOutgoing;
public CheckMenuItem chkDisplayStructure;
public Label lblAutoScrolll;
public CheckMenuItem chkAutoscroll;
public CheckMenuItem chkSkipBigPackets;
public CheckMenuItem chkMessageName;
public CheckMenuItem chkMessageHash;
public Label lblPacketInfo;
public CheckMenuItem chkUseNewStructures;
public CheckMenuItem chkAlwaysOnTop;
public CheckMenuItem chkOpenOnConnect;
public CheckMenuItem chkResetOnConnect;
public CheckMenuItem chkHideOnDisconnect;
public CheckMenuItem chkResetOnDisconnect;
private final static int FILTER_AMOUNT_THRESHOLD_L = 15;
private final static int FILTER_AMOUNT_THRESHOLD_M = 9;
private final static int FILTER_AMOUNT_THRESHOLD_H = 4;
private final static int FILTER_AMOUNT_THRESHOLD_U = 2;
private final static int FILTER_TIME_THRESHOLD = 5000;
public RadioMenuItem chkAntiSpam_none;
public RadioMenuItem chkAntiSpam_low;
public RadioMenuItem chkAntiSpam_medium;
public RadioMenuItem chkAntiSpam_high;
public RadioMenuItem chkAntiSpam_ultra;
public Label lblFiltered;
private Map<Integer, LinkedList<Long>> filterTimestamps = new HashMap<>();
private StyleClassedTextArea area;
private Stage stage;
private PacketInfoManager packetInfoManager = null;
private int filteredAmount = 0;
private volatile boolean initialized = false;
private final List<Element> appendLater = new ArrayList<>();
private List<MenuItem> allMenuItems = new ArrayList<>();
private boolean isSelected(MenuItem item) {
if (item instanceof CheckMenuItem) {
return ((CheckMenuItem)item).isSelected();
}
if (item instanceof RadioMenuItem) {
return ((RadioMenuItem)item).isSelected();
}
return false;
}
private void setSelected(MenuItem item, boolean selected) {
if (item instanceof CheckMenuItem) {
((CheckMenuItem)item).setSelected(selected);
}
if (item instanceof RadioMenuItem) {
((RadioMenuItem)item).setSelected(selected);
}
}
private void saveAllMenuItems() {
List<Boolean> selection = new ArrayList<>();
for (MenuItem menuItem : allMenuItems) {
selection.add(isSelected(menuItem));
}
Cacher.put(LOGGER_SETTINGS_CACHE, selection);
}
private void loadAllMenuItems() {
List<Object> selectedMenuItems = Cacher.getList(LOGGER_SETTINGS_CACHE);
if (selectedMenuItems != null) {
for (int i = 0; i < selectedMenuItems.size(); i++) {
boolean isSelected = (boolean) selectedMenuItems.get(i);
setSelected(allMenuItems.get(i), isSelected);
}
}
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
allMenuItems.addAll(Arrays.asList(
chkViewIncoming, chkViewOutgoing, chkDisplayStructure, chkAutoscroll,
chkSkipBigPackets, chkMessageName, chkMessageHash, chkUseNewStructures,
chkOpenOnConnect, chkResetOnConnect, chkHideOnDisconnect, chkResetOnDisconnect,
chkAntiSpam_none, chkAntiSpam_low, chkAntiSpam_medium, chkAntiSpam_high, chkAntiSpam_ultra
));
loadAllMenuItems();
for (MenuItem item : allMenuItems) {
item.setOnAction(event -> {
saveAllMenuItems();
updateLoggerInfo();
});
}
area = new StyleClassedTextArea();
area.getStyleClass().add("dark");
area.setWrapText(true);
VirtualizedScrollPane<StyleClassedTextArea> vsPane = new VirtualizedScrollPane<>(area);
borderPane.setCenter(vsPane);
synchronized (appendLater) {
initialized = true;
if (!appendLater.isEmpty()) {
appendLog(appendLater);
appendLater.clear();
}
}
}
private static String cleanTextContent(String text) {
// // strips off all non-ASCII characters
// text = text.replaceAll("[^\\x00-\\x7F]", "");
//
// // erases all the ASCII control characters
text = text.replaceAll("[\\p{Cntrl}&&[^\n\t]]", "");
// removes non-printable characters from Unicode
// text = text.replaceAll("\\p{C}", "");
return text.trim();
}
private boolean checkFilter(HPacket packet) {
int headerId = packet.headerId();
int threshold = chkAntiSpam_none.isSelected() ? 100000000 : (
chkAntiSpam_low.isSelected() ? FILTER_AMOUNT_THRESHOLD_L : (
chkAntiSpam_medium.isSelected() ? FILTER_AMOUNT_THRESHOLD_M : (
chkAntiSpam_high.isSelected() ? FILTER_AMOUNT_THRESHOLD_H : FILTER_AMOUNT_THRESHOLD_U
)
)
);
if (!filterTimestamps.containsKey(headerId)) {
filterTimestamps.put(headerId, new LinkedList<>());
}
long queueRemoveThreshold = System.currentTimeMillis() - FILTER_TIME_THRESHOLD;
LinkedList<Long> list = filterTimestamps.get(headerId);
while (!list.isEmpty() && list.get(0) < queueRemoveThreshold) list.removeFirst();
if (list.size() == threshold) list.removeFirst();
list.add(System.currentTimeMillis());
return list.size() >= threshold;
}
public void appendMessage(HPacket packet, int types) {
boolean isBlocked = (types & PacketLogger.MESSAGE_TYPE.BLOCKED.getValue()) != 0;
boolean isReplaced = (types & PacketLogger.MESSAGE_TYPE.REPLACED.getValue()) != 0;
boolean isIncoming = (types & PacketLogger.MESSAGE_TYPE.INCOMING.getValue()) != 0;
if (isIncoming && !isBlocked && !isReplaced) {
boolean filter = checkFilter(packet);
if (filter) {
filteredAmount++;
updateLoggerInfo();
return;
}
}
if (isIncoming && !chkViewIncoming.isSelected()) return;
if (!isIncoming && !chkViewOutgoing.isSelected()) return;
ArrayList<Element> elements = new ArrayList<>();
boolean packetInfoAvailable = packetInfoManager.getPacketInfoList().size() > 0;
if ((chkMessageName.isSelected() || chkMessageHash.isSelected()) && packetInfoAvailable) {
List<PacketInfo> messages = packetInfoManager.getAllPacketInfoFromHeaderId(
(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER),
packet.headerId()
);
List<String> names = messages.stream().map(PacketInfo::getName)
.filter(Objects::nonNull).distinct().collect(Collectors.toList());
List<String> hashes = messages.stream().map(PacketInfo::getHash)
.filter(Objects::nonNull).distinct().collect(Collectors.toList());
boolean addedSomething = false;
if (chkMessageName.isSelected() && names.size() > 0) {
for (String name : names) {elements.add(new Element("["+name+"]", "messageinfo")); }
addedSomething = true;
}
if (chkMessageHash.isSelected() && hashes.size() > 0) {
for (String hash : hashes) {elements.add(new Element("["+hash+"]", "messageinfo")); }
addedSomething = true;
}
if (addedSomething) {
elements.add(new Element("\n", ""));
}
}
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked"));
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced"));
if (isIncoming) {
// handle skipped eventually
elements.add(new Element("Incoming[", "incoming"));
elements.add(new Element(String.valueOf(packet.headerId()), ""));
elements.add(new Element("]", "incoming"));
elements.add(new Element(" <- ", ""));
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
elements.add(new Element("<packet skipped>", "skipped"));
}
else {
elements.add(new Element(packet.toString(), "incoming"));
}
} else {
elements.add(new Element("Outgoing[", "outgoing"));
elements.add(new Element(String.valueOf(packet.headerId()), ""));
elements.add(new Element("]", "outgoing"));
elements.add(new Element(" -> ", ""));
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
elements.add(new Element("<packet skipped>", "skipped"));
}
else {
elements.add(new Element(packet.toString(), "outgoing"));
}
}
if (packet.length() <= 2000) {
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, packetInfoManager, chkUseNewStructures.isSelected());
String cleaned = cleanTextContent(expr);
if (cleaned.equals(expr)) {
if (!expr.equals("") && chkDisplayStructure.isSelected())
elements.add(new Element("\n" + cleanTextContent(expr), "structure"));
}
}
elements.add(new Element("\n--------------------\n", ""));
synchronized (appendLater) {
if (initialized) {
appendLog(elements);
}
else {
appendLater.addAll(elements);
}
}
}
private synchronized void appendLog(List<Element> elements) {
Platform.runLater(() -> {
StringBuilder sb = new StringBuilder();
StyleSpansBuilder<Collection<String>> styleSpansBuilder = new StyleSpansBuilder<>(0);
for (Element element : elements) {
sb.append(element.text);
styleSpansBuilder.add(Collections.singleton(element.className), element.text.length());
}
int oldLen = area.getLength();
area.appendText(sb.toString());
// System.out.println(sb.toString());
area.setStyleSpans(oldLen, styleSpansBuilder.create());
if (chkAutoscroll.isSelected()) {
// area.moveTo(area.getLength());
area.requestFollowCaret();
}
});
}
public void setStage(Stage stage) {
this.stage = stage;
}
public void updateLoggerInfo() {
Platform.runLater(() -> {
lblViewIncoming.setText("View Incoming: " + (chkViewIncoming.isSelected() ? "True" : "False"));
lblViewOutgoing.setText("View Outgoing: " + (chkViewOutgoing.isSelected() ? "True" : "False"));
lblAutoScrolll.setText("Autoscroll: " + (chkAutoscroll.isSelected() ? "True" : "False"));
lblFiltered.setText("Filtered: " + filteredAmount);
boolean packetInfoAvailable = packetInfoManager.getPacketInfoList().size() > 0;
lblPacketInfo.setText("Packet info: " + (packetInfoAvailable ? "True" : "False"));
});
}
public void setPacketInfoManager(PacketInfoManager packetInfoManager) {
this.packetInfoManager = packetInfoManager;
Platform.runLater(this::updateLoggerInfo);
}
public void toggleAlwaysOnTop(ActionEvent actionEvent) {
stage.setAlwaysOnTop(chkAlwaysOnTop.isSelected());
}
public void clearText(ActionEvent actionEvent) {
area.clear();
}
public void onDisconnect() {
Platform.runLater(() -> {
if (chkHideOnDisconnect.isSelected()) {
stage.hide();
}
if (chkResetOnDisconnect.isSelected()) {
clearText(null);
}
});
}
public void onConnect() {
Platform.runLater(() -> {
if (chkResetOnConnect.isSelected()) {
clearText(null);
}
if (chkOpenOnConnect.isSelected()) {
stage.show();
}
});
}
public void exportAll(ActionEvent actionEvent) {
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter =
new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle("Save Packets");
//Show save file dialog
File file = fileChooser.showSaveDialog(stage);
if(file != null){
try {
FileWriter fileWriter = new FileWriter(file);
BufferedWriter out = new BufferedWriter(fileWriter);
out.write(area.getText());
out.flush();
out.close();
fileWriter.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,50 @@
package gearth.services.packet_info;
import gearth.protocol.HMessage;
public class PacketInfo {
private final HMessage.Direction destination;
private final int headerId;
private final String hash;
private final String name;
private final String structure;
private final String source;
public PacketInfo(HMessage.Direction destination, int headerId, String hash, String name, String structure, String source) {
this.destination = destination;
this.headerId = headerId;
this.hash = hash;
this.name = name;
this.structure = structure;
this.source = source;
}
public String getName() {
return name;
}
public String getHash() {
return hash;
}
public int getHeaderId() {
return headerId;
}
public HMessage.Direction getDestination() {
return destination;
}
public String getStructure() {
return structure;
}
public String getSource() {
return source;
}
public String toString() {
return headerId + ": " + "[" + name + "][" + structure + "]";
}
}

View File

@ -0,0 +1,184 @@
package gearth.services.packet_info;
import gearth.services.packet_info.providers.RemotePacketInfoProvider;
import gearth.services.packet_info.providers.implementations.HarblePacketInfoProvider;
import gearth.services.packet_info.providers.implementations.SulekPacketInfoProvider;
import gearth.services.packet_info.providers.implementations.GEarthUnityPacketInfoProvider;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.HClient;
import java.util.*;
import java.util.concurrent.Semaphore;
public class PacketInfoManager {
private Map<Integer, List<PacketInfo>> headerIdToMessage_incoming = new HashMap<>();
private Map<Integer, List<PacketInfo>> headerIdToMessage_outgoing = new HashMap<>();
private Map<String, List<PacketInfo>> hashToMessage_incoming = new HashMap<>();
private Map<String, List<PacketInfo>> hashToMessage_outgoing = new HashMap<>();
private Map<String, List<PacketInfo>> nameToMessage_incoming = new HashMap<>();
private Map<String, List<PacketInfo>> nameToMessage_outgoing = new HashMap<>();
private List<PacketInfo> packetInfoList;
public PacketInfoManager(List<PacketInfo> packetInfoList) {
this.packetInfoList = packetInfoList;
for (PacketInfo packetInfo : packetInfoList) {
addMessage(packetInfo);
}
}
private void addMessage(PacketInfo packetInfo) {
if (packetInfo.getHash() == null && packetInfo.getName() == null) return;
Map<Integer, List<PacketInfo>> headerIdToMessage =
packetInfo.getDestination() == HMessage.Direction.TOCLIENT
? headerIdToMessage_incoming :
headerIdToMessage_outgoing;
Map<String, List<PacketInfo>> hashToMessage =
packetInfo.getDestination() == HMessage.Direction.TOCLIENT
? hashToMessage_incoming
: hashToMessage_outgoing;
Map<String, List<PacketInfo>> nameToMessage =
packetInfo.getDestination() == HMessage.Direction.TOCLIENT
? nameToMessage_incoming
: nameToMessage_outgoing;
headerIdToMessage.computeIfAbsent(packetInfo.getHeaderId(), k -> new ArrayList<>());
headerIdToMessage.get(packetInfo.getHeaderId()).add(packetInfo);
if (packetInfo.getHash() != null) {
hashToMessage.computeIfAbsent(packetInfo.getHash(), k -> new ArrayList<>());
hashToMessage.get(packetInfo.getHash()).add(packetInfo);
}
if (packetInfo.getName() != null) {
nameToMessage.computeIfAbsent(packetInfo.getName(), k -> new ArrayList<>());
nameToMessage.get(packetInfo.getName()).add(packetInfo);
}
}
public List<PacketInfo> getAllPacketInfoFromHeaderId(HMessage.Direction direction, int headerId) {
Map<Integer, List<PacketInfo>> headerIdToMessage =
(direction == HMessage.Direction.TOSERVER
? headerIdToMessage_outgoing
: headerIdToMessage_incoming);
return headerIdToMessage.get(headerId) == null ? new ArrayList<>() : headerIdToMessage.get(headerId);
}
public List<PacketInfo> getAllPacketInfoFromHash(HMessage.Direction direction, String hash) {
Map<String, List<PacketInfo>> hashToMessage =
(direction == HMessage.Direction.TOSERVER
? hashToMessage_outgoing
: hashToMessage_incoming);
return hashToMessage.get(hash) == null ? new ArrayList<>() : hashToMessage.get(hash);
}
public List<PacketInfo> getAllPacketInfoFromName(HMessage.Direction direction, String name) {
Map<String, List<PacketInfo>> nameToMessage =
(direction == HMessage.Direction.TOSERVER
? nameToMessage_outgoing
: nameToMessage_incoming);
return nameToMessage.get(name) == null ? new ArrayList<>() : nameToMessage.get(name);
}
public PacketInfo getPacketInfoFromHeaderId(HMessage.Direction direction, int headerId) {
List<PacketInfo> all = getAllPacketInfoFromHeaderId(direction, headerId);
return all.size() == 0 ? null : all.get(0);
}
public PacketInfo getPacketInfoFromHash(HMessage.Direction direction, String hash) {
List<PacketInfo> all = getAllPacketInfoFromHash(direction, hash);
return all.size() == 0 ? null : all.get(0);
}
public PacketInfo getPacketInfoFromName(HMessage.Direction direction, String name) {
List<PacketInfo> all = getAllPacketInfoFromName(direction, name);
return all.size() == 0 ? null : all.get(0);
}
public List<PacketInfo> getPacketInfoList() {
return packetInfoList;
}
public static PacketInfoManager fromHotelVersion(String hotelversion, HClient clientType) {
List<PacketInfo> result = new ArrayList<>();
if (clientType == HClient.UNITY) {
result.addAll(new GEarthUnityPacketInfoProvider(hotelversion).provide());
}
else if (clientType == HClient.FLASH) {
try {
List<RemotePacketInfoProvider> providers = new ArrayList<>();
providers.add(new HarblePacketInfoProvider(hotelversion));
providers.add(new SulekPacketInfoProvider(hotelversion));
Semaphore blockUntilComplete = new Semaphore(providers.size());
blockUntilComplete.acquire(providers.size());
List<PacketInfo> synchronizedResult = Collections.synchronizedList(result);
for (RemotePacketInfoProvider provider : providers) {
new Thread(() -> {
synchronizedResult.addAll(provider.provide());
blockUntilComplete.release();
}).start();
}
blockUntilComplete.acquire(providers.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return new PacketInfoManager(result);
}
public static PacketInfoManager readFromPacket(HPacket hPacket) {
List<PacketInfo> packetInfoList = new ArrayList<>();
int size = hPacket.readInteger();
for (int i = 0; i < size; i++) {
int headerId = hPacket.readInteger();
String hash = hPacket.readString();
String name = hPacket.readString();
String structure = hPacket.readString();
boolean isOutgoing = hPacket.readBoolean();
String source = hPacket.readString();
packetInfoList.add(new PacketInfo(
isOutgoing ? HMessage.Direction.TOSERVER : HMessage.Direction.TOCLIENT,
headerId,
hash.equals("NULL") ? null : hash,
name.equals("NULL") ? null : name,
structure.equals("NULL") ? null : structure,
source));
}
return new PacketInfoManager(packetInfoList);
}
public void appendToPacket(HPacket hPacket) {
hPacket.appendInt(packetInfoList.size());
for (PacketInfo packetInfo : packetInfoList) {
hPacket.appendInt(packetInfo.getHeaderId());
hPacket.appendString(packetInfo.getHash() == null ? "NULL" : packetInfo.getHash());
hPacket.appendString(packetInfo.getName() == null ? "NULL" : packetInfo.getName());
hPacket.appendString(packetInfo.getStructure() == null ? "NULL" : packetInfo.getStructure());
hPacket.appendBoolean(packetInfo.getDestination() == HMessage.Direction.TOSERVER);
hPacket.appendString(packetInfo.getSource());
}
}
public static PacketInfoManager EMPTY = new PacketInfoManager(new ArrayList<>());
}

View File

@ -0,0 +1,39 @@
package gearth.services.packet_info.providers;
import gearth.services.packet_info.PacketInfo;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public abstract class PacketInfoProvider {
protected final String hotelVersion;
public PacketInfoProvider(String hotelVersion) {
this.hotelVersion = hotelVersion;
}
protected abstract File getFile();
public List<PacketInfo> provide() {
File file = getFile();
if (file == null || !file.exists() || file.isDirectory()) return new ArrayList<>();
try {
String contents = String.join("\n", Files.readAllLines(file.toPath()));
JSONObject object = new JSONObject(contents);
return parsePacketInfo(object);
} catch (IOException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
protected abstract List<PacketInfo> parsePacketInfo(JSONObject jsonObject);
}

View File

@ -0,0 +1,40 @@
package gearth.services.packet_info.providers;
import gearth.misc.Cacher;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.File;
import java.io.IOException;
public abstract class RemotePacketInfoProvider extends PacketInfoProvider {
public RemotePacketInfoProvider(String hotelVersion) {
super(hotelVersion);
}
protected abstract String getRemoteUrl();
protected abstract String getCacheName();
@Override
protected File getFile() {
File f = new File(Cacher.getCacheDir(), getCacheName());
if (!f.exists()) {
Connection connection = Jsoup.connect(getRemoteUrl()).ignoreContentType(true);
try {
connection.timeout(3000);
Connection.Response response = connection.execute();
if (response.statusCode() == 200) {
String messagesBodyJson = response.body();
Cacher.updateCache(messagesBodyJson, getCacheName());
}
else {
return null;
}
} catch (IOException e) {
return null;
}
}
return new File(Cacher.getCacheDir(), getCacheName());
}
}

View File

@ -0,0 +1,64 @@
package gearth.services.packet_info.providers.implementations;
import gearth.Main;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.providers.PacketInfoProvider;
import gearth.protocol.HMessage;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
public class GEarthUnityPacketInfoProvider extends PacketInfoProvider {
public GEarthUnityPacketInfoProvider(String hotelVersion) {
super(hotelVersion);
}
@Override
protected File getFile() {
try {
return new File(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI())
.getParentFile(), "messages.json");
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
}
private PacketInfo jsonToPacketInfo(JSONObject object, HMessage.Direction destination) {
String name = object.getString("Name");
int headerId = object.getInt("Id");
return new PacketInfo(destination, headerId, null, name, null, "G-Earth");
}
@Override
protected List<PacketInfo> parsePacketInfo(JSONObject jsonObject) {
List<PacketInfo> packetInfos = new ArrayList<>();
try {
JSONArray incoming = jsonObject.getJSONArray("Incoming");
JSONArray outgoing = jsonObject.getJSONArray("Outgoing");
if (incoming != null && outgoing != null) {
for (int i = 0; i < incoming.length(); i++) {
JSONObject jsonInfo = incoming.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOCLIENT);
packetInfos.add(packetInfo);
}
for (int i = 0; i < outgoing.length(); i++) {
JSONObject jsonInfo = outgoing.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOSERVER);
packetInfos.add(packetInfo);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return packetInfos;
}
}

View File

@ -0,0 +1,79 @@
package gearth.services.packet_info.providers.implementations;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.providers.RemotePacketInfoProvider;
import gearth.protocol.HMessage;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class HarblePacketInfoProvider extends RemotePacketInfoProvider {
public static final String CACHE_PREFIX = "HARBLE_API-";
public static final String HARBLE_API_URL = "https://api.harble.net/messages/$hotelversion$.json";
public HarblePacketInfoProvider(String hotelVersion) {
super(hotelVersion);
}
@Override
protected String getRemoteUrl() {
return HARBLE_API_URL.replace("$hotelversion$", hotelVersion);
}
@Override
protected String getCacheName() {
return CACHE_PREFIX + hotelVersion;
}
private PacketInfo jsonToPacketInfo(JSONObject object, HMessage.Direction destination) {
String name;
String hash;
String structure;
try {
name = object.getString("Name")
.replaceAll("Composer$", "");
}
catch (Exception e) { name = null; }
try { hash = object.getString("Hash"); }
catch (Exception e) { hash = null; }
try { structure = object.getString("Structure");
} catch (Exception e) { structure = null; }
structure = (structure == null || structure.equals("")) ? null : structure;
int headerId;
try {headerId = object.getInt("Id"); }
catch (Exception e) { headerId = Integer.parseInt(object.getString("Id")); }
return new PacketInfo(destination, headerId, hash, name, structure, "Harble");
}
@Override
protected List<PacketInfo> parsePacketInfo(JSONObject jsonObject) {
List<PacketInfo> packetInfos = new ArrayList<>();
try {
JSONArray incoming = jsonObject.getJSONArray("Incoming");
JSONArray outgoing = jsonObject.getJSONArray("Outgoing");
if (incoming != null && outgoing != null) {
for (int i = 0; i < incoming.length(); i++) {
JSONObject jsonInfo = incoming.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOCLIENT);
packetInfos.add(packetInfo);
}
for (int i = 0; i < outgoing.length(); i++) {
JSONObject jsonInfo = outgoing.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOSERVER);
packetInfos.add(packetInfo);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return packetInfos;
}
}

View File

@ -0,0 +1,63 @@
package gearth.services.packet_info.providers.implementations;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.providers.RemotePacketInfoProvider;
import gearth.protocol.HMessage;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class SulekPacketInfoProvider extends RemotePacketInfoProvider {
public static final String CACHE_PREFIX = "SULEK_API-";
public static final String SULEK_API_URL = "https://api.sulek.dev/releases/$hotelversion$/messages";
public SulekPacketInfoProvider(String hotelVersion) {
super(hotelVersion);
}
@Override
protected String getRemoteUrl() {
return SULEK_API_URL.replace("$hotelversion$", hotelVersion);
}
@Override
protected String getCacheName() {
return CACHE_PREFIX + hotelVersion;
}
private PacketInfo jsonToPacketInfo(JSONObject object, HMessage.Direction destination) {
int headerId = object.getInt("id");
String name = object.getString("name")
.replaceAll("(((Message)?Composer)|((Message)?Event))$", "");
return new PacketInfo(destination, headerId, null, name, null, "Sulek");
}
@Override
protected List<PacketInfo> parsePacketInfo(JSONObject jsonObject) {
List<PacketInfo> packetInfos = new ArrayList<>();
try {
JSONArray incoming = jsonObject.getJSONObject("messages").getJSONArray("incoming");
JSONArray outgoing = jsonObject.getJSONObject("messages").getJSONArray("outgoing");
for (int i = 0; i < incoming.length(); i++) {
JSONObject jsonInfo = incoming.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOCLIENT);
packetInfos.add(packetInfo);
}
for (int i = 0; i < outgoing.length(); i++) {
JSONObject jsonInfo = outgoing.getJSONObject(i);
PacketInfo packetInfo = jsonToPacketInfo(jsonInfo, HMessage.Direction.TOSERVER);
packetInfos.add(packetInfo);
}
} catch (Exception e) {
e.printStackTrace();
}
return packetInfos;
}
}

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation;
package gearth.services.packetrepresentation;
public class InvalidPacketException extends Exception {
}

View File

@ -1,6 +1,7 @@
package gearth.misc.packetrepresentation;
package gearth.services.packetrepresentation;
import gearth.misc.packetrepresentation.prediction.StructurePredictor;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packetrepresentation.prediction.StructurePredictor;
import gearth.protocol.HPacket;
import java.nio.ByteBuffer;
@ -48,8 +49,8 @@ public class PacketStringUtils {
packet = replaceAll(packet, "\\{u:([0-9]+)}",
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
packet = replaceAll(packet, "\\{h:([0-9]+)}",
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
packet = replaceAll(packet, "\\{h:(-?[0-9]+)}",
m -> toString(ByteBuffer.allocate(2).putShort(Short.parseShort(m.group(1))).array()));
packet = replaceAll(packet, "\\{b:([Ff]alse|[Tt]rue)}",
m -> m.group(1).toLowerCase().equals("true") ? "[1]" : "[0]");
@ -124,13 +125,24 @@ public class PacketStringUtils {
}
}
actualString.append(match);
String latin = new String(actualString.toString().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
HPacket temp = new HPacket(0);
temp.appendString(latin, StandardCharsets.ISO_8859_1);
packet = packet.substring(0, start) +
toString(new HPacket(0, latin).readBytes(latin.length() + 2, 6)) +
toString(temp.readBytes(latin.length() + 2, 6)) +
packet.substring(end + 2);
}
String[] identifier = {null};
if (!fixLengthLater && packet.startsWith("{")) {
packet = replaceAll(packet, "^\\{([^:{}]*)}", m -> {
identifier[0] = m.group(1);
return "[255][255]";
});
}
if (identifier[0] != null) fixLengthLater = true;
if (packet.contains("{") || packet.contains("}")) {
throw new InvalidPacketException();
@ -160,6 +172,9 @@ public class PacketStringUtils {
if (fixLengthLater) {
hPacket.fixLength();
}
if (identifier[0] != null) {
hPacket.setIdentifier(identifier[0]);
}
return hPacket;
}
public static String toString(byte[] packet) {
@ -175,14 +190,21 @@ public class PacketStringUtils {
}
// generates an expression for a packet from a packet structure (ex. "i(isi(b))iBd")
public static String toExpressionFromGivenStructure(HPacket packet, String struct) {
public static String toExpressionFromGivenStructure(HPacket packet, String struct, PacketInfo packetInfo) {
int oldReadIndex = packet.getReadIndex();
packet.resetReadIndex();
StringBuilder builder = new StringBuilder();
builder.append("{l}{h:").append(packet.headerId()).append("}");
if (packetInfo != null) {
String identifier = packetInfo.getName() == null ? packetInfo.getHash() : packetInfo.getName();
builder.append("{").append(identifier).append("}");
}
else {
builder.append("{l}{h:").append(packet.headerId()).append("}");
}
buildExpressionFromGivenStructure(packet, struct, 0, builder);
packet.setReadIndex(oldReadIndex);
return builder.toString();
}
@ -216,9 +238,12 @@ public class PacketStringUtils {
else return;
}
}
public static String predictedExpression(HPacket packet) {
public static String predictedExpression(HPacket packet, PacketInfo packetInfo) {
StructurePredictor structurePredictor = new StructurePredictor(packet);
return structurePredictor.getExpression();
String structure = structurePredictor.getStructure();
if (structure == null) return "";
return PacketStringUtils.toExpressionFromGivenStructure(packet, structure, packetInfo);
}
public static boolean structureEquals(HPacket packet, String struct) {
@ -241,6 +266,12 @@ public class PacketStringUtils {
}
public static void main(String[] args) throws InvalidPacketException {
HPacket fghdft = fromString("{l}{h:-1}{i:1}{i:0}{i:6}{i:4}{s:\"1.0\"}");
System.out.println(fghdft);
HPacket zed = fromString("{test}{s:\"¥\"}{i:0}{i:0}");
System.out.println(zed);
HPacket p1 = fromString("{l}{h:1129}{s:\"\\\\\\\\\"}{i:0}{i:0}");
System.out.println(p1.toExpression());
HPacket p1_2 = fromString(p1.toExpression());
@ -253,6 +284,9 @@ public class PacketStringUtils {
new HPacket("{l}{h:5}{s:\"asdas\"}"),
"s"
));
HPacket p3 = fromString("{l}{h:2266}{s:\"¥\"}{i:0}{i:0}");
System.out.println(p3);
}
}

View File

@ -1,8 +1,7 @@
package gearth.misc.packetrepresentation.prediction;
package gearth.services.packetrepresentation.prediction;
import gearth.misc.packetrepresentation.PacketStringUtils;
import gearth.misc.packetrepresentation.prediction.checkers.TypeChecker;
import gearth.misc.packetrepresentation.prediction.checkers.TypeCheckerProducer;
import gearth.services.packetrepresentation.prediction.checkers.TypeChecker;
import gearth.services.packetrepresentation.prediction.checkers.TypeCheckerProducer;
import gearth.protocol.HPacket;
import java.util.List;
@ -65,13 +64,6 @@ public class StructurePredictor {
structure = stringBuilder.reverse().toString();
}
public String getExpression() {
if (structure == null) {
return "";
}
return PacketStringUtils.toExpressionFromGivenStructure(packet, structure);
}
public String getStructure() {
return structure;
}

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,7 +1,6 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;
import gearth.services.Constants;
import java.nio.charset.StandardCharsets;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -1,4 +1,4 @@
package gearth.misc.packetrepresentation.prediction.checkers;
package gearth.services.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;

View File

@ -87,7 +87,11 @@ public class GEarthController {
private void trySetController() {
if (++initcount == 2) {
GEarthController self = this;
tabs.forEach(subForm -> subForm.setParentController(self));
extensionsController.setParentController(self);
tabs.forEach(subForm -> {
if (subForm != extensionsController) subForm.setParentController(self);
});
}
}

View File

@ -116,7 +116,11 @@ public class ConnectionController extends SubForm {
}
}
private void updateInputUI() {
if (parentController == null) return;
grd_clientSelection.setDisable(getHConnection().getState() != HState.NOT_CONNECTED);
txtfield_hotelversion.setText(getHConnection().getHotelVersion());
@ -184,6 +188,8 @@ public class ConnectionController extends SubForm {
}
}));
Platform.runLater(this::updateInputUI);
}
public void btnConnect_clicked(ActionEvent actionEvent) {

View File

@ -1,5 +1,6 @@
package gearth.ui.extensions;
import gearth.services.extensionhandler.extensions.ExtensionType;
import gearth.services.extensionhandler.extensions.GEarthExtension;
import javafx.application.Platform;
import javafx.event.EventHandler;
@ -142,6 +143,11 @@ public class ExtensionItemContainer extends GridPane {
parent.getChildren().add(this);
if (item.extensionType() == ExtensionType.INTERNAL) {
setBackground(new Background(new BackgroundFill(Paint.valueOf("F0FFFF"), CornerRadii.EMPTY, Insets.EMPTY)));
}
initExtension();
}

View File

@ -133,4 +133,8 @@ public class ExtensionsController extends SubForm {
Platform.runLater(this::updateGPythonStatus);
});
}
public ExtensionHandler getExtensionHandler() {
return extensionHandler;
}
}

View File

@ -2,12 +2,10 @@ package gearth.ui.extra;
import gearth.Main;
import gearth.misc.Cacher;
import gearth.misc.packetrepresentation.prediction.checkers.TypeCheckerProducer;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.services.Constants;
import gearth.services.gpython.GPythonVersionUtils;
import gearth.ui.SubForm;
import gearth.ui.info.InfoController;

View File

@ -0,0 +1,85 @@
package gearth.ui.injection;
import gearth.misc.StringifyAble;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
public class InjectedPackets implements StringifyAble {
private String packetsAsString;
private String description;
public InjectedPackets(String packetsAsString, int amountPackets, PacketInfoManager packetInfoManager, HMessage.Direction direction) {
String description;
if (amountPackets > 1) {
description = String.format("(packets: %d, length: %d)", amountPackets, packetsAsString.length());
}
else { // assume 1 packet
HPacket packet = new HPacket(packetsAsString);
String identifier = null;
if (!packet.isPacketComplete()) {
identifier = packet.getIdentifier();
}
else {
Optional<PacketInfo> maybeInfo = packetInfoManager.getAllPacketInfoFromHeaderId(direction, packet.headerId())
.stream().filter(packetInfo -> packetInfo.getName() != null).findFirst();
if (maybeInfo.isPresent()) {
PacketInfo packetInfo = maybeInfo.get();
identifier = packetInfo.getName();
}
}
if (identifier != null) {
description = String.format("%s", identifier);
}
else {
description = String.format("(id: %d, length: %d)", packet.headerId(), packet.length());
}
}
this.description = description;
this.packetsAsString = packetsAsString;
}
public InjectedPackets(String fromString) {
constructFromString(fromString);
}
public String getPacketsAsString() {
return packetsAsString;
}
public String getDescription() {
return description;
}
@Override
public String stringify() {
Map<String, String> info = new HashMap<>();
info.put("packetsAsString", packetsAsString);
info.put("description", description);
return new JSONObject(info).toString();
}
@Override
public void constructFromString(String str) {
JSONObject jsonObject = new JSONObject(str);
this.packetsAsString = jsonObject.getString("packetsAsString");
this.description = jsonObject.getString("description");
}
@Override
public String toString() {
return description;
}
}

View File

@ -1,25 +1,42 @@
package gearth.ui.injection;
import gearth.misc.Cacher;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import gearth.protocol.connection.HState;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.event.EventHandler;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text;
import gearth.protocol.HConnection;
import gearth.protocol.HPacket;
import gearth.ui.SubForm;
import sun.misc.Cache;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class InjectionController extends SubForm {
private static final String HISTORY_CACHE_KEY = "INJECTED_HISTORY";
private static final int historylimit = 69;
public TextArea inputPacket;
public Text lbl_corrruption;
public Text lbl_pcktInfo;
public Button btn_sendToServer;
public Button btn_sendToClient;
public ListView<InjectedPackets> history;
public Label lblHistory;
protected void onParentSet() {
getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(this::updateUI));
@ -27,6 +44,29 @@ public class InjectionController extends SubForm {
inputPacket.textProperty().addListener(event -> Platform.runLater(this::updateUI));
}
public void initialize() {
history.setOnMouseClicked(event -> {
if(event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
InjectedPackets injectedPackets = history.getSelectionModel().getSelectedItem();
if (injectedPackets != null) {
Platform.runLater(() -> {
inputPacket.setText(injectedPackets.getPacketsAsString());
updateUI();
});
}
}
});
lblHistory.setTooltip(new Tooltip("Double click a packet to restore it"));
List<Object> rawHistory = Cacher.getList(HISTORY_CACHE_KEY);
if (rawHistory != null) {
List<InjectedPackets> history = rawHistory.stream()
.map(o -> (String)o).limit(historylimit - 1).map(InjectedPackets::new).collect(Collectors.toList());
updateHistoryView(history);
}
}
private static boolean isPacketIncomplete(String line) {
boolean unmatchedBrace = false;
@ -95,9 +135,38 @@ public class InjectionController extends SubForm {
}
if (!dirty) {
btn_sendToClient.setDisable(getHConnection().getState() != HState.CONNECTED);
btn_sendToServer.setDisable(getHConnection().getState() != HState.CONNECTED);
PacketInfoManager packetInfoManager = getHConnection().getPacketInfoManager();
List<String> unIdentifiedPackets = Arrays.stream(packets)
.filter(hPacket -> !hPacket.isPacketComplete())
.map(HPacket::getIdentifier).collect(Collectors.toList());
boolean canSendToClient = unIdentifiedPackets.stream().allMatch(s -> {
if (packetInfoManager == null) return false;
return packetInfoManager.getPacketInfoFromHash(HMessage.Direction.TOCLIENT, s) != null ||
packetInfoManager.getPacketInfoFromName(HMessage.Direction.TOCLIENT, s) != null;
});
boolean canSendToServer = unIdentifiedPackets.stream().allMatch(s -> {
if (packetInfoManager == null) return false;
return packetInfoManager.getPacketInfoFromHash(HMessage.Direction.TOSERVER, s) != null ||
packetInfoManager.getPacketInfoFromName(HMessage.Direction.TOSERVER, s) != null;
});
btn_sendToClient.setDisable(!canSendToClient || getHConnection().getState() != HState.CONNECTED);
btn_sendToServer.setDisable(!canSendToServer || getHConnection().getState() != HState.CONNECTED);
if (packets.length == 1) {
// complete packet to show correct headerId
if (!packets[0].isPacketComplete()) {
HPacket packet = packets[0];
if (packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && !packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOCLIENT, packetInfoManager);
}
else if (!packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOSERVER, packetInfoManager);
}
}
lbl_pcktInfo.setText("header (id:" + packets[0].headerId() + ", length:" +
packets[0].length() + ")");
}
@ -124,6 +193,8 @@ public class InjectionController extends SubForm {
getHConnection().sendToServerAsync(packet);
writeToLog(Color.BLUE, "SS -> packet with id: " + packet.headerId());
}
addToHistory(packets, inputPacket.getText(), HMessage.Direction.TOSERVER);
}
public void sendToClient_clicked(ActionEvent actionEvent) {
@ -132,6 +203,40 @@ public class InjectionController extends SubForm {
getHConnection().sendToClientAsync(packet);
writeToLog(Color.RED, "CS -> packet with id: " + packet.headerId());
}
addToHistory(packets, inputPacket.getText(), HMessage.Direction.TOCLIENT);
}
private void addToHistory(HPacket[] packets, String packetsAsString, HMessage.Direction direction) {
InjectedPackets injectedPackets = new InjectedPackets(packetsAsString, packets.length, getHConnection().getPacketInfoManager(), direction);
List<InjectedPackets> newHistory = new ArrayList<>();
newHistory.add(injectedPackets);
List<Object> rawOldHistory = Cacher.getList(HISTORY_CACHE_KEY);
if (rawOldHistory != null) {
List<InjectedPackets> history = rawOldHistory.stream()
.map(o -> (String)o).limit(historylimit - 1).map(InjectedPackets::new).collect(Collectors.toList());
// dont add to history if its equal to the latest added packet
if (history.size() != 0 && history.get(0).getPacketsAsString().equals(injectedPackets.getPacketsAsString())) {
return;
}
newHistory.addAll(history);
}
List<String> historyAsStrings = newHistory.stream().map(InjectedPackets::stringify).collect(Collectors.toList());
Cacher.put(HISTORY_CACHE_KEY, historyAsStrings);
updateHistoryView(newHistory);
}
private void updateHistoryView(List<InjectedPackets> allHistoryItems) {
Platform.runLater(() -> {
history.getItems().clear();
history.getItems().addAll(allHistoryItems);
});
}

View File

@ -1,6 +1,8 @@
package gearth.ui.logger;
import gearth.extensions.parsers.HDirection;
import gearth.protocol.connection.HState;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducer;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
@ -17,6 +19,7 @@ import gearth.ui.logger.loggerdisplays.PacketLogger;
import gearth.ui.logger.loggerdisplays.PacketLoggerFactory;
import java.util.Calendar;
import java.util.function.Predicate;
public class LoggerController extends SubForm {
@ -33,16 +36,20 @@ public class LoggerController extends SubForm {
private int packetLimit = 8000;
private PacketLogger packetLogger = PacketLoggerFactory.get();
private PacketLoggerFactory packetLoggerFactory;
private PacketLogger packetLogger;
public void onParentSet(){
packetLoggerFactory = new PacketLoggerFactory(parentController.extensionsController.getExtensionHandler());
packetLogger = packetLoggerFactory.get();
getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(() -> {
if (newState == HState.PREPARING) {
miniLogText(Color.ORANGE, "Connecting to "+getHConnection().getDomain() + ":" + getHConnection().getServerPort());
}
if (newState == HState.CONNECTED) {
miniLogText(Color.GREEN, "Connected to "+getHConnection().getDomain() + ":" + getHConnection().getServerPort());
packetLogger.start();
packetLogger.start(getHConnection());
}
if (newState == HState.NOT_CONNECTED) {
miniLogText(Color.RED, "End of connection");
@ -69,7 +76,7 @@ public class LoggerController extends SubForm {
packetLogger.appendMessage(message.getPacket(), types);
if (cbx_showstruct.isSelected() && message.getPacket().length() < packetLimit) {
packetLogger.appendStructure(message.getPacket());
packetLogger.appendStructure(message.getPacket(), message.getDestination());
}
});
});

View File

@ -1,5 +1,6 @@
package gearth.ui.logger.loggerdisplays;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.util.HashMap;
@ -60,8 +61,8 @@ class LinuxTerminalLogger extends SimpleTerminalLogger {
}
@Override
public void appendStructure(HPacket packet) {
String expr = packet.toExpression();
public void appendStructure(HPacket packet, HMessage.Direction direction) {
String expr = packet.toExpression(direction, packetInfoManager, true);
if (!expr.equals("")) {
System.out.println(
colorizePackets.get("EXPRESSION") +

View File

@ -1,5 +1,7 @@
package gearth.ui.logger.loggerdisplays;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
/**
@ -27,11 +29,11 @@ public interface PacketLogger {
}
}
void start();
void start(HConnection hConnection);
void stop();
void appendSplitLine();
void appendMessage(HPacket packet, int types);
void appendStructure(HPacket packet);
void appendStructure(HPacket packet, HMessage.Direction direction);
}

View File

@ -1,21 +1,33 @@
package gearth.ui.logger.loggerdisplays;
import gearth.Main;
import gearth.extensions.InternalExtensionFormBuilder;
import gearth.misc.OSValidator;
import gearth.ui.logger.loggerdisplays.uilogger.UiLogger;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extensionhandler.extensions.extensionproducers.ExtensionProducerObserver;
import gearth.services.internal_extensions.uilogger.UiLogger;
/**
* Created by Jonas on 04/04/18.
*/
public class PacketLoggerFactory {
public class PacketLoggerFactory implements ExtensionProducer {
private UiLogger uiLogger;
public static boolean usesUIlogger() {
return (!Main.hasFlag("-t"));
}
public static PacketLogger get() {
public PacketLoggerFactory(ExtensionHandler handler) {
handler.addExtensionProducer(this);
}
public PacketLogger get() {
if (usesUIlogger()) {
return new UiLogger();
// return new UiLogger(); //now an extension
return uiLogger;
}
if (OSValidator.isUnix()) {
@ -24,4 +36,11 @@ public class PacketLoggerFactory {
return new SimpleTerminalLogger();
}
@Override
public void startProducing(ExtensionProducerObserver observer) {
if (usesUIlogger()) {
uiLogger = new InternalExtensionFormBuilder<UiLogger>()
.launch(UiLogger.class, observer);
}
}
}

View File

@ -1,13 +1,20 @@
package gearth.ui.logger.loggerdisplays;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
/**
* Created by Jonas on 04/04/18.
*/
class SimpleTerminalLogger implements PacketLogger {
protected PacketInfoManager packetInfoManager = null;
@Override
public void start() {
public void start(HConnection hConnection) {
packetInfoManager = hConnection.getPacketInfoManager();
// System.out.println("-- START OF SESSION --");
}
@ -53,8 +60,8 @@ class SimpleTerminalLogger implements PacketLogger {
}
@Override
public void appendStructure(HPacket packet) {
String expr = packet.toExpression();
public void appendStructure(HPacket packet, HMessage.Direction direction) {
String expr = packet.toExpression(direction, packetInfoManager, true);
if (!expr.equals("")) {
System.out.println(expr);
}

View File

@ -1,116 +0,0 @@
package gearth.ui.logger.loggerdisplays.uilogger;
import gearth.protocol.HPacket;
import gearth.ui.logger.loggerdisplays.PacketLogger;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class UiLogger implements PacketLogger {
private Stage stage;
private UiLoggerController controller = null;
@Override
public void start() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/gearth/ui/logger/uilogger/UiLogger.fxml"));
try {
Parent root = loader.load();
synchronized (appendLater) {
controller = loader.getController();
for (Elem elem : appendLater) {
controller.appendMessage(elem.packet, elem.types);
}
appendLater.clear();
}
stage = new Stage();
stage.setTitle("G-Earth | Packet Logger");
stage.initModality(Modality.NONE);
stage.getIcons().add(new Image(getClass().getResourceAsStream("/gearth/G-EarthLogoSmaller.png")));
Scene scene = new Scene(root);
scene.getStylesheets().add("/gearth/ui/bootstrap3.css");
scene.getStylesheets().add("/gearth/ui/logger/uilogger/logger.css");
UiLoggerController controller = (UiLoggerController) loader.getController();
controller.setStage(stage);
// scene.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
// final KeyCombination keyCombIncoming = new KeyCodeCombination(KeyCode.I,
// KeyCombination.CONTROL_DOWN);
// final KeyCombination keyCombOutgoing = new KeyCodeCombination(KeyCode.O,
// KeyCombination.CONTROL_DOWN);
//
// public void handle(KeyEvent ke) {
// if (keyCombIncoming.match(ke)) {
// controller.toggleViewIncoming();
// ke.consume();
// } else if (keyCombOutgoing.match(ke)) {
// controller.toggleViewOutgoing();
// ke.consume();
// }
// }
// });
stage.setScene(scene);
// ScenicView.show(scene);
// don't let the user close this window on their own
stage.setOnCloseRequest(Event::consume);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
if (stage != null)
stage.close();
}
@Override
public void appendSplitLine() {
// don't use this, we can't discern incoming/outgoing
//Platform.runLater(() -> controller.appendSplitLine());
}
private class Elem {
HPacket packet;
int types;
Elem(HPacket packet, int types) {
this.packet = packet;
this.types = types;
}
}
private final List<Elem> appendLater = new ArrayList<>();
@Override
public void appendMessage(HPacket packet, int types) {
synchronized (appendLater) {
if (controller == null) {
appendLater.add(new Elem(packet, types));
}
else {
controller.appendMessage(packet, types);
}
}
}
@Override
public void appendStructure(HPacket packet) {
}
}

View File

@ -1,239 +0,0 @@
package gearth.ui.logger.loggerdisplays.uilogger;
import gearth.misc.harble_api.HarbleAPI;
import gearth.misc.harble_api.HarbleAPIFetcher;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.ui.logger.loggerdisplays.PacketLogger;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import java.net.URL;
import java.util.*;
public class UiLoggerController implements Initializable {
public FlowPane flowPane;
public BorderPane borderPane;
public Label lblViewIncoming;
public Label lblViewOutgoing;
public CheckMenuItem chkViewIncoming;
public CheckMenuItem chkViewOutgoing;
public CheckMenuItem chkDisplayStructure;
public Label lblAutoScrolll;
public CheckMenuItem chkAutoscroll;
public CheckMenuItem chkSkipBigPackets;
public CheckMenuItem chkMessageName;
public CheckMenuItem chkMessageHash;
public Label lblHarbleAPI;
private StyleClassedTextArea area;
private Stage stage;
private boolean viewIncoming = true;
private boolean viewOutgoing = true;
private boolean displayStructure = true;
private boolean autoScroll = true;
private boolean skiphugepackets = true;
private boolean viewMessageName = true;
private boolean viewMessageHash = false;
private boolean alwaysOnTop = false;
private volatile boolean initialized = false;
private final List<Element> appendLater = new ArrayList<>();
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
area = new StyleClassedTextArea();
area.getStyleClass().add("dark");
area.setWrapText(true);
VirtualizedScrollPane<StyleClassedTextArea> vsPane = new VirtualizedScrollPane<>(area);
borderPane.setCenter(vsPane);
synchronized (appendLater) {
initialized = true;
if (!appendLater.isEmpty()) {
appendLog(appendLater);
appendLater.clear();
}
}
}
private static String cleanTextContent(String text) {
// // strips off all non-ASCII characters
// text = text.replaceAll("[^\\x00-\\x7F]", "");
//
// // erases all the ASCII control characters
text = text.replaceAll("[\\p{Cntrl}&&[^\n\t]]", "");
// removes non-printable characters from Unicode
// text = text.replaceAll("\\p{C}", "");
return text.trim();
}
public void appendMessage(HPacket packet, int types) {
boolean isBlocked = (types & PacketLogger.MESSAGE_TYPE.BLOCKED.getValue()) != 0;
boolean isReplaced = (types & PacketLogger.MESSAGE_TYPE.REPLACED.getValue()) != 0;
boolean isIncoming = (types & PacketLogger.MESSAGE_TYPE.INCOMING.getValue()) != 0;
if (isIncoming && !viewIncoming) return;
if (!isIncoming && !viewOutgoing) return;
ArrayList<Element> elements = new ArrayList<>();
lblHarbleAPI.setText("Messages: " + (HarbleAPIFetcher.HARBLEAPI == null ? "False" : "True"));
if ((viewMessageName || viewMessageHash) && HarbleAPIFetcher.HARBLEAPI != null) {
HarbleAPI api = HarbleAPIFetcher.HARBLEAPI;
HarbleAPI.HarbleMessage message = api.getHarbleMessageFromHeaderId(
(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER),
packet.headerId()
);
if ( message != null && !(viewMessageName && !viewMessageHash && message.getName() == null)) {
if (viewMessageName && message.getName() != null) {
elements.add(new Element("["+message.getName()+"]", "messageinfo"));
}
if (viewMessageHash) {
elements.add(new Element("["+message.getHash()+"]", "messageinfo"));
}
elements.add(new Element("\n", ""));
}
}
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked"));
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced"));
if (isIncoming) {
// handle skipped eventually
elements.add(new Element("Incoming[", "incoming"));
elements.add(new Element(String.valueOf(packet.headerId()), ""));
elements.add(new Element("]", "incoming"));
elements.add(new Element(" <- ", ""));
if (skiphugepackets && packet.length() > 4000) {
elements.add(new Element("<packet skipped>", "skipped"));
}
else {
elements.add(new Element(packet.toString(), "incoming"));
}
} else {
elements.add(new Element("Outgoing[", "outgoing"));
elements.add(new Element(String.valueOf(packet.headerId()), ""));
elements.add(new Element("]", "outgoing"));
elements.add(new Element(" -> ", ""));
if (skiphugepackets && packet.length() > 8000) {
elements.add(new Element("<packet skipped>", "skipped"));
}
else {
elements.add(new Element(packet.toString(), "outgoing"));
}
}
if (packet.length() <= 2000) {
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER);
String cleaned = cleanTextContent(expr);
if (cleaned.equals(expr)) {
if (!expr.equals("") && displayStructure)
elements.add(new Element("\n" + cleanTextContent(expr), "structure"));
}
}
elements.add(new Element("\n--------------------\n", ""));
synchronized (appendLater) {
if (initialized) {
appendLog(elements);
}
else {
appendLater.addAll(elements);
}
}
}
private synchronized void appendLog(List<Element> elements) {
Platform.runLater(() -> {
StringBuilder sb = new StringBuilder();
StyleSpansBuilder<Collection<String>> styleSpansBuilder = new StyleSpansBuilder<>(0);
for (Element element : elements) {
sb.append(element.text);
styleSpansBuilder.add(Collections.singleton(element.className), element.text.length());
}
int oldLen = area.getLength();
area.appendText(sb.toString());
// System.out.println(sb.toString());
area.setStyleSpans(oldLen, styleSpansBuilder.create());
if (autoScroll) {
// area.moveTo(area.getLength());
area.requestFollowCaret();
}
});
}
public void setStage(Stage stage) {
this.stage = stage;
}
public void toggleViewIncoming() {
viewIncoming = !viewIncoming;
lblViewIncoming.setText("View Incoming: " + (viewIncoming ? "True" : "False"));
// chkViewIncoming.setSelected(viewIncoming);
}
public void toggleViewOutgoing() {
viewOutgoing = !viewOutgoing;
lblViewOutgoing.setText("View Outgoing: " + (viewOutgoing ? "True" : "False"));
// chkViewOutgoing.setSelected(viewOutgoing);
}
public void toggleDisplayStructure() {
displayStructure = !displayStructure;
// chkDisplayStructure.setSelected(displayStructure);
}
public void toggleAutoscroll(ActionEvent actionEvent) {
autoScroll = !autoScroll;
lblAutoScrolll.setText("Autoscroll: " + (autoScroll ? "True" : "False"));
}
public void toggleSkipPackets(ActionEvent actionEvent) {
skiphugepackets = !skiphugepackets;
}
public void toggleMessageName(ActionEvent actionEvent) {
viewMessageName = !viewMessageName;
}
public void toggleMessageHash(ActionEvent actionEvent) {
viewMessageHash = !viewMessageHash;
}
public void toggleAlwaysOnTop(ActionEvent actionEvent) {
stage.setAlwaysOnTop(!alwaysOnTop);
alwaysOnTop = !alwaysOnTop;
}
public void clearText(ActionEvent actionEvent) {
area.clear();
}
}

View File

@ -72,8 +72,8 @@ public class InteractableScheduleItem extends ScheduleItem implements StringifyA
.append("\t")
.append(getDelayProperty().get().toString())
.append("\t")
.append(getPacketProperty().get().toString())
.append("\t")
// .append(getPacketProperty().get().toString())
// .append("\t")
.append(getDestinationProperty().get().name())
.append("\t")
.append(getPacketAsStringProperty().get());
@ -87,9 +87,10 @@ public class InteractableScheduleItem extends ScheduleItem implements StringifyA
int index = Integer.parseInt(parts[0]);
boolean paused = parts[1].equals("true");
Interval delay = new Interval(parts[2]);
HPacket packet = new HPacket(parts[3]);
HMessage.Direction direction = parts[4].equals(HMessage.Direction.TOSERVER.name()) ? HMessage.Direction.TOSERVER : HMessage.Direction.TOCLIENT;
String packetAsString = parts[5];
// HPacket packet = new HPacket(parts[3]);
HMessage.Direction direction = parts[3].equals(HMessage.Direction.TOSERVER.name()) ? HMessage.Direction.TOSERVER : HMessage.Direction.TOCLIENT;
String packetAsString = parts[4];
HPacket packet = new HPacket(packetAsString);
construct(index, paused, delay, packet, direction);
this.packetAsStringProperty = new SimpleStringProperty(packetAsString);

View File

@ -216,7 +216,6 @@ public class SchedulerController extends SubForm {
File file = fileChooser.showSaveDialog(parentController.getStage());
if(file != null){
try {
FileWriter fileWriter = new FileWriter(file);
BufferedWriter out = new BufferedWriter(fileWriter);

View File

@ -1,5 +1,7 @@
package gearth.ui.tools;
import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
@ -138,11 +140,26 @@ public class ToolsController extends SubForm {
}
private HPacket parseToPacket(String p) {
PacketInfoManager packetInfoManager = getHConnection().getPacketInfoManager();
HPacket packet = new HPacket(p);
if (!packet.isPacketComplete() && packetInfoManager != null) {
if (packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && !packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOCLIENT, packetInfoManager);
}
else if (!packet.canComplete(HMessage.Direction.TOCLIENT, packetInfoManager) && packet.canComplete(HMessage.Direction.TOSERVER, packetInfoManager)) {
packet.completePacket(HMessage.Direction.TOSERVER, packetInfoManager);
}
}
return packet;
}
public void btn_toExpr_clicked(ActionEvent actionEvent) {
txt_exprArea.setText(new HPacket(txt_packetArea.getText()).toExpression());
txt_exprArea.setText(parseToPacket(txt_packetArea.getText()).toExpression(getHConnection().getPacketInfoManager(), true));
}
public void btn_toPacket_clicked(ActionEvent actionEvent) {
txt_packetArea.setText(new HPacket(txt_exprArea.getText()).toString());
txt_packetArea.setText(parseToPacket(txt_exprArea.getText()).toString());
}
}

View File

@ -1,17 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<GridPane prefHeight="324.0" prefWidth="588.0" style="-fx-background-color: #FFFFFF;" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="extensions.blockreplacepackets.BlockAndReplacePackets">
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane prefHeight="324.0" prefWidth="588.0" style="-fx-background-color: #FFFFFF;" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.services.internal_extensions.blockreplacepackets.BlockAndReplacePackets">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="grid" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="442.0" prefWidth="620.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.services.internal_extensions.packetinfoexplorer.PacketInfoExplorer">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" prefHeight="360.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane style="-fx-border-width: 1px 0 0 0; -fx-border-color: #bbb;">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="105.0" minWidth="105.0" prefWidth="105.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="245.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="20.0" minHeight="20.0" prefHeight="20.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<children>
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Filter headerId:" textFill="#000000d3" />
<TextField fx:id="txt_filterHeaderId" GridPane.rowIndex="1" />
</children>
</GridPane>
<GridPane style="-fx-border-color: #bbb; -fx-border-width: 0 0 0 1px;" GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="20.0" minHeight="20.0" prefHeight="20.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<children>
<TextField fx:id="txt_filterNameHash" GridPane.rowIndex="1" />
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Filter name or hash:" textFill="#000000d3" />
</children>
</GridPane>
<GridPane prefHeight="100.0" prefWidth="101.0" style="-fx-border-color: #bbb; -fx-border-width: 0 0 0 1px;" GridPane.columnIndex="3">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="78.0" minHeight="10.0" prefHeight="70.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane fx:id="source_grid" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Filter source:" textFill="#000000d3" />
</children>
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</GridPane>
<GridPane style="-fx-border-width: 0 0 0 1px; -fx-border-color: #bbb;" GridPane.columnIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<CheckBox fx:id="chk_toClient" mnemonicParsing="false" selected="true" text="TOCLIENT" />
<CheckBox fx:id="chk_toServer" layoutX="10.0" layoutY="17.0" mnemonicParsing="false" selected="true" text="TOSERVER" GridPane.rowIndex="1" />
</children>
</GridPane>
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Filter direction:" textFill="#000000d3" />
</children>
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</GridPane>
</children>
</GridPane>
</children>
</GridPane>

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.input.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" prefHeight="560.0" prefWidth="820.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.services.internal_extensions.uilogger.UiLoggerController">
<top>
<MenuBar BorderPane.alignment="CENTER">
<Menu mnemonicParsing="false" text="Window">
<items>
<CheckMenuItem fx:id="chkAlwaysOnTop" mnemonicParsing="false" onAction="#toggleAlwaysOnTop" text="Always on top" />
<Menu mnemonicParsing="false" text="On connect">
<items>
<CheckMenuItem fx:id="chkOpenOnConnect" mnemonicParsing="false" selected="true" text="Open window" />
<CheckMenuItem fx:id="chkResetOnConnect" mnemonicParsing="false" selected="true" text="Reset packetlogger" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="On disconnect">
<items>
<CheckMenuItem fx:id="chkHideOnDisconnect" mnemonicParsing="false" selected="true" text="Hide window" />
<CheckMenuItem fx:id="chkResetOnDisconnect" mnemonicParsing="false" text="Reset packetlogger" />
</items>
</Menu>
</items>
</Menu>
<Menu mnemonicParsing="false" text="View">
<CheckMenuItem fx:id="chkViewIncoming" mnemonicParsing="false" selected="true" text="View Incoming">
<accelerator>
<KeyCodeCombination alt="UP" code="I" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<CheckMenuItem fx:id="chkViewOutgoing" mnemonicParsing="false" selected="true" text="View Outgoing">
<accelerator>
<KeyCodeCombination alt="UP" code="O" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<CheckMenuItem fx:id="chkAutoscroll" mnemonicParsing="false" selected="true" text="Autoscroll">
<accelerator>
<KeyCodeCombination alt="UP" code="L" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<MenuItem mnemonicParsing="false" onAction="#clearText" text="Clear text">
<accelerator>
<KeyCodeCombination alt="UP" code="E" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></MenuItem>
</Menu>
<Menu mnemonicParsing="false" text="Packets">
<items>
<Menu mnemonicParsing="false" text="Display Details">
<items>
<CheckMenuItem fx:id="chkDisplayStructure" mnemonicParsing="false" selected="true" text="Structure" />
<CheckMenuItem fx:id="chkMessageName" mnemonicParsing="false" selected="true" text="Message Name" />
<CheckMenuItem fx:id="chkMessageHash" mnemonicParsing="false" text="Message Hash" />
<CheckMenuItem fx:id="chkUseNewStructures" mnemonicParsing="false" selected="true" text="New structures" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Anti-spam filter">
<items>
<RadioMenuItem fx:id="chkAntiSpam_none" mnemonicParsing="false" selected="true" text="None">
<toggleGroup>
<ToggleGroup fx:id="antispam" />
</toggleGroup>
</RadioMenuItem>
<RadioMenuItem fx:id="chkAntiSpam_low" mnemonicParsing="false" text="Low" toggleGroup="$antispam" />
<RadioMenuItem fx:id="chkAntiSpam_medium" mnemonicParsing="false" text="Medium" toggleGroup="$antispam" />
<RadioMenuItem fx:id="chkAntiSpam_high" mnemonicParsing="false" text="High" toggleGroup="$antispam" />
<RadioMenuItem fx:id="chkAntiSpam_ultra" mnemonicParsing="false" text="Ultra" toggleGroup="$antispam" />
</items>
</Menu>
<CheckMenuItem fx:id="chkSkipBigPackets" mnemonicParsing="false" selected="true" text="Skip big packets" />
<MenuItem mnemonicParsing="false" onAction="#exportAll" text="Export all" />
</items>
</Menu>
</MenuBar>
</top>
<bottom>
<FlowPane fx:id="flowPane" prefHeight="20.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<padding>
<Insets left="10.0" top="1.0" />
</padding>
<Label fx:id="lblViewIncoming" style="-fx-text-fill: black !important" text="View Incoming: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblViewOutgoing" style="-fx-text-fill: black !important" text="View Outgoing: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label layoutX="138.0" layoutY="11.0" text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblAutoScrolll" layoutX="151.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Autoscroll: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin></Label>
<Label layoutX="270.0" layoutY="11.0" text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblPacketInfo" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Packet info: False">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label layoutX="270.0" layoutY="11.0" text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblFiltered" layoutX="389.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Filtered: 0" />
</FlowPane>
</bottom>
</BorderPane>

View File

@ -1,19 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
@ -148,7 +140,7 @@
<RowConstraints minHeight="20.0" prefHeight="34.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Client type:">
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Client type:" textFill="#000000cd">
<padding>
<Insets left="12.0" />
</padding>

View File

@ -11,7 +11,7 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/8.0.241" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="331.0" minWidth="10.0" prefWidth="318.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="10.0" prefWidth="247.0" />

View File

@ -65,6 +65,11 @@
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="214.0" text="Mikee#0055" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="491.0" layoutY="94.0" text="Links:" textFill="#000000b2">
<font>
<Font name="System Bold" size="14.0" />

View File

@ -1,81 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.text.TextFlow?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="gearth.ui.injection.InjectionController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="232.0" minHeight="10.0" prefHeight="36.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="232.0" minHeight="10.0" prefHeight="194.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="121.0" minHeight="10.0" prefHeight="32.0" vgrow="SOMETIMES"/>
</rowConstraints>
<padding>
<Insets bottom="7.0"/>
</padding>
<GridPane GridPane.rowIndex="0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<GridPane prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.injection.InjectionController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="180.0" prefWidth="180.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="32.0" minHeight="32.0" prefHeight="32.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="232.0" minHeight="10.0" prefHeight="194.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="121.0" minHeight="10.0" prefHeight="32.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="7.0" />
</padding>
<GridPane GridPane.rowIndex="0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane.margin>
<Insets left="13.0" right="13.0" top="4.0" />
</GridPane.margin>
<Text fx:id="lbl_corrruption" fill="#ee0404b2" strokeType="OUTSIDE" strokeWidth="0.0" text="isCorrupted: True">
<font>
<Font name="System Italic" size="11.0" />
</font>
</Text>
<Text fx:id="lbl_pcktInfo" fill="#000000b2" nodeOrientation="LEFT_TO_RIGHT" strokeType="OUTSIDE" strokeWidth="0.0" text="header (id:NULL, length:0)" GridPane.columnIndex="1" GridPane.halignment="RIGHT">
<font>
<Font name="System Italic" size="11.0" />
</font>
</Text>
</GridPane>
<TextArea fx:id="inputPacket" prefHeight="185.0" prefWidth="545.0" wrapText="true" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0" />
</GridPane.margin>
</TextArea>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<Button fx:id="btn_sendToServer" disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#sendToServer_clicked" text="Send to server" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
</GridPane.margin>
</Button>
<Button fx:id="btn_sendToClient" disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#sendToClient_clicked" text="Send to client" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0" />
</GridPane.margin>
</Button>
</GridPane>
<GridPane.margin>
<Insets />
</GridPane.margin>
</GridPane>
<GridPane GridPane.columnIndex="1">
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="32.0" minHeight="32.0" prefHeight="32.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane.margin>
<Insets left="13.0" right="13.0" top="4.0"/>
</GridPane.margin>
<Text fx:id="lbl_corrruption" fill="#ee0404b2" strokeType="OUTSIDE" strokeWidth="0.0"
text="isCorrupted: True">
<font>
<Font name="System Italic" size="11.0"/>
</font>
</Text>
<Text fx:id="lbl_pcktInfo" fill="#000000b2" nodeOrientation="LEFT_TO_RIGHT" strokeType="OUTSIDE"
strokeWidth="0.0" text="header (id:NULL, length:0)" GridPane.columnIndex="1"
GridPane.halignment="RIGHT">
<font>
<Font name="System Italic" size="11.0"/>
</font>
</Text>
</GridPane>
<TextArea fx:id="inputPacket" prefHeight="185.0" prefWidth="545.0" wrapText="true" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0"/>
</GridPane.margin>
</TextArea>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<Button fx:id="btn_sendToServer" disable="true" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#sendToServer_clicked"
text="Send to server" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0"/>
</GridPane.margin>
</Button>
<Button fx:id="btn_sendToClient" disable="true" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#sendToClient_clicked"
text="Send to client" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="5.0" left="10.0" right="10.0" top="5.0"/>
</GridPane.margin>
</Button>
</GridPane>
<children>
<ListView fx:id="history" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1" />
<Label fx:id="lblHistory" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="History:" textFill="#000000cc">
<GridPane.margin>
<Insets top="4.0" />
</GridPane.margin>
</Label>
</children>
<GridPane.margin>
<Insets bottom="5.0" left="6.0" right="10.0" />
</GridPane.margin>
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
</GridPane>
</children>
</GridPane>

View File

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckMenuItem?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.input.KeyCodeCombination?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.FlowPane?>
<BorderPane fx:id="borderPane" prefHeight="560.0" prefWidth="820.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.logger.loggerdisplays.uilogger.UiLoggerController">
<top>
<MenuBar BorderPane.alignment="CENTER">
<Menu mnemonicParsing="false" text="View">
<Menu mnemonicParsing="false" text="Display Details">
<items>
<CheckMenuItem fx:id="chkDisplayStructure" mnemonicParsing="false" onAction="#toggleDisplayStructure" selected="true" text="Structure" />
<CheckMenuItem fx:id="chkMessageName" mnemonicParsing="false" onAction="#toggleMessageName" selected="true" text="Message Name" />
<CheckMenuItem fx:id="chkMessageHash" mnemonicParsing="false" onAction="#toggleMessageHash" text="Message Hash" />
</items>
</Menu>
<CheckMenuItem fx:id="chkViewIncoming" mnemonicParsing="false" onAction="#toggleViewIncoming" selected="true" text="View Incoming">
<accelerator>
<KeyCodeCombination alt="UP" code="I" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<CheckMenuItem fx:id="chkViewOutgoing" mnemonicParsing="false" onAction="#toggleViewOutgoing" selected="true" text="View Outgoing">
<accelerator>
<KeyCodeCombination alt="UP" code="O" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<CheckMenuItem fx:id="chkAutoscroll" mnemonicParsing="false" onAction="#toggleAutoscroll" selected="true" text="Autoscroll">
<accelerator>
<KeyCodeCombination alt="UP" code="L" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
<CheckMenuItem fx:id="chkSkipBigPackets" mnemonicParsing="false" onAction="#toggleSkipPackets" selected="true" text="Skip big packets" />
<CheckMenuItem fx:id="chkAlwaysOnTop" mnemonicParsing="false" onAction="#toggleAlwaysOnTop" text="Always on top" />
<CheckMenuItem fx:id="chkClearText" mnemonicParsing="false" onAction="#clearText" text="Clear text">
<accelerator>
<KeyCodeCombination alt="UP" code="E" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></CheckMenuItem>
</Menu>
</MenuBar>
</top>
<bottom>
<FlowPane fx:id="flowPane" prefHeight="20.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<padding>
<Insets left="10.0" top="1.0" />
</padding>
<Label fx:id="lblViewIncoming" style="-fx-text-fill: black !important" text="View Incoming: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblViewOutgoing" style="-fx-text-fill: black !important" text="View Outgoing: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label layoutX="138.0" layoutY="11.0" text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblAutoScrolll" layoutX="151.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Autoscroll: True">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin></Label>
<Label layoutX="270.0" layoutY="11.0" text="|">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblHarbleAPI" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Messages: False">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>
</Label>
</FlowPane>
</bottom>
</BorderPane>

View File

@ -7,7 +7,7 @@
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<packaging>pom</packaging>
<version>1.3.4</version>
<version>1.4</version>
<name>G-Earth-Parent</name>
<url>https://github.com/sirjonasxx/G-Earth</url>
@ -18,7 +18,6 @@
<!-- Compile our extensions too please! -->
<module>Extensions/AdminOnConnect</module>
<module>Extensions/BlockReplacePackets</module>
</modules>
<build>