diff --git a/.gitignore b/.gitignore index a520cf6..b548b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ out/ G-Earth2.iml +Extensions/ diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..889dc56 --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: main.extensions.examples.adminonconnect.AdminOnConnect + diff --git a/src/json-simple-1.1.1.jar b/src/json-simple-1.1.1.jar new file mode 100644 index 0000000..66347a6 Binary files /dev/null and b/src/json-simple-1.1.1.jar differ diff --git a/src/main/Main.java b/src/main/Main.java index 62a8940..aff2565 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -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(); }); } diff --git a/src/main/extensions/Extension.java b/src/main/extensions/Extension.java index ee236e4..525582c 100644 --- a/src/main/extensions/Extension.java +++ b/src/main/extensions/Extension.java @@ -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> incomingMessageListeners = new HashMap<>(); - private Map> outgoingMessageListeners = new HashMap<>(); + private final Map> incomingMessageListeners = new HashMap<>(); + private final Map> 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; - 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); + List 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)); + } + } } } - 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); - habboMessage.getPacket().setReadIndex(6); - } + 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,10 +259,13 @@ public abstract class Extension { incomingMessageListeners : outgoingMessageListeners; - if (!listeners.containsKey(headerId)) { - listeners.put(headerId, new ArrayList<>()); + 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 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) 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); + } } diff --git a/src/main/extensions/ExtensionForm.java b/src/main/extensions/ExtensionForm.java new file mode 100644 index 0000000..fe50b9a --- /dev/null +++ b/src/main/extensions/ExtensionForm.java @@ -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(){} +} diff --git a/src/main/extensions/ExtensionInfo.java b/src/main/extensions/ExtensionInfo.java new file mode 100644 index 0000000..a4f16d7 --- /dev/null +++ b/src/main/extensions/ExtensionInfo.java @@ -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(); +} \ No newline at end of file diff --git a/src/main/extensions/examples/AdminOnConnect.java b/src/main/extensions/examples/adminonconnect/AdminOnConnect.java similarity index 67% rename from src/main/extensions/examples/AdminOnConnect.java rename to src/main/extensions/examples/adminonconnect/AdminOnConnect.java index 11f1dde..499f3e1 100644 --- a/src/main/extensions/examples/AdminOnConnect.java +++ b/src/main/extensions/examples/adminonconnect/AdminOnConnect.java @@ -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"; - } } diff --git a/src/main/extensions/examples/blockreplacepackets/BlockAndReplacePackets.java b/src/main/extensions/examples/blockreplacepackets/BlockAndReplacePackets.java new file mode 100644 index 0000000..5bf6606 --- /dev/null +++ b/src/main/extensions/examples/blockreplacepackets/BlockAndReplacePackets.java @@ -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)); + } +} diff --git a/src/main/extensions/examples/blockreplacepackets/blockreplace.fxml b/src/main/extensions/examples/blockreplacepackets/blockreplace.fxml new file mode 100644 index 0000000..917179b --- /dev/null +++ b/src/main/extensions/examples/blockreplacepackets/blockreplace.fxml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/extensions/examples/SpeechColorizer.java b/src/main/extensions/examples/speechcolorizer/SpeechColorizer.java similarity index 83% rename from src/main/extensions/examples/SpeechColorizer.java rename to src/main/extensions/examples/speechcolorizer/SpeechColorizer.java index 5ff340f..919c76c 100644 --- a/src/main/extensions/examples/SpeechColorizer.java +++ b/src/main/extensions/examples/speechcolorizer/SpeechColorizer.java @@ -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); diff --git a/src/main/extensions/extra/Inspector.java b/src/main/extensions/extra/Inspector.java new file mode 100644 index 0000000..6da0308 --- /dev/null +++ b/src/main/extensions/extra/Inspector.java @@ -0,0 +1,7 @@ +package main.extensions.extra; + +/** + * Created by Jonas on 22/09/18. + */ +public class Inspector { +} diff --git a/src/main/misc/Cacher.java b/src/main/misc/Cacher.java index be593c1..021be4f 100644 --- a/src/main/misc/Cacher.java +++ b/src/main/misc/Cacher.java @@ -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()) { + private static boolean cacheFileExists() { + File f = new File(getCacheDir(), CACHEFILENAME); + return (f.exists() && !f.isDirectory()); + } + + private static JSONObject getCacheContents() { + if (cacheFileExists()) { try { - List lines = Files.readAllLines(f.toPath()); + File f = new File(getCacheDir(), CACHEFILENAME); + String contents = String.join("\n", Files.readAllLines(f.toPath())); - for (String line : lines) { - if (line.startsWith(key+":")) { - return true; - } - } - - } catch (IOException e) { + JSONParser parser = new JSONParser(); + return (JSONObject) parser.parse(contents); + } catch (IOException | ParseException e) { e.printStackTrace(); } } - return false; + return new JSONObject(); } + private static void updateCache(JSONObject contents) { + try (FileWriter file = new FileWriter(new File(getCacheDir(), CACHEFILENAME))) { - public static String get(String key) { - File f = new File(getCacheDir(), "cache.txt"); - if (f.exists()) { - try { - List lines = Files.readAllLines(f.toPath()); + file.write(contents.toJSONString()); + file.flush(); - for (String line : lines) { - if (line.startsWith(key+":")) { - return line.split(":")[1]; - } - } - - } catch (IOException e) { - e.printStackTrace(); - } - } - 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 lines = new ArrayList(); - 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(); + } catch (IOException e) { + e.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(); - } - } + public static void put(String key, Object val) { + JSONObject object = getCacheContents(); + if (object.containsKey(key)) object.remove(key); -// 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 lines = new ArrayList(); - 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(); - } + object.put(key, val); + updateCache(object); } + public static Object get(String key) { + JSONObject object = getCacheContents(); - public static void update(String key, String value) { - remove(key); - add(key, value); + return object.get(key); } - - - 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()); } } diff --git a/src/main/misc/ConfirmationDialog.java b/src/main/misc/ConfirmationDialog.java new file mode 100644 index 0000000..cc75890 --- /dev/null +++ b/src/main/misc/ConfirmationDialog.java @@ -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 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; + } + + +} diff --git a/src/main/protocol/HConnection.java b/src/main/protocol/HConnection.java index f801fda..4dfa583 100644 --- a/src/main/protocol/HConnection.java +++ b/src/main/protocol/HConnection.java @@ -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 sendToClientAsyncQueue = new LinkedList<>(); private final Queue sendToServerAsyncQueue = new LinkedList<>(); @@ -63,16 +65,27 @@ public class HConnection { CONNECTED // CONNECTED } - private static List autoDetectHosts; + public static List 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 additionalCachedHotels = (List) 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 additionalCachedHotels = (List) 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 potentialHost = new ArrayList<>(); potentialHost.add(domain+":"+port); prepare(potentialHost); @@ -134,17 +157,29 @@ public class HConnection { removeFromHosts(); } - try { - for (String host : allPotentialHosts) { - InetAddress address = InetAddress.getByName(host.split(":")[0]); - actual_domain.add(address.getHostAddress()); - } - setState(State.PREPARED); - } catch (UnknownHostException e) { - e.printStackTrace(); - setState(State.NOT_CONNECTED); + List 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(); + actual_domain.add(null); + willremove.add(host); + } } + + List additionalCachedHotels = (List) 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 { @@ -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 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 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; diff --git a/src/main/protocol/memory/Rc4Obtainer.java b/src/main/protocol/memory/Rc4Obtainer.java index cd173fb..62d5f7e 100644 --- a/src/main/protocol/memory/Rc4Obtainer.java +++ b/src/main/protocol/memory/Rc4Obtainer.java @@ -72,6 +72,7 @@ public class Rc4Obtainer { if (payloadBuffer.peak().length == 0) { outgoingHandler.setRc4(rc4Tryout); + incomingHandler.setRc4(rc4Tryout); break outerloop; } diff --git a/src/main/protocol/packethandler/Handler.java b/src/main/protocol/packethandler/Handler.java index ab0d206..fd12dff 100644 --- a/src/main/protocol/packethandler/Handler.java +++ b/src/main/protocol/packethandler/Handler.java @@ -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 bufferListeners = new ArrayList<>(); public void addBufferListener(BufferListener listener) { diff --git a/src/main/protocol/packethandler/IncomingHandler.java b/src/main/protocol/packethandler/IncomingHandler.java index a085e6a..168a70c 100644 --- a/src/main/protocol/packethandler/IncomingHandler.java +++ b/src/main/protocol/packethandler/IncomingHandler.java @@ -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 --"); + } } diff --git a/src/main/protocol/packethandler/OutgoingHandler.java b/src/main/protocol/packethandler/OutgoingHandler.java index ece5193..545dbe9 100644 --- a/src/main/protocol/packethandler/OutgoingHandler.java +++ b/src/main/protocol/packethandler/OutgoingHandler.java @@ -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 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,21 +60,9 @@ 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++) { encrbuffer[i] = tempEncryptedBuffer.get(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 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 --"); + } } diff --git a/src/main/ui/buttons/BoxButton.java b/src/main/ui/buttons/BoxButton.java index 4ae2ad3..f0abd39 100644 --- a/src/main/ui/buttons/BoxButton.java +++ b/src/main/ui/buttons/BoxButton.java @@ -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); diff --git a/src/main/ui/buttons/DeleteButton.java b/src/main/ui/buttons/DeleteButton.java index 47ac9f9..2d91f52 100644 --- a/src/main/ui/buttons/DeleteButton.java +++ b/src/main/ui/buttons/DeleteButton.java @@ -1,5 +1,9 @@ package main.ui.buttons; +import org.omg.CORBA.Environment; + +import java.io.File; + public class DeleteButton extends BoxButton { public DeleteButton() { diff --git a/src/main/ui/buttons/ExitButton.java b/src/main/ui/buttons/ExitButton.java new file mode 100644 index 0000000..faaccd8 --- /dev/null +++ b/src/main/ui/buttons/ExitButton.java @@ -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"); + } +} diff --git a/src/main/ui/buttons/FireButton.java b/src/main/ui/buttons/FireButton.java new file mode 100644 index 0000000..798dbb3 --- /dev/null +++ b/src/main/ui/buttons/FireButton.java @@ -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"); + } +} diff --git a/src/main/ui/buttons/PauseResumeButton.java b/src/main/ui/buttons/PauseResumeButton.java index 779a88e..d8ca648 100644 --- a/src/main/ui/buttons/PauseResumeButton.java +++ b/src/main/ui/buttons/PauseResumeButton.java @@ -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); diff --git a/src/main/ui/buttons/ReloadButton.java b/src/main/ui/buttons/ReloadButton.java new file mode 100644 index 0000000..e294fba --- /dev/null +++ b/src/main/ui/buttons/ReloadButton.java @@ -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"); } +} diff --git a/src/main/ui/buttons/ButtonDelete.png b/src/main/ui/buttons/files/ButtonDelete.png similarity index 100% rename from src/main/ui/buttons/ButtonDelete.png rename to src/main/ui/buttons/files/ButtonDelete.png diff --git a/src/main/ui/buttons/ButtonDeleteHover.png b/src/main/ui/buttons/files/ButtonDeleteHover.png similarity index 100% rename from src/main/ui/buttons/ButtonDeleteHover.png rename to src/main/ui/buttons/files/ButtonDeleteHover.png diff --git a/src/main/ui/buttons/ButtonEdit.png b/src/main/ui/buttons/files/ButtonEdit.png similarity index 100% rename from src/main/ui/buttons/ButtonEdit.png rename to src/main/ui/buttons/files/ButtonEdit.png diff --git a/src/main/ui/buttons/ButtonEditHover.png b/src/main/ui/buttons/files/ButtonEditHover.png similarity index 100% rename from src/main/ui/buttons/ButtonEditHover.png rename to src/main/ui/buttons/files/ButtonEditHover.png diff --git a/src/main/ui/buttons/files/ButtonExit.png b/src/main/ui/buttons/files/ButtonExit.png new file mode 100644 index 0000000..4b92915 Binary files /dev/null and b/src/main/ui/buttons/files/ButtonExit.png differ diff --git a/src/main/ui/buttons/files/ButtonExitHover.png b/src/main/ui/buttons/files/ButtonExitHover.png new file mode 100644 index 0000000..49987cf Binary files /dev/null and b/src/main/ui/buttons/files/ButtonExitHover.png differ diff --git a/src/main/ui/buttons/files/ButtonFire.png b/src/main/ui/buttons/files/ButtonFire.png new file mode 100644 index 0000000..90ee3fd Binary files /dev/null and b/src/main/ui/buttons/files/ButtonFire.png differ diff --git a/src/main/ui/buttons/files/ButtonFireHover.png b/src/main/ui/buttons/files/ButtonFireHover.png new file mode 100644 index 0000000..8a14c82 Binary files /dev/null and b/src/main/ui/buttons/files/ButtonFireHover.png differ diff --git a/src/main/ui/buttons/ButtonPause.png b/src/main/ui/buttons/files/ButtonPause.png similarity index 100% rename from src/main/ui/buttons/ButtonPause.png rename to src/main/ui/buttons/files/ButtonPause.png diff --git a/src/main/ui/buttons/ButtonPauseHover.png b/src/main/ui/buttons/files/ButtonPauseHover.png similarity index 100% rename from src/main/ui/buttons/ButtonPauseHover.png rename to src/main/ui/buttons/files/ButtonPauseHover.png diff --git a/src/main/ui/buttons/files/ButtonReload.png b/src/main/ui/buttons/files/ButtonReload.png new file mode 100644 index 0000000..4440bc2 Binary files /dev/null and b/src/main/ui/buttons/files/ButtonReload.png differ diff --git a/src/main/ui/buttons/files/ButtonReloadHover.png b/src/main/ui/buttons/files/ButtonReloadHover.png new file mode 100644 index 0000000..365372d Binary files /dev/null and b/src/main/ui/buttons/files/ButtonReloadHover.png differ diff --git a/src/main/ui/buttons/ButtonResume.png b/src/main/ui/buttons/files/ButtonResume.png similarity index 100% rename from src/main/ui/buttons/ButtonResume.png rename to src/main/ui/buttons/files/ButtonResume.png diff --git a/src/main/ui/buttons/ButtonResumeHover.png b/src/main/ui/buttons/files/ButtonResumeHover.png similarity index 100% rename from src/main/ui/buttons/ButtonResumeHover.png rename to src/main/ui/buttons/files/ButtonResumeHover.png diff --git a/src/main/ui/connection/Connection.java b/src/main/ui/connection/Connection.java index b79b9bf..f7122c0 100644 --- a/src/main/ui/connection/Connection.java +++ b/src/main/ui/connection/Connection.java @@ -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 knownHosts = HConnection.autoDetectHosts; + Set hosts = new HashSet<>(); + Set ports = new HashSet<>(); + + for (String h : knownHosts) { + String[] split = h.split(":"); + hosts.add(split[0]); + ports.add(split[1]); + } + + List hostsSorted = new ArrayList<>(hosts); + hostsSorted.sort(String::compareTo); + + List portsSorted = new ArrayList<>(ports); + portsSorted.sort(String::compareTo); + + inpPort.getItems().addAll(portsSorted); + inpHost.getItems().addAll(hostsSorted); inpPort.getSelectionModel().selectFirst(); inpHost.getSelectionModel().selectFirst(); diff --git a/src/main/ui/extensions/ExtensionItemContainer.java b/src/main/ui/extensions/ExtensionItemContainer.java index 6dfd330..820ab7e 100644 --- a/src/main/ui/extensions/ExtensionItemContainer.java +++ b/src/main/ui/extensions/ExtensionItemContainer.java @@ -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 onExit = null; + private EventHandler 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; + } } diff --git a/src/main/ui/extensions/ExtensionItemContainerProducer.java b/src/main/ui/extensions/ExtensionItemContainerProducer.java new file mode 100644 index 0000000..ba3a9f4 --- /dev/null +++ b/src/main/ui/extensions/ExtensionItemContainerProducer.java @@ -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; + } + +} diff --git a/src/main/ui/extensions/Extensions.fxml b/src/main/ui/extensions/Extensions.fxml index 153d095..b07e03e 100644 --- a/src/main/ui/extensions/Extensions.fxml +++ b/src/main/ui/extensions/Extensions.fxml @@ -83,7 +83,7 @@ -