Merge remote-tracking branch 'origin/master' into windowsSupport
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.idea/
|
||||
out/
|
||||
G-Earth2.iml
|
||||
Extensions/
|
||||
|
3
src/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: main.extensions.examples.adminonconnect.AdminOnConnect
|
||||
|
BIN
src/json-simple-1.1.1.jar
Normal file
@ -1,6 +1,7 @@
|
||||
package main;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
@ -17,7 +18,6 @@ public class Main extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception{
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(GEarthController.class.getResource("G-Earth.fxml"));
|
||||
Parent root = loader.load();
|
||||
|
||||
@ -29,11 +29,11 @@ public class Main extends Application {
|
||||
primaryStage.setTitle("G-Earth");
|
||||
primaryStage.setScene(new Scene(root, 620, 295));
|
||||
primaryStage.show();
|
||||
|
||||
primaryStage.getScene().getStylesheets().add(GEarthController.class.getResource("bootstrap3.css").toExternalForm());
|
||||
|
||||
primaryStage.setOnCloseRequest( event -> {
|
||||
companion.abort();
|
||||
Platform.exit();
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -4,10 +4,7 @@ import main.protocol.HMessage;
|
||||
import main.protocol.HPacket;
|
||||
import main.ui.extensions.Extensions;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -26,14 +23,29 @@ public abstract class Extension {
|
||||
void act(String[] args);
|
||||
}
|
||||
|
||||
protected static final boolean CANLEAVE = true; // can you disconnect the ext
|
||||
protected static final boolean CANDELETE = true; // can you delete the ext (will be false for some built-in extensions)
|
||||
|
||||
private String[] args;
|
||||
private boolean isCorrupted = false;
|
||||
private static final String[] PORT_FLAG = {"--port", "-p"};
|
||||
private static final String[] FILE_FLAG = {"--filename", "-f"};
|
||||
|
||||
private OutputStream out = null;
|
||||
private Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
|
||||
private Map<Integer, List<MessageListener>> outgoingMessageListeners = new HashMap<>();
|
||||
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++) {
|
||||
for (String str : arg) {
|
||||
if (args[i].toLowerCase().equals(str.toLowerCase())) {
|
||||
return args[i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the connection with G-Earth, pass the arguments given in the Main method "super(args)"
|
||||
@ -41,29 +53,53 @@ public abstract class Extension {
|
||||
*/
|
||||
public Extension(String[] args) {
|
||||
//obtain port
|
||||
int port = 0;
|
||||
this.args = args;
|
||||
|
||||
outerloop:
|
||||
for (int i = 0; i < args.length - 1; i++) {
|
||||
for (String str : PORT_FLAG) {
|
||||
if (args[i].equals(str)) {
|
||||
port = Integer.parseInt(args[i+1]);
|
||||
break outerloop;
|
||||
|
||||
if (getInfoAnnotations() == null) {
|
||||
System.err.println("Extension info not found\n\n" +
|
||||
"Usage:\n" +
|
||||
"@ExtensionInfo ( \n" +
|
||||
" Title = \"...\",\n" +
|
||||
" Description = \"...\",\n" +
|
||||
" Version = \"...\",\n" +
|
||||
" Author = \"...\"" +
|
||||
"\n)");
|
||||
isCorrupted = true;
|
||||
}
|
||||
|
||||
if (getArgument(args, PORT_FLAG) == null) {
|
||||
System.err.println("Don't forget to include G-Earth's port in your program parameters (-p {port})");
|
||||
isCorrupted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (isCorrupted) {
|
||||
return;
|
||||
}
|
||||
|
||||
int port = Integer.parseInt(getArgument(args, PORT_FLAG));
|
||||
String file = getArgument(args, FILE_FLAG);
|
||||
|
||||
Socket gEarthExtensionServer = null;
|
||||
try {
|
||||
gEarthExtensionServer = new Socket("localhost", port);
|
||||
|
||||
gEarthExtensionServer = new Socket("127.0.0.1", port);
|
||||
InputStream in = gEarthExtensionServer.getInputStream();
|
||||
DataInputStream dIn = new DataInputStream(in);
|
||||
out = gEarthExtensionServer.getOutputStream();
|
||||
|
||||
while (!gEarthExtensionServer.isClosed()) {
|
||||
|
||||
int length = dIn.readInt();
|
||||
int length;
|
||||
try {
|
||||
length = dIn.readInt();
|
||||
}
|
||||
catch(EOFException exception) {
|
||||
//g-earth closed the extension
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] headerandbody = new byte[length + 4];
|
||||
|
||||
int amountRead = 0;
|
||||
@ -77,11 +113,18 @@ public abstract class Extension {
|
||||
|
||||
|
||||
if (packet.headerId() == Extensions.OUTGOING_MESSAGES_IDS.INFOREQUEST) {
|
||||
ExtensionInfo info = getInfoAnnotations();
|
||||
|
||||
HPacket response = new HPacket(Extensions.INCOMING_MESSAGES_IDS.EXTENSIONINFO);
|
||||
response.appendString(getTitle())
|
||||
.appendString(getAuthor())
|
||||
.appendString(getVersion())
|
||||
.appendString(getDescription());
|
||||
response.appendString(info.Title())
|
||||
.appendString(info.Author())
|
||||
.appendString(info.Version())
|
||||
.appendString(info.Description())
|
||||
.appendBoolean(isOnClickMethodUsed())
|
||||
.appendBoolean(file != null)
|
||||
.appendString(file == null ? "": file)
|
||||
.appendBoolean(CANLEAVE)
|
||||
.appendBoolean(CANDELETE);
|
||||
writeToStream(response.toBytes());
|
||||
}
|
||||
else if (packet.headerId() == Extensions.OUTGOING_MESSAGES_IDS.CONNECTIONSTART) {
|
||||
@ -121,19 +164,29 @@ public abstract class Extension {
|
||||
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--) {
|
||||
listeners.get(-1).get(i).act(habboMessage);
|
||||
habboMessage.getPacket().setReadIndex(6);
|
||||
correctListeners.add(listeners.get(-1).get(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (listeners.containsKey(habboPacket.headerId())) {
|
||||
for (int i = listeners.get(habboPacket.headerId()).size() - 1; i >= 0; i--) {
|
||||
listeners.get(habboPacket.headerId()).get(i).act(habboMessage);
|
||||
correctListeners.add(listeners.get(habboPacket.headerId()).get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(MessageListener listener : correctListeners) {
|
||||
habboMessage.getPacket().setReadIndex(6);
|
||||
listener.act(habboMessage);
|
||||
}
|
||||
}
|
||||
habboMessage.getPacket().setReadIndex(6);
|
||||
|
||||
HPacket response = new HPacket(Extensions.INCOMING_MESSAGES_IDS.MANIPULATEDPACKET);
|
||||
response.appendLongString(habboMessage.stringify());
|
||||
@ -143,9 +196,9 @@ public abstract class Extension {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException | ArrayIndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Connection failed; is G-Earth active?");
|
||||
// e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
if (gEarthExtensionServer != null && !gEarthExtensionServer.isClosed()) {
|
||||
@ -206,9 +259,12 @@ public abstract class Extension {
|
||||
incomingMessageListeners :
|
||||
outgoingMessageListeners;
|
||||
|
||||
synchronized (listeners) {
|
||||
if (!listeners.containsKey(headerId)) {
|
||||
listeners.put(headerId, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
listeners.get(headerId).add(messageListener);
|
||||
}
|
||||
@ -249,6 +305,25 @@ public abstract class Extension {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@ -270,8 +345,8 @@ public abstract class Extension {
|
||||
*/
|
||||
protected void onEndConnection(){}
|
||||
|
||||
protected abstract String getTitle();
|
||||
protected abstract String getDescription();
|
||||
protected abstract String getVersion();
|
||||
protected abstract String getAuthor();
|
||||
|
||||
ExtensionInfo getInfoAnnotations() {
|
||||
return getClass().getAnnotation(ExtensionInfo.class);
|
||||
}
|
||||
}
|
||||
|
114
src/main/extensions/ExtensionForm.java
Normal file
@ -0,0 +1,114 @@
|
||||
package main.extensions;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
import main.protocol.HMessage;
|
||||
import main.protocol.HPacket;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
public abstract class ExtensionForm extends Application {
|
||||
|
||||
private Extension extension = null;
|
||||
protected static String[] args;
|
||||
private volatile Stage primaryStage = null;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Platform.setImplicitExit(false);
|
||||
setStageData(primaryStage);
|
||||
this.primaryStage = primaryStage;
|
||||
primaryStage.setOnCloseRequest(event -> {
|
||||
event.consume();
|
||||
Platform.runLater(primaryStage::hide);
|
||||
});
|
||||
ExtensionForm thiss = this;
|
||||
|
||||
ExtensionInfo extInfo = getClass().getAnnotation(ExtensionInfo.class);
|
||||
|
||||
Thread t = new Thread(() -> {
|
||||
extension = new Extension(args) {
|
||||
@Override
|
||||
protected void init() {
|
||||
thiss.initExtension();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
thiss.onClick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartConnection() {
|
||||
thiss.onStartConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEndConnection() {
|
||||
thiss.onEndConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
ExtensionInfo getInfoAnnotations() {
|
||||
return extInfo;
|
||||
}
|
||||
};
|
||||
extension.run();
|
||||
// Platform.runLater(primaryStage::close);
|
||||
//when the extension has ended, close this process
|
||||
Platform.exit();
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
public abstract void setStageData(Stage primaryStage) throws Exception;
|
||||
|
||||
|
||||
//wrap extension methods
|
||||
protected boolean requestFlags(Extension.FlagsCheckListener flagRequestCallback){
|
||||
return extension.requestFlags(flagRequestCallback);
|
||||
}
|
||||
protected void writeToConsole(String s) {
|
||||
extension.writeToConsole(s);
|
||||
}
|
||||
protected void intercept(HMessage.Side side, Extension.MessageListener messageListener) {
|
||||
extension.intercept(side, messageListener);
|
||||
}
|
||||
protected void intercept(HMessage.Side side, int headerId, Extension.MessageListener messageListener){
|
||||
extension.intercept(side, headerId, messageListener);
|
||||
}
|
||||
protected boolean sendToServer(HPacket packet){
|
||||
return extension.sendToServer(packet);
|
||||
}
|
||||
protected boolean sendToClient(HPacket packet){
|
||||
return extension.sendToClient(packet);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private void onClick(){
|
||||
Platform.runLater(() -> {
|
||||
primaryStage.show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A connection with Habbo has been started
|
||||
*/
|
||||
protected void onStartConnection(){}
|
||||
|
||||
/**
|
||||
* A connection with Habbo has ended
|
||||
*/
|
||||
protected void onEndConnection(){}
|
||||
}
|
15
src/main/extensions/ExtensionInfo.java
Normal file
@ -0,0 +1,15 @@
|
||||
package main.extensions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 25/09/18.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExtensionInfo {
|
||||
String Title();
|
||||
String Description();
|
||||
String Version();
|
||||
String Author();
|
||||
}
|
@ -1,17 +1,26 @@
|
||||
package main.extensions.examples;
|
||||
package main.extensions.examples.adminonconnect;
|
||||
|
||||
import main.extensions.Extension;
|
||||
import main.extensions.ExtensionInfo;
|
||||
import main.protocol.HMessage;
|
||||
import main.protocol.HPacket;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 26/06/18.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ExtensionInfo(
|
||||
Title = "Always admin!",
|
||||
Description = "Gives you admin permission on connect",
|
||||
Version = "1.0",
|
||||
Author = "sirjonasxx"
|
||||
)
|
||||
public class AdminOnConnect extends Extension {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
new AdminOnConnect(args);
|
||||
new AdminOnConnect(args).run();
|
||||
}
|
||||
public AdminOnConnect(String[] args) {
|
||||
super(args);
|
||||
@ -39,22 +48,4 @@ public class AdminOnConnect extends Extension {
|
||||
protected void onStartConnection() {
|
||||
done = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
System.out.println("clicked");
|
||||
}
|
||||
|
||||
protected String getTitle() {
|
||||
return "Always admin!";
|
||||
}
|
||||
protected String getDescription() {
|
||||
return "Gives you admin permission on connect";
|
||||
}
|
||||
protected String getVersion() {
|
||||
return "1.0";
|
||||
}
|
||||
protected String getAuthor() {
|
||||
return "sirjonasxx";
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package main.extensions.examples.blockreplacepackets;
|
||||
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import main.extensions.ExtensionForm;
|
||||
import main.extensions.ExtensionInfo;
|
||||
import main.ui.GEarthController;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
|
||||
|
||||
@ExtensionInfo(
|
||||
Title = "iManipulate",
|
||||
Description = "Block &/ replace packets",
|
||||
Version = "0.1",
|
||||
Author = "sirjonasxx"
|
||||
)
|
||||
public class BlockAndReplacePackets extends ExtensionForm {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ExtensionForm.args = args;
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initExtension() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStageData(Stage primaryStage) throws Exception {
|
||||
FXMLLoader loader = new FXMLLoader(BlockAndReplacePackets.class.getResource("blockreplace.fxml"));
|
||||
Parent root = loader.load();
|
||||
|
||||
primaryStage.setTitle("Packet blocker and replacer");
|
||||
primaryStage.setScene(new Scene(root, 565, 262));
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
|
||||
<GridPane prefHeight="260.0" prefWidth="179.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.extensions.examples.blockreplacepackets.BlockAndReplacePackets">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="367.0" minWidth="10.0" prefWidth="163.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="121.0" minHeight="10.0" prefHeight="28.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="234.0" minHeight="10.0" prefHeight="234.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<TextArea fx:id="text" editable="false" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</GridPane.margin>
|
||||
</TextArea>
|
||||
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Blocks packets:" textAlignment="CENTER" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
@ -1,6 +1,7 @@
|
||||
package main.extensions.examples;
|
||||
package main.extensions.examples.speechcolorizer;
|
||||
|
||||
import main.extensions.Extension;
|
||||
import main.extensions.ExtensionInfo;
|
||||
import main.protocol.HMessage;
|
||||
import main.protocol.HPacket;
|
||||
|
||||
@ -15,11 +16,16 @@ import java.util.Random;
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@ExtensionInfo(
|
||||
Title = "Colorize me!",
|
||||
Description = "Because we like to be weird",
|
||||
Version = "1.0",
|
||||
Author = "sirjonasxx"
|
||||
)
|
||||
public class SpeechColorizer extends Extension {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpeechColorizer(args);
|
||||
new SpeechColorizer(args).run();
|
||||
}
|
||||
private SpeechColorizer(String[] args) {
|
||||
super(args);
|
7
src/main/extensions/extra/Inspector.java
Normal file
@ -0,0 +1,7 @@
|
||||
package main.extensions.extra;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
public class Inspector {
|
||||
}
|
@ -1,183 +1,71 @@
|
||||
package main.misc;
|
||||
|
||||
import java.io.*;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 05/04/18.
|
||||
* Created by Jonas on 28/09/18.
|
||||
*/
|
||||
public class Cacher {
|
||||
|
||||
private static final String CACHEFILENAME = "jsoncache.json";
|
||||
|
||||
private static String getCacheDir() {
|
||||
return System.getProperty("user.home") + File.separator + ".G-Earth" + File.separator;
|
||||
}
|
||||
|
||||
public static boolean exists(String key) {
|
||||
File f = new File(getCacheDir(), "cache.txt");
|
||||
if (f.exists()) {
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(f.toPath());
|
||||
private static boolean cacheFileExists() {
|
||||
File f = new File(getCacheDir(), CACHEFILENAME);
|
||||
return (f.exists() && !f.isDirectory());
|
||||
}
|
||||
|
||||
for (String line : lines) {
|
||||
if (line.startsWith(key+":")) {
|
||||
return true;
|
||||
private static JSONObject getCacheContents() {
|
||||
if (cacheFileExists()) {
|
||||
try {
|
||||
File f = new File(getCacheDir(), CACHEFILENAME);
|
||||
String contents = String.join("\n", Files.readAllLines(f.toPath()));
|
||||
|
||||
JSONParser parser = new JSONParser();
|
||||
return (JSONObject) parser.parse(contents);
|
||||
} catch (IOException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new JSONObject();
|
||||
}
|
||||
private static void updateCache(JSONObject contents) {
|
||||
try (FileWriter file = new FileWriter(new File(getCacheDir(), CACHEFILENAME))) {
|
||||
|
||||
file.write(contents.toJSONString());
|
||||
file.flush();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String get(String key) {
|
||||
File f = new File(getCacheDir(), "cache.txt");
|
||||
if (f.exists()) {
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(f.toPath());
|
||||
public static void put(String key, Object val) {
|
||||
JSONObject object = getCacheContents();
|
||||
if (object.containsKey(key)) object.remove(key);
|
||||
|
||||
for (String line : lines) {
|
||||
if (line.startsWith(key+":")) {
|
||||
return line.split(":")[1];
|
||||
}
|
||||
object.put(key, val);
|
||||
updateCache(object);
|
||||
}
|
||||
public static Object get(String key) {
|
||||
JSONObject object = getCacheContents();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return object.get(key);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void remove(String key) {
|
||||
File targetFile = new File(getCacheDir() + File.separator + "cache.txt");
|
||||
File parent = targetFile.getParentFile();
|
||||
if (!parent.exists() && !parent.mkdirs()) {
|
||||
throw new IllegalStateException("Couldn't create dir: " + parent);
|
||||
}
|
||||
if (!targetFile.exists()) {
|
||||
try {
|
||||
targetFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
File f1 = new File(getCacheDir() + File.separator + "cache.txt");
|
||||
FileReader fr = new FileReader(f1);
|
||||
BufferedReader br = new BufferedReader(fr);
|
||||
String line = null;
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
if (!line.startsWith(key + ":"))
|
||||
lines.add(line);
|
||||
|
||||
}
|
||||
fr.close();
|
||||
br.close();
|
||||
|
||||
FileWriter fw = new FileWriter(f1);
|
||||
BufferedWriter out = new BufferedWriter(fw);
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
out.write(lines.get(i));
|
||||
if (i != lines.size() - 1) out.write("\n");
|
||||
}
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void add(String key, String value) {
|
||||
File targetFile = new File(getCacheDir() + File.separator + "cache.txt");
|
||||
File parent = targetFile.getParentFile();
|
||||
if (!parent.exists() && !parent.mkdirs()) {
|
||||
throw new IllegalStateException("Couldn't create dir: " + parent);
|
||||
}
|
||||
if (!targetFile.exists()) {
|
||||
try {
|
||||
targetFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// File f = new File(getCacheDir(), "cache.txt");
|
||||
// if (!f.exists()) {
|
||||
// try {
|
||||
// PrintWriter writer = new PrintWriter(f.getPath(), "UTF-8");
|
||||
// writer.write("");
|
||||
// writer.close();
|
||||
// } catch (FileNotFoundException | UnsupportedEncodingException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
File f1 = new File(getCacheDir() + File.separator + "cache.txt");
|
||||
FileReader fr = new FileReader(f1);
|
||||
BufferedReader br = new BufferedReader(fr);
|
||||
String line = null;
|
||||
boolean containmmm = false;
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
if (line.startsWith(key+":"))
|
||||
containmmm = true;
|
||||
lines.add(line);
|
||||
|
||||
}
|
||||
fr.close();
|
||||
br.close();
|
||||
|
||||
FileWriter fw = new FileWriter(f1);
|
||||
BufferedWriter out = new BufferedWriter(fw);
|
||||
|
||||
if (!containmmm) {
|
||||
out.write(key+":"+value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
out.write("\n"+ lines.get(i));
|
||||
}
|
||||
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void update(String key, String value) {
|
||||
remove(key);
|
||||
add(key, value);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
// System.out.println(exists("hallo"));
|
||||
// System.out.println(get("hallo"));
|
||||
//
|
||||
// add("hallo","doei");
|
||||
//
|
||||
// System.out.println(exists("hallo"));
|
||||
// System.out.println(get("hallo"));
|
||||
//
|
||||
// remove("hallo");
|
||||
// System.out.println(get("hallo"));
|
||||
System.out.println(get("PRODUCTION-201804032203-770536283-pingHeader"));
|
||||
public static void clear() {
|
||||
updateCache(new JSONObject());
|
||||
}
|
||||
}
|
||||
|
50
src/main/misc/ConfirmationDialog.java
Normal file
@ -0,0 +1,50 @@
|
||||
package main.misc;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DialogPane;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 27/09/18.
|
||||
*/
|
||||
public class ConfirmationDialog {
|
||||
|
||||
public static boolean showDialog = true;
|
||||
|
||||
public static Alert createAlertWithOptOut(Alert.AlertType type, String title, String headerText,
|
||||
String message, String optOutMessage, /*Callback<Boolean, Void> optOutAction,*/
|
||||
ButtonType... buttonTypes) {
|
||||
Alert alert = new Alert(type);
|
||||
// Need to force the alert to layout in order to grab the graphic,
|
||||
// as we are replacing the dialog pane with a custom pane
|
||||
alert.getDialogPane().applyCss();
|
||||
Node graphic = alert.getDialogPane().getGraphic();
|
||||
// Create a new dialog pane that has a checkbox instead of the hide/show details button
|
||||
// Use the supplied callback for the action of the checkbox
|
||||
alert.setDialogPane(new DialogPane() {
|
||||
@Override
|
||||
protected Node createDetailsButton() {
|
||||
CheckBox optOut = new CheckBox();
|
||||
optOut.setText(optOutMessage);
|
||||
optOut.setOnAction(event -> showDialog = !optOut.isSelected());
|
||||
return optOut;
|
||||
}
|
||||
});
|
||||
alert.getDialogPane().getButtonTypes().addAll(buttonTypes);
|
||||
alert.getDialogPane().setContentText(message);
|
||||
// Fool the dialog into thinking there is some expandable content
|
||||
// a Group won't take up any space if it has no children
|
||||
alert.getDialogPane().setExpandableContent(new Group());
|
||||
alert.getDialogPane().setExpanded(true);
|
||||
// Reset the dialog graphic using the default style
|
||||
alert.getDialogPane().setGraphic(graphic);
|
||||
alert.setTitle(title);
|
||||
alert.setHeaderText(headerText);
|
||||
return alert;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package main.protocol;
|
||||
|
||||
import main.misc.Cacher;
|
||||
import main.protocol.hostreplacer.HostReplacer;
|
||||
import main.protocol.hostreplacer.HostReplacerFactory;
|
||||
import main.protocol.memory.Rc4Obtainer;
|
||||
@ -16,6 +17,7 @@ import java.util.*;
|
||||
|
||||
public class HConnection {
|
||||
|
||||
public static final String HOTELS_CACHE_KEY = "hotelsConnectionInfo";
|
||||
|
||||
private final Queue<HPacket> sendToClientAsyncQueue = new LinkedList<>();
|
||||
private final Queue<HPacket> sendToServerAsyncQueue = new LinkedList<>();
|
||||
@ -63,16 +65,27 @@ public class HConnection {
|
||||
CONNECTED // CONNECTED
|
||||
}
|
||||
|
||||
private static List<String> autoDetectHosts;
|
||||
public static List<String> autoDetectHosts;
|
||||
static {
|
||||
autoDetectHosts = new ArrayList<>();
|
||||
autoDetectHosts.add("game-us.habbo.com:38101");
|
||||
autoDetectHosts.add("game-nl.habbo.com:30000");
|
||||
autoDetectHosts.add("game-br.habbo.com:30000");
|
||||
autoDetectHosts.add("game-de.habbo.com:30000");
|
||||
autoDetectHosts.add("game-es.habbo.com:30000");
|
||||
autoDetectHosts.add("game-fi.habbo.com:30000");
|
||||
autoDetectHosts.add("game-fr.habbo.com:30000");
|
||||
autoDetectHosts.add("game-it.habbo.com:30000");
|
||||
autoDetectHosts.add("game-nl.habbo.com:30000");
|
||||
autoDetectHosts.add("game-tr.habbo.com:30000");
|
||||
autoDetectHosts.add("game-us.habbo.com:38101");
|
||||
|
||||
List<String> additionalCachedHotels = (List<String>) Cacher.get(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels != null) {
|
||||
for (String additionalHotel : additionalCachedHotels) {
|
||||
if (!autoDetectHosts.contains(additionalHotel)) {
|
||||
autoDetectHosts.add(additionalHotel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -110,6 +123,16 @@ public class HConnection {
|
||||
|
||||
// manual method
|
||||
public void prepare(String domain, int port) {
|
||||
List<String> additionalCachedHotels = (List<String>) Cacher.get(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels == null) {
|
||||
additionalCachedHotels = new ArrayList<>();
|
||||
}
|
||||
if (!additionalCachedHotels.contains(domain +":"+port)) {
|
||||
additionalCachedHotels.add(domain+":"+port);
|
||||
Cacher.put(HOTELS_CACHE_KEY, additionalCachedHotels);
|
||||
}
|
||||
|
||||
|
||||
List<String> potentialHost = new ArrayList<>();
|
||||
potentialHost.add(domain+":"+port);
|
||||
prepare(potentialHost);
|
||||
@ -134,19 +157,31 @@ public class HConnection {
|
||||
removeFromHosts();
|
||||
}
|
||||
|
||||
try {
|
||||
for (String host : allPotentialHosts) {
|
||||
InetAddress address = InetAddress.getByName(host.split(":")[0]);
|
||||
actual_domain.add(address.getHostAddress());
|
||||
}
|
||||
setState(State.PREPARED);
|
||||
|
||||
List<String> willremove = new ArrayList<>();
|
||||
for (String host : allPotentialHosts) {
|
||||
InetAddress address = null;
|
||||
try {
|
||||
address = InetAddress.getByName(host.split(":")[0]);
|
||||
actual_domain.add(address.getHostAddress());
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
setState(State.NOT_CONNECTED);
|
||||
// e.printStackTrace();
|
||||
actual_domain.add(null);
|
||||
willremove.add(host);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> additionalCachedHotels = (List<String>) Cacher.get(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels != null) {
|
||||
for (String host: willremove) {
|
||||
additionalCachedHotels.remove(host);
|
||||
}
|
||||
Cacher.put(HOTELS_CACHE_KEY, additionalCachedHotels);
|
||||
}
|
||||
|
||||
setState(State.PREPARED);
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
if (state == State.PREPARED) {
|
||||
|
||||
@ -157,6 +192,8 @@ public class HConnection {
|
||||
|
||||
|
||||
for (int i = 0; i < actual_domain.size(); i++) {
|
||||
if (actual_domain.get(i) == null) continue;
|
||||
|
||||
ServerSocket proxy = new ServerSocket(port.get(i), 10, InetAddress.getByName("127.0.0." + (i+1)));
|
||||
this.proxy.add(proxy);
|
||||
String dom = actual_domain.get(i);
|
||||
@ -186,7 +223,7 @@ public class HConnection {
|
||||
|
||||
} catch (IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
//e1.printStackTrace();
|
||||
// e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -359,17 +396,31 @@ public class HConnection {
|
||||
}
|
||||
|
||||
private void addToHosts() {
|
||||
String[] lines = new String[input_domain.size()];
|
||||
List<String> linesTemp = new ArrayList<>();
|
||||
for (int i = 0; i < input_domain.size(); i++) {
|
||||
lines[i] = ("127.0.0." + (i+1)) + " " + input_domain.get(i);
|
||||
if (actual_domain.get(i) != null) {
|
||||
linesTemp.add(("127.0.0." + (i+1)) + " " + input_domain.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
String[] lines = new String[linesTemp.size()];
|
||||
for (int i = 0; i < linesTemp.size(); i++) {
|
||||
lines[i] = linesTemp.get(i);
|
||||
}
|
||||
hostsReplacer.addRedirect(lines);
|
||||
hostRedirected = true;
|
||||
}
|
||||
private void removeFromHosts(){
|
||||
String[] lines = new String[input_domain.size()];
|
||||
List<String> linesTemp = new ArrayList<>();
|
||||
for (int i = 0; i < input_domain.size(); i++) {
|
||||
lines[i] = ("127.0.0." + (i+1)) + " " + input_domain.get(i);
|
||||
if (actual_domain.get(i) != null) {
|
||||
linesTemp.add(("127.0.0." + (i+1)) + " " + input_domain.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
String[] lines = new String[linesTemp.size()];
|
||||
for (int i = 0; i < linesTemp.size(); i++) {
|
||||
lines[i] = linesTemp.get(i);
|
||||
}
|
||||
hostsReplacer.removeRedirect(lines);
|
||||
hostRedirected = false;
|
||||
|
@ -72,6 +72,7 @@ public class Rc4Obtainer {
|
||||
|
||||
if (payloadBuffer.peak().length == 0) {
|
||||
outgoingHandler.setRc4(rc4Tryout);
|
||||
incomingHandler.setRc4(rc4Tryout);
|
||||
break outerloop;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package main.protocol.packethandler;
|
||||
|
||||
import main.protocol.HMessage;
|
||||
import main.protocol.TrafficListener;
|
||||
import main.protocol.crypto.RC4;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@ -10,6 +11,8 @@ import java.util.List;
|
||||
|
||||
public abstract class Handler {
|
||||
|
||||
protected static final boolean DEBUG = false;
|
||||
|
||||
volatile PayloadBuffer payloadBuffer = new PayloadBuffer();
|
||||
volatile OutputStream out;
|
||||
volatile Object[] listeners = null; //get notified on packet send
|
||||
@ -17,6 +20,9 @@ public abstract class Handler {
|
||||
volatile boolean isDataStream = false;
|
||||
volatile int currentIndex = 0;
|
||||
|
||||
protected RC4 clientcipher = null;
|
||||
protected RC4 servercipher = null;
|
||||
|
||||
|
||||
public Handler(OutputStream outputStream, Object[] listeners) {
|
||||
this.listeners = listeners;
|
||||
@ -28,18 +34,11 @@ public abstract class Handler {
|
||||
isDataStream = true;
|
||||
}
|
||||
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
if (isDataStream) {
|
||||
payloadBuffer.push(buffer);
|
||||
notifyBufferListeners(buffer.length);
|
||||
public abstract void act(byte[] buffer) throws IOException;
|
||||
|
||||
if (!isTempBlocked) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.write(buffer);
|
||||
}
|
||||
public void setRc4(RC4 rc4) {
|
||||
this.clientcipher = rc4.deepCopy();
|
||||
this.servercipher = rc4.deepCopy();
|
||||
}
|
||||
|
||||
public void block() {
|
||||
@ -73,7 +72,7 @@ public abstract class Handler {
|
||||
|
||||
public abstract void flush() throws IOException;
|
||||
|
||||
|
||||
protected abstract void printForDebugging(byte[] bytes);
|
||||
|
||||
private List<BufferListener> bufferListeners = new ArrayList<>();
|
||||
public void addBufferListener(BufferListener listener) {
|
||||
|
@ -13,13 +13,48 @@ public class IncomingHandler extends Handler {
|
||||
super(outputStream, listeners);
|
||||
}
|
||||
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
private Boolean isEncryptedStream = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
if (isDataStream) {
|
||||
if (DEBUG) {
|
||||
printForDebugging(buffer);
|
||||
}
|
||||
|
||||
|
||||
if (isEncryptedStream == null || !isEncryptedStream) {
|
||||
payloadBuffer.push(buffer);
|
||||
}
|
||||
else {
|
||||
payloadBuffer.push(servercipher.rc4(buffer));
|
||||
}
|
||||
|
||||
|
||||
notifyBufferListeners(buffer.length);
|
||||
|
||||
if (!isTempBlocked) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.write(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToStream(byte[] buffer) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
out.write(buffer);
|
||||
out.write(
|
||||
(isEncryptedStream == null || !isEncryptedStream)
|
||||
? buffer
|
||||
: clientcipher.rc4(buffer)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -33,14 +68,29 @@ public class IncomingHandler extends Handler {
|
||||
|
||||
for (HPacket hpacket : hpackets){
|
||||
HMessage hMessage = new HMessage(hpacket, HMessage.Side.TOCLIENT, currentIndex);
|
||||
if (isDataStream) notifyListeners(hMessage);
|
||||
if (isDataStream) {
|
||||
notifyListeners(hMessage);
|
||||
}
|
||||
|
||||
if (!hMessage.isBlocked()) {
|
||||
out.write(hMessage.getPacket().toBytes());
|
||||
out.write(
|
||||
(isEncryptedStream == null || !isEncryptedStream)
|
||||
? hMessage.getPacket().toBytes()
|
||||
: clientcipher.rc4(hMessage.getPacket().toBytes())
|
||||
);
|
||||
}
|
||||
|
||||
if (isDataStream && isEncryptedStream == null && hpacket.length() == 261) {
|
||||
isEncryptedStream = hpacket.readBoolean(264);
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printForDebugging(byte[] bytes) {
|
||||
System.out.println("-- DEBUG INCOMING -- " + new HPacket(bytes).toString() + " -- DEBUG --");
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,7 @@ public class OutgoingHandler extends Handler {
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
|
||||
private final static int encryptOffset = 3; //all packets with index < 3 aren't encrypted
|
||||
private RC4 clientcipher = null;
|
||||
private RC4 servercipher = null;
|
||||
private List<Byte> tempEncryptedBuffer = new ArrayList<>();
|
||||
|
||||
public OutgoingHandler(OutputStream outputStream, Object[] listeners) {
|
||||
@ -35,7 +32,6 @@ public class OutgoingHandler extends Handler {
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
dataStreamCheck(buffer);
|
||||
if (isDataStream) {
|
||||
|
||||
if (currentIndex < encryptOffset) {
|
||||
payloadBuffer.push(buffer);
|
||||
}
|
||||
@ -45,7 +41,11 @@ public class OutgoingHandler extends Handler {
|
||||
}
|
||||
}
|
||||
else {
|
||||
payloadBuffer.push(clientcipher.rc4(buffer));
|
||||
byte[] tm = clientcipher.rc4(buffer);
|
||||
if (DEBUG) {
|
||||
printForDebugging(tm);
|
||||
}
|
||||
payloadBuffer.push(tm);
|
||||
}
|
||||
|
||||
notifyBufferListeners(buffer.length);
|
||||
@ -60,20 +60,8 @@ public class OutgoingHandler extends Handler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToStream(byte[] buffer) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
out.write(servercipher.rc4(buffer));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setRc4(RC4 rc4) {
|
||||
this.clientcipher = rc4;
|
||||
this.servercipher = rc4.deepCopy();
|
||||
super.setRc4(rc4);
|
||||
|
||||
byte[] encrbuffer = new byte[tempEncryptedBuffer.size()];
|
||||
for (int i = 0; i < tempEncryptedBuffer.size(); i++) {
|
||||
@ -87,6 +75,19 @@ public class OutgoingHandler extends Handler {
|
||||
}
|
||||
tempEncryptedBuffer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToStream(byte[] buffer) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
out.write(servercipher.rc4(buffer));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<Byte> getEncryptedBuffer() {
|
||||
return tempEncryptedBuffer;
|
||||
}
|
||||
@ -109,4 +110,10 @@ public class OutgoingHandler extends Handler {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void printForDebugging(byte[] bytes) {
|
||||
System.out.println("-- DEBUG OUTGOING -- " + new HPacket(bytes).toString() + " -- DEBUG --");
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BoxButton extends StackPane {
|
||||
|
||||
private ImageView imageView;
|
||||
@ -15,9 +17,9 @@ public class BoxButton extends StackPane {
|
||||
private boolean isVisible;
|
||||
|
||||
//paths zijn relatief aan deze classpath
|
||||
public BoxButton(String imagePath, String imageOnHoverPath) {
|
||||
this.image = new Image(getClass().getResourceAsStream(imagePath));
|
||||
this.imageOnHover = new Image(getClass().getResourceAsStream(imageOnHoverPath));
|
||||
public BoxButton(String imageName, String imageOnHoverName) {
|
||||
this.image = new Image(getClass().getResourceAsStream("files" + File.separator + imageName));
|
||||
this.imageOnHover = new Image(getClass().getResourceAsStream("files" + File.separator + imageOnHoverName));
|
||||
this.imageView = new ImageView();
|
||||
|
||||
setCursor(Cursor.DEFAULT);
|
||||
|
@ -1,5 +1,9 @@
|
||||
package main.ui.buttons;
|
||||
|
||||
import org.omg.CORBA.Environment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DeleteButton extends BoxButton {
|
||||
|
||||
public DeleteButton() {
|
||||
|
10
src/main/ui/buttons/ExitButton.java
Normal file
@ -0,0 +1,10 @@
|
||||
package main.ui.buttons;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 26/09/18.
|
||||
*/
|
||||
public class ExitButton extends BoxButton {
|
||||
public ExitButton() {
|
||||
super("ButtonExit.png", "ButtonExitHover.png");
|
||||
}
|
||||
}
|
10
src/main/ui/buttons/FireButton.java
Normal file
@ -0,0 +1,10 @@
|
||||
package main.ui.buttons;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 26/09/18.
|
||||
*/
|
||||
public class FireButton extends BoxButton {
|
||||
public FireButton() {
|
||||
super("ButtonFire.png", "ButtonFireHover.png");
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -31,10 +32,10 @@ public class PauseResumeButton extends StackPane{
|
||||
public PauseResumeButton(boolean isPaused) {
|
||||
this.isPaused[0] = isPaused;
|
||||
|
||||
this.imagePause = new Image(getClass().getResourceAsStream("ButtonPause.png"));
|
||||
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("ButtonPauseHover.png"));
|
||||
this.imageResume = new Image(getClass().getResourceAsStream("ButtonResume.png"));
|
||||
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("ButtonResumeHover.png"));
|
||||
this.imagePause = new Image(getClass().getResourceAsStream("files"+ File.separator+"ButtonPause.png"));
|
||||
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("files"+ File.separator+"ButtonPauseHover.png"));
|
||||
this.imageResume = new Image(getClass().getResourceAsStream("files"+ File.separator+"ButtonResume.png"));
|
||||
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("files"+ File.separator+"ButtonResumeHover.png"));
|
||||
this.imageView = new ImageView();
|
||||
|
||||
setCursor(Cursor.DEFAULT);
|
||||
|
9
src/main/ui/buttons/ReloadButton.java
Normal file
@ -0,0 +1,9 @@
|
||||
package main.ui.buttons;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 26/09/18.
|
||||
*/
|
||||
public class ReloadButton extends BoxButton {
|
||||
public ReloadButton() {
|
||||
super("ButtonReload.png", "ButtonReloadHover.png"); }
|
||||
}
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 443 B |
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 454 B |
BIN
src/main/ui/buttons/files/ButtonExit.png
Normal file
After Width: | Height: | Size: 644 B |
BIN
src/main/ui/buttons/files/ButtonExitHover.png
Normal file
After Width: | Height: | Size: 538 B |
BIN
src/main/ui/buttons/files/ButtonFire.png
Normal file
After Width: | Height: | Size: 677 B |
BIN
src/main/ui/buttons/files/ButtonFireHover.png
Normal file
After Width: | Height: | Size: 642 B |
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 621 B After Width: | Height: | Size: 621 B |
BIN
src/main/ui/buttons/files/ButtonReload.png
Normal file
After Width: | Height: | Size: 643 B |
BIN
src/main/ui/buttons/files/ButtonReloadHover.png
Normal file
After Width: | Height: | Size: 535 B |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 446 B |
@ -14,6 +14,10 @@ import main.protocol.TrafficListener;
|
||||
import main.ui.SubForm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Connection extends SubForm {
|
||||
|
||||
@ -35,8 +39,24 @@ public class Connection extends SubForm {
|
||||
updateInputUI();
|
||||
});
|
||||
|
||||
inpPort.getItems().addAll("30000", "38101");
|
||||
inpHost.getItems().addAll("game-nl.habbo.com", "game-us.habbo.com");
|
||||
List<String> knownHosts = HConnection.autoDetectHosts;
|
||||
Set<String> hosts = new HashSet<>();
|
||||
Set<String> ports = new HashSet<>();
|
||||
|
||||
for (String h : knownHosts) {
|
||||
String[] split = h.split(":");
|
||||
hosts.add(split[0]);
|
||||
ports.add(split[1]);
|
||||
}
|
||||
|
||||
List<String> hostsSorted = new ArrayList<>(hosts);
|
||||
hostsSorted.sort(String::compareTo);
|
||||
|
||||
List<String> portsSorted = new ArrayList<>(ports);
|
||||
portsSorted.sort(String::compareTo);
|
||||
|
||||
inpPort.getItems().addAll(portsSorted);
|
||||
inpHost.getItems().addAll(hostsSorted);
|
||||
|
||||
inpPort.getSelectionModel().selectFirst();
|
||||
inpHost.getSelectionModel().selectFirst();
|
||||
|
@ -1,17 +1,25 @@
|
||||
package main.ui.extensions;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Font;
|
||||
import main.ui.buttons.SimpleClickButton;
|
||||
import main.extensions.Extension;
|
||||
import main.misc.ConfirmationDialog;
|
||||
import main.ui.buttons.*;
|
||||
import main.ui.extensions.executer.ExecutionInfo;
|
||||
import main.ui.extensions.executer.ExtensionRunner;
|
||||
import main.ui.extensions.executer.ExtensionRunnerFactory;
|
||||
import main.ui.extensions.executer.NormalExtensionRunner;
|
||||
import main.ui.scheduler.ScheduleItem;
|
||||
import main.ui.buttons.DeleteButton;
|
||||
import main.ui.buttons.EditButton;
|
||||
import main.ui.buttons.PauseResumeButton;
|
||||
|
||||
import javax.tools.Tool;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 19/07/18.
|
||||
@ -19,17 +27,27 @@ import main.ui.buttons.PauseResumeButton;
|
||||
public class ExtensionItemContainer extends GridPane {
|
||||
|
||||
public static final int[] columnWidths = {22, 34, 18, 13, 11};
|
||||
GEarthExtension item;
|
||||
private GEarthExtension item;
|
||||
|
||||
Label titleLabel;
|
||||
Label descriptionLabel;
|
||||
Label authorLabel;
|
||||
Label versionLabel;
|
||||
private Label titleLabel;
|
||||
private Label descriptionLabel;
|
||||
private Label authorLabel;
|
||||
private Label versionLabel;
|
||||
|
||||
VBox parent;
|
||||
private VBox parent;
|
||||
|
||||
ExtensionItemContainer(GEarthExtension item, VBox parent, ScrollPane scrollPane) {
|
||||
private volatile int port;
|
||||
|
||||
private HBox buttonsBox = null;
|
||||
private HBox additionalButtonBox = null;
|
||||
|
||||
private ExitButton exitButton;
|
||||
private SimpleClickButton clickButton;
|
||||
private ReloadButton reloadButton;
|
||||
|
||||
ExtensionItemContainer(GEarthExtension item, VBox parent, ScrollPane scrollPane, int port) {
|
||||
super();
|
||||
this.port = port;
|
||||
setGridLinesVisible(true);
|
||||
VBox.setMargin(this, new Insets(2, -2, -2, -2));
|
||||
|
||||
@ -61,28 +79,72 @@ public class ExtensionItemContainer extends GridPane {
|
||||
add(authorLabel, 2, 0);
|
||||
add(versionLabel, 3, 0);
|
||||
|
||||
// getChildren().addAll(indexLabel, packetLabel, delayLabel, destinationLabel);
|
||||
|
||||
|
||||
|
||||
DeleteButton deleteButton = new DeleteButton();
|
||||
deleteButton.show();
|
||||
deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> item.isRemoveClickTrigger());
|
||||
SimpleClickButton clickButton = new SimpleClickButton();
|
||||
exitButton = new ExitButton();
|
||||
Tooltip delete = new Tooltip("Close connection with this extension");
|
||||
Tooltip.install(exitButton,delete);
|
||||
exitButton.show();
|
||||
exitButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> item.isRemoveClickTrigger());
|
||||
clickButton = new SimpleClickButton();
|
||||
clickButton.show();
|
||||
clickButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> item.isClickTrigger());
|
||||
|
||||
HBox buttonsBox = new HBox(clickButton, deleteButton);
|
||||
buttonsBox.setSpacing(10);
|
||||
buttonsBox = new HBox(clickButton, exitButton);
|
||||
|
||||
reloadButton = new ReloadButton();
|
||||
Tooltip reload = new Tooltip("Restart this extension");
|
||||
Tooltip.install(reloadButton, reload);
|
||||
reloadButton.show();
|
||||
reloadButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
reloadButton.setVisible(false);
|
||||
ExtensionRunner runner = ExtensionRunnerFactory.get();
|
||||
runner.tryRunExtension(Paths.get(NormalExtensionRunner.JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY, item.getFileName()).toString(), port);
|
||||
});
|
||||
|
||||
DeleteButton deleteButton = new DeleteButton();
|
||||
Tooltip uninstall = new Tooltip("Uninstall this extension");
|
||||
Tooltip.install(deleteButton, uninstall);
|
||||
deleteButton.show();
|
||||
GridPane this2 = this;
|
||||
deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
boolean delet_dis = true;
|
||||
|
||||
if (ConfirmationDialog.showDialog) {
|
||||
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION,
|
||||
"Confirmation Dialog", null,
|
||||
"Are you sure want to uninstall this extension?", "Do not ask again",
|
||||
ButtonType.YES, ButtonType.NO
|
||||
);
|
||||
|
||||
if (!(alert.showAndWait().filter(t -> t == ButtonType.YES).isPresent())) {
|
||||
delet_dis = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (delet_dis) {
|
||||
ExtensionRunner runner = ExtensionRunnerFactory.get();
|
||||
runner.uninstallExtension(item.getFileName());
|
||||
parent.getChildren().remove(this2);
|
||||
}
|
||||
});
|
||||
|
||||
additionalButtonBox = new HBox(reloadButton, deleteButton);
|
||||
|
||||
clickButton.setVisible(item.isFireButtonUsed());
|
||||
exitButton.setVisible(item.isLeaveButtonVisible());
|
||||
deleteButton.setVisible(item.isDeleteButtonVisible());
|
||||
|
||||
buttonsBox.setSpacing(8);
|
||||
buttonsBox.setAlignment(Pos.CENTER);
|
||||
additionalButtonBox.setSpacing(8);
|
||||
additionalButtonBox.setAlignment(Pos.CENTER);
|
||||
|
||||
GridPane.setMargin(buttonsBox, new Insets(0, 5, 0, 5));
|
||||
GridPane.setMargin(additionalButtonBox, new Insets(0, 5, 0, 5));
|
||||
add(buttonsBox, 4, 0);
|
||||
|
||||
parent.getChildren().add(this);
|
||||
|
||||
|
||||
GridPane this2 = this;
|
||||
item.onDelete(observable -> parent.getChildren().remove(this2));
|
||||
initExtension();
|
||||
}
|
||||
|
||||
private Label initNewLabelColumn(String text) {
|
||||
@ -92,4 +154,51 @@ public class ExtensionItemContainer extends GridPane {
|
||||
label.setText(text);
|
||||
return label;
|
||||
}
|
||||
|
||||
private EventHandler<MouseEvent> onExit = null;
|
||||
private EventHandler<MouseEvent> onClick = null;
|
||||
|
||||
void initExtension(){
|
||||
if (onExit != null) {
|
||||
exitButton.removeEventHandler(MouseEvent.MOUSE_CLICKED, onExit);
|
||||
clickButton.removeEventHandler(MouseEvent.MOUSE_CLICKED, onClick);
|
||||
}
|
||||
onExit = event -> item.isRemoveClickTrigger();
|
||||
onClick = event -> item.isClickTrigger();
|
||||
|
||||
exitButton.addEventHandler(MouseEvent.MOUSE_CLICKED, onExit);
|
||||
clickButton.addEventHandler(MouseEvent.MOUSE_CLICKED, onClick);
|
||||
|
||||
ExtensionItemContainer this2 = this;
|
||||
item.onDelete(observable -> {
|
||||
if (item.isInstalledExtension()) {
|
||||
setBackground(new Background(new BackgroundFill(Paint.valueOf("#cccccc"),null, null)));
|
||||
getChildren().remove(buttonsBox);
|
||||
add(additionalButtonBox, 4, 0);
|
||||
reloadButton.setVisible(true);
|
||||
}
|
||||
else {
|
||||
parent.getChildren().remove(this2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void hasReconnected(GEarthExtension extension) {
|
||||
item = extension;
|
||||
initExtension();
|
||||
|
||||
setBackground(new Background(new BackgroundFill(Paint.valueOf("#ffffff"),null, null)));
|
||||
getChildren().remove(additionalButtonBox);
|
||||
if (buttonsBox != null) {
|
||||
add(buttonsBox, 4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//returns null if there is none
|
||||
String getExtensionFileName() {
|
||||
if (item.isInstalledExtension()) {
|
||||
return item.getFileName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
45
src/main/ui/extensions/ExtensionItemContainerProducer.java
Normal file
@ -0,0 +1,45 @@
|
||||
package main.ui.extensions;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 27/09/18.
|
||||
*/
|
||||
public class ExtensionItemContainerProducer {
|
||||
|
||||
private VBox parent;
|
||||
private ScrollPane scrollPane;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private int port = -1;
|
||||
|
||||
public ExtensionItemContainerProducer(VBox parent, ScrollPane scrollPane) {
|
||||
this.parent = parent;
|
||||
this.scrollPane = scrollPane;
|
||||
}
|
||||
|
||||
void extensionConnected(GEarthExtension extension) {
|
||||
synchronized (lock) {
|
||||
if (extension.isInstalledExtension()) {
|
||||
for (Node n : parent.getChildren()) {
|
||||
if (n instanceof ExtensionItemContainer) {
|
||||
ExtensionItemContainer container = (ExtensionItemContainer) n;
|
||||
if (container.getExtensionFileName().equals(extension.getFileName())) {
|
||||
container.hasReconnected(extension);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new ExtensionItemContainer(extension, parent, scrollPane, port);
|
||||
}
|
||||
}
|
||||
|
||||
void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
}
|
@ -83,7 +83,7 @@
|
||||
<Insets left="3.0" />
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
<Button fx:id="btn_install" disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="3" />
|
||||
<Button fx:id="btn_install" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="3" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
|
@ -9,10 +9,19 @@ import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import main.Main;
|
||||
import main.protocol.*;
|
||||
import main.ui.SubForm;
|
||||
import main.ui.extensions.executer.ExecutionInfo;
|
||||
import main.ui.extensions.executer.ExtensionRunner;
|
||||
import main.ui.extensions.executer.ExtensionRunnerFactory;
|
||||
import main.ui.scheduler.ScheduleItem;
|
||||
import sun.misc.ExtensionInfo;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
@ -108,6 +117,9 @@ public class Extensions extends SubForm {
|
||||
public GridPane header_ext;
|
||||
public ScrollPane scroller;
|
||||
|
||||
private ExtensionRunner extensionRunner = null;
|
||||
private GEarthExtensionsRegistrer extensionsRegistrer = null;
|
||||
|
||||
public static class OUTGOING_MESSAGES_IDS {
|
||||
public static final int ONDOUBLECLICK = 1;
|
||||
public static final int INFOREQUEST = 2; // backend: implemented
|
||||
@ -138,6 +150,8 @@ public class Extensions extends SubForm {
|
||||
}
|
||||
|
||||
protected void onParentSet() {
|
||||
ExtensionItemContainerProducer producer = new ExtensionItemContainerProducer(extensioncontainer, scroller);
|
||||
|
||||
getHConnection().addStateChangeListener((oldState, newState) -> {
|
||||
if (newState == HConnection.State.CONNECTED) {
|
||||
for (GEarthExtension extension : gEarthExtensions) {
|
||||
@ -217,7 +231,6 @@ public class Extensions extends SubForm {
|
||||
});
|
||||
|
||||
|
||||
GEarthExtensionsRegistrer extensionsRegistrer = null;
|
||||
HashMap<GEarthExtension, GEarthExtension.ReceiveMessageListener> messageListeners = new HashMap<>();
|
||||
try {
|
||||
extensionsRegistrer = new GEarthExtensionsRegistrer(new GEarthExtensionsRegistrer.ExtensionRegisterObserver() {
|
||||
@ -259,7 +272,7 @@ public class Extensions extends SubForm {
|
||||
if (getHConnection().getState() == HConnection.State.CONNECTED) {
|
||||
extension.sendMessage(new HPacket(OUTGOING_MESSAGES_IDS.CONNECTIONSTART));
|
||||
}
|
||||
Platform.runLater(() -> new ExtensionItemContainer(extension, extensioncontainer, scroller));
|
||||
Platform.runLater(() -> producer.extensionConnected(extension));
|
||||
extension.onRemoveClick(observable -> {
|
||||
try {
|
||||
extension.getConnection().close();
|
||||
@ -285,11 +298,25 @@ public class Extensions extends SubForm {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
producer.setPort(extensionsRegistrer.getPort());
|
||||
ext_port.setText(extensionsRegistrer.getPort()+"");
|
||||
// System.out.println("Extension server registered on port: " + extensionsRegistrer.getPort());
|
||||
|
||||
extensionRunner = ExtensionRunnerFactory.get();
|
||||
extensionRunner.runAllExtensions(extensionsRegistrer.getPort());
|
||||
}
|
||||
|
||||
|
||||
public void installBtnClicked(ActionEvent actionEvent) {
|
||||
List<ScheduleItem> list = new ArrayList<>();
|
||||
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Install extension");
|
||||
fileChooser.getExtensionFilters().addAll(
|
||||
new FileChooser.ExtensionFilter("G-Earth extensions", ExecutionInfo.ALLOWEDEXTENSIONTYPES));
|
||||
File selectedFile = fileChooser.showOpenDialog(parentController.getStage());
|
||||
if (selectedFile != null) {
|
||||
extensionRunner.installAndRunExtension(selectedFile.getPath(), extensionsRegistrer.getPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
package main.ui.extensions;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import main.protocol.HMessage;
|
||||
import main.protocol.HPacket;
|
||||
import main.protocol.packethandler.PayloadBuffer;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -24,6 +20,13 @@ public class GEarthExtension {
|
||||
private String version;
|
||||
private String description;
|
||||
|
||||
private boolean fireEventButtonVisible;
|
||||
private boolean leaveButtonVisible;
|
||||
private boolean deleteButtonVisible;
|
||||
|
||||
private boolean isInstalledExtension; // <- extension is in the extensions directory
|
||||
private String fileName;
|
||||
|
||||
private Socket connection;
|
||||
|
||||
//calls callback when the extension is creatd
|
||||
@ -53,10 +56,7 @@ public class GEarthExtension {
|
||||
|
||||
if (packet.headerId() == Extensions.INCOMING_MESSAGES_IDS.EXTENSIONINFO) {
|
||||
GEarthExtension gEarthExtension = new GEarthExtension(
|
||||
packet.readString(),
|
||||
packet.readString(),
|
||||
packet.readString(),
|
||||
packet.readString(),
|
||||
packet,
|
||||
connection,
|
||||
onDisconnectedCallback
|
||||
);
|
||||
@ -70,11 +70,19 @@ public class GEarthExtension {
|
||||
|
||||
}
|
||||
|
||||
private GEarthExtension(String title, String author, String version, String description, Socket connection, OnDisconnectedCallback onDisconnectedCallback) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.version = version;
|
||||
this.description = description;
|
||||
private GEarthExtension(HPacket extensionInfo, Socket connection, OnDisconnectedCallback onDisconnectedCallback) {
|
||||
this.title = extensionInfo.readString();
|
||||
this.author = extensionInfo.readString();
|
||||
this.version = extensionInfo.readString();
|
||||
this.description = extensionInfo.readString();
|
||||
this.fireEventButtonVisible = extensionInfo.readBoolean();
|
||||
|
||||
this.isInstalledExtension = extensionInfo.readBoolean();
|
||||
this.fileName = extensionInfo.readString();
|
||||
|
||||
this.leaveButtonVisible = extensionInfo.readBoolean();
|
||||
this.deleteButtonVisible = extensionInfo.readBoolean();
|
||||
|
||||
this.connection = connection;
|
||||
|
||||
GEarthExtension selff = this;
|
||||
@ -126,20 +134,31 @@ public class GEarthExtension {
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
public boolean isFireButtonUsed() {
|
||||
return fireEventButtonVisible;
|
||||
}
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
public boolean isDeleteButtonVisible() {
|
||||
return deleteButtonVisible;
|
||||
}
|
||||
public boolean isLeaveButtonVisible() {
|
||||
return leaveButtonVisible;
|
||||
}
|
||||
|
||||
|
||||
public boolean isInstalledExtension() {
|
||||
return isInstalledExtension;
|
||||
}
|
||||
|
||||
public boolean closeConnection() {
|
||||
try {
|
||||
|
39
src/main/ui/extensions/executer/ExecutionInfo.java
Normal file
@ -0,0 +1,39 @@
|
||||
package main.ui.extensions.executer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
public class ExecutionInfo {
|
||||
|
||||
private static Map<String, String> extensionTypeToExecutionCommand;
|
||||
public final static List<String> ALLOWEDEXTENSIONTYPES;
|
||||
public final static String EXTENSIONSDIRECTORY = "Extensions";
|
||||
|
||||
static {
|
||||
extensionTypeToExecutionCommand = new HashMap<>();
|
||||
extensionTypeToExecutionCommand.put("*.jar","java -jar {path}");
|
||||
extensionTypeToExecutionCommand.put("*.py","python {path}");
|
||||
extensionTypeToExecutionCommand.put("*.py3","python3 {path}");
|
||||
extensionTypeToExecutionCommand.put("*.sh","{path}");
|
||||
extensionTypeToExecutionCommand.put("*.exe","{path}");
|
||||
|
||||
for(String type : extensionTypeToExecutionCommand.keySet()) {
|
||||
extensionTypeToExecutionCommand.put(
|
||||
type,
|
||||
extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename}"
|
||||
);
|
||||
}
|
||||
|
||||
ALLOWEDEXTENSIONTYPES = new ArrayList<>(extensionTypeToExecutionCommand.keySet());
|
||||
}
|
||||
|
||||
public static String getExecutionCommand(String type) {
|
||||
return extensionTypeToExecutionCommand.get(type);
|
||||
}
|
||||
|
||||
}
|
21
src/main/ui/extensions/executer/ExtensionRunner.java
Normal file
@ -0,0 +1,21 @@
|
||||
package main.ui.extensions.executer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 21/09/18.
|
||||
*/
|
||||
public interface ExtensionRunner {
|
||||
|
||||
void runAllExtensions(int port);
|
||||
|
||||
void installAndRunExtension(String path, int port);
|
||||
|
||||
void tryRunExtension(String path, int port);
|
||||
|
||||
void uninstallExtension(String path);
|
||||
}
|
17
src/main/ui/extensions/executer/ExtensionRunnerFactory.java
Normal file
@ -0,0 +1,17 @@
|
||||
package main.ui.extensions.executer;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
public class ExtensionRunnerFactory {
|
||||
|
||||
private static ExtensionRunner runner = obtain();
|
||||
|
||||
public static ExtensionRunner get() {
|
||||
return runner;
|
||||
}
|
||||
|
||||
private static ExtensionRunner obtain() {
|
||||
return new NormalExtensionRunner();
|
||||
}
|
||||
}
|
128
src/main/ui/extensions/executer/NormalExtensionRunner.java
Normal file
@ -0,0 +1,128 @@
|
||||
package main.ui.extensions.executer;
|
||||
|
||||
import main.Main;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 22/09/18.
|
||||
*/
|
||||
public class NormalExtensionRunner implements ExtensionRunner {
|
||||
|
||||
public static final String JARPATH = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParent();
|
||||
|
||||
@Override
|
||||
public void runAllExtensions(int port) {
|
||||
if (dirExists(ExecutionInfo.EXTENSIONSDIRECTORY)){
|
||||
File folder =
|
||||
new File(JARPATH +
|
||||
FileSystems.getDefault().getSeparator()+
|
||||
ExecutionInfo.EXTENSIONSDIRECTORY);
|
||||
|
||||
File[] childs = folder.listFiles();
|
||||
for (File file : childs) {
|
||||
tryRunExtension(file.getPath(), port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installAndRunExtension(String path, int port) {
|
||||
if (!dirExists(ExecutionInfo.EXTENSIONSDIRECTORY)) {
|
||||
createDirectory(ExecutionInfo.EXTENSIONSDIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
String name = Paths.get(path).getFileName().toString();
|
||||
String[] split = name.split("\\.");
|
||||
String ext = "*." + split[split.length - 1];
|
||||
|
||||
String realname = String.join(".",Arrays.copyOf(split, split.length-1));
|
||||
String newname = realname + "-" + getRandomString() + ext.substring(1);
|
||||
|
||||
|
||||
Path originalPath = Paths.get(path);
|
||||
Path newPath = Paths.get(
|
||||
JARPATH,
|
||||
ExecutionInfo.EXTENSIONSDIRECTORY,
|
||||
newname
|
||||
);
|
||||
|
||||
try {
|
||||
Files.copy(
|
||||
originalPath,
|
||||
newPath
|
||||
);
|
||||
|
||||
addExecPermission(newPath.toString());
|
||||
tryRunExtension(newPath.toString(), port);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void tryRunExtension(String path, int port) {
|
||||
try {
|
||||
Runtime.getRuntime().exec(
|
||||
ExecutionInfo.getExecutionCommand(getFileExtension(path))
|
||||
.replace("{path}", path)
|
||||
.replace("{port}", port+"")
|
||||
.replace("{filename}", Paths.get(path).getFileName().toString())
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallExtension(String filename) {
|
||||
try {
|
||||
Files.delete(Paths.get(
|
||||
JARPATH,
|
||||
ExecutionInfo.EXTENSIONSDIRECTORY,
|
||||
filename
|
||||
));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addExecPermission(String path) {
|
||||
//not needed at first sight
|
||||
}
|
||||
|
||||
private String getFileExtension(String path) {
|
||||
String name = Paths.get(path).getFileName().toString();
|
||||
String[] split = name.split("\\.");
|
||||
return "*." + split[split.length - 1];
|
||||
}
|
||||
|
||||
private boolean dirExists(String dir) {
|
||||
return Files.isDirectory(Paths.get(JARPATH, dir));
|
||||
}
|
||||
private void createDirectory(String dir) {
|
||||
if (!dirExists(dir)) {
|
||||
try {
|
||||
Files.createDirectories(Paths.get(JARPATH, dir));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
private String getRandomString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
builder.append(r.nextInt(10));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ public class Info extends SubForm {
|
||||
|
||||
public void initialize() {
|
||||
String[] lines = {
|
||||
"G-Earth",
|
||||
"G-Earth 0.1.1",
|
||||
"Linux Habbo Packet Manipulator",
|
||||
"",
|
||||
"Made by:",
|
||||
|
@ -8,7 +8,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Created by Jonas on 04/04/18.
|
||||
*/
|
||||
class GnomeTerminalLogger extends SimpleTerminalLogger {
|
||||
class LinuxTerminalLogger extends SimpleTerminalLogger {
|
||||
|
||||
public final static Map<String, String> colorizePackets;
|
||||
static {
|
@ -1,14 +1,19 @@
|
||||
package main.ui.logger.loggerdisplays;
|
||||
|
||||
import main.misc.OSValidator;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 04/04/18.
|
||||
*/
|
||||
public class PacketLoggerFactory {
|
||||
|
||||
public static PacketLogger get() {
|
||||
if (System.getenv("XDG_CURRENT_DESKTOP") != null && System.getenv("XDG_CURRENT_DESKTOP").toLowerCase().contains("gnome")) {
|
||||
return new GnomeTerminalLogger();
|
||||
if (OSValidator.isUnix()) {
|
||||
return new LinuxTerminalLogger();
|
||||
}
|
||||
// if (System.getenv("XDG_CURRENT_DESKTOP") != null && System.getenv("XDG_CURRENT_DESKTOP").toLowerCase().contains("gnome")) {
|
||||
// return new GnomeTerminalLogger();
|
||||
// }
|
||||
return new SimpleTerminalLogger();
|
||||
}
|
||||
|
||||
|