mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2025-02-20 13:02:36 +01:00
Merge branch 'development'
This commit is contained in:
commit
36f844d6dc
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
130
G-Earth/src/main/java/gearth/extensions/ExtensionBase.java
Normal file
130
G-Earth/src/main/java/gearth/extensions/ExtensionBase.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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, "");
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.extensions.extra.harble;
|
||||
package gearth.extensions.extra.tools;
|
||||
|
||||
public interface ChatInputListener {
|
||||
void inputEntered(String input);
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -2,6 +2,6 @@ package gearth.protocol.packethandler.flash;
|
||||
|
||||
public interface OnDatastreamConfirmedListener {
|
||||
|
||||
void confirm(String hotelVersion, String clientType);
|
||||
void confirm(String hotelVersion, String clientIdentifier);
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package gearth.services.extensionhandler.extensions;
|
||||
|
||||
public enum ExtensionType {
|
||||
INTERNAL,
|
||||
EXTERNAL
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package extensions.blockreplacepackets.rules;
|
||||
package gearth.services.internal_extensions.blockreplacepackets.rules;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package extensions.blockreplacepackets.rules;
|
||||
package gearth.services.internal_extensions.blockreplacepackets.rules;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import javafx.beans.InvalidationListener;
|
@ -1,4 +1,4 @@
|
||||
package extensions.blockreplacepackets.rules;
|
||||
package gearth.services.internal_extensions.blockreplacepackets.rules;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
@ -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 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package extensions.blockreplacepackets.rules;
|
||||
package gearth.services.internal_extensions.blockreplacepackets.rules;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package extensions.blockreplacepackets.rules;
|
||||
package gearth.services.internal_extensions.blockreplacepackets.rules;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gearth.ui.logger.loggerdisplays.uilogger;
|
||||
package gearth.services.internal_extensions.uilogger;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 17/11/2018.
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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 + "]";
|
||||
}
|
||||
}
|
@ -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<>());
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation;
|
||||
package gearth.services.packetrepresentation;
|
||||
|
||||
public class InvalidPacketException extends Exception {
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
package gearth.services.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -133,4 +133,8 @@ public class ExtensionsController extends SubForm {
|
||||
Platform.runLater(this::updateGPythonStatus);
|
||||
});
|
||||
}
|
||||
|
||||
public ExtensionHandler getExtensionHandler() {
|
||||
return extensionHandler;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -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") +
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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>
|
3
pom.xml
3
pom.xml
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user