Kaynağa Gözat

Progress bar + reflection + tabs + lots of shit

tbvns 6 ay önce
ebeveyn
işleme
c21a14dda0

+ 1 - 1
.idea/misc.xml

@@ -8,7 +8,7 @@
       </list>
     </option>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="22" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="temurin-22" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
 </project>

+ 5 - 0
core/pom.xml

@@ -14,6 +14,11 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
     <dependencies>
+        <dependency>
+            <groupId>xyz.tbvns</groupId>
+            <artifactId>PowerGD</artifactId>
+            <version>1.0-ALPHA</version>
+        </dependency>
         <dependency>
             <groupId>com.github.oshi</groupId>
             <artifactId>oshi-core</artifactId>

+ 1 - 0
core/src/main/java/module-info.java

@@ -6,6 +6,7 @@ module core {
     requires lombok;
     requires org.apache.commons.io;
     requires org.apache.commons.codec;
+    requires javafx.controls;
 
     exports xyz.tbvns.core;
     exports xyz.tbvns.core.Objects;

+ 27 - 2
core/src/main/java/xyz/tbvns/core/Decoder.java

@@ -1,5 +1,6 @@
 package xyz.tbvns.core;
 
+import javafx.scene.control.ProgressBar;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.FileUtils;
 
@@ -33,7 +34,21 @@ public class Decoder {
         gzipOutputStream.close();
 
         byte[] levelData = java.util.Base64.getUrlEncoder().encode(outputStream.toByteArray());
-        levelData = xor(levelData, 11);
+
+        return new String(levelData);
+    }
+
+    public static String encodeLevel(String levelStr, UIProgressBar progressBar, float factor) throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
+        gzipOutputStream.write(levelStr.getBytes(StandardCharsets.UTF_8));
+        gzipOutputStream.flush();
+        gzipOutputStream.finish();
+        gzipOutputStream.close();
+        progressBar.updateBar(progressBar.getProgressBar().getProgress() + 0.5 * factor);
+
+        byte[] levelData = java.util.Base64.getUrlEncoder().encode(outputStream.toByteArray());
+        progressBar.updateBar(progressBar.getProgressBar().getProgress() + 0.5 * factor);
 
         return new String(levelData);
     }
@@ -57,7 +72,9 @@ public class Decoder {
         gzipOutputStream.finish();
         gzipOutputStream.close();
 
-        return outputStream.toByteArray();
+        byte[] levelData = xor(outputStream.toByteArray(), 11);
+
+        return levelData;
     }
 
     public static void exportGMD(String name, String data, String path) throws IOException, URISyntaxException {
@@ -66,6 +83,14 @@ public class Decoder {
         FileUtils.writeStringToFile(new File(path), template, StandardCharsets.UTF_8);
     }
 
+    public static void exportGMD(String name, String data, String path, UIProgressBar progressBar, float factor) throws IOException, URISyntaxException {
+        String template = new String(Decoder.class.getResourceAsStream("/template.gmd").readAllBytes());
+        progressBar.updateBar(progressBar.getProgressBar().getProgress() + 0.2 * factor);
+        template = template.replace("%name%", name).replace("%levelData%", encodeLevel(data, progressBar, factor*0.8f));
+        FileUtils.writeStringToFile(new File(path), template, StandardCharsets.UTF_8);
+        progressBar.updateBar(progressBar.getProgressBar().getProgress() + 0.2 * factor);
+    }
+
     public static byte[] xor(byte[] in, int key) {
         byte[] out = new byte[in.length];
         for (int i = 0; i < in.length; i++) {

+ 66 - 0
core/src/main/java/xyz/tbvns/core/UIProgressBar.java

@@ -0,0 +1,66 @@
+package xyz.tbvns.core;
+
+import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.control.ProgressBar;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.GridPane;
+import javafx.stage.Stage;
+import lombok.Getter;
+
+public class UIProgressBar {
+    @Getter private ProgressBar progressBar;
+    @Getter private Stage stage;
+    public void open(String title) {
+        Platform.runLater(() -> {
+            openNow(title);
+        });
+    }
+
+    public void openNow(String title) {
+        stage = new Stage();
+        stage.setWidth(200);
+        stage.setHeight(80);
+        stage.setAlwaysOnTop(true);
+        stage.setResizable(false);
+
+        FlowPane pane = new FlowPane();
+        pane.setPrefWidth(stage.getWidth());
+        pane.setPrefHeight(stage.getHeight());
+        pane.setAlignment(Pos.CENTER);
+
+        Label label = new Label(title);
+        label.setPrefWidth(pane.getPrefWidth() - 20);
+        pane.getChildren().add(label);
+
+        progressBar = new ProgressBar();
+        progressBar.setProgress(0);
+        progressBar.setPrefWidth(pane.getPrefWidth() - 20);
+        pane.getChildren().add(progressBar);
+
+        Scene scene = new Scene(pane);
+        stage.setScene(scene);
+        stage.show();
+    }
+
+    public void updateBar(double value) {
+        Platform.runLater(() -> {
+            progressBar.setProgress(value);
+        });
+    }
+
+    public void close() {
+        new Thread(() -> {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            Platform.runLater(() -> {
+                stage.close();
+            });
+        }).start();
+    }
+}

+ 21 - 16
pom.xml

@@ -42,16 +42,6 @@
 
 
     <dependencies>
-        <dependency>
-            <groupId>org.openjfx</groupId>
-            <artifactId>javafx-controls</artifactId>
-            <version>21</version>
-        </dependency>
-        <dependency>
-            <groupId>org.openjfx</groupId>
-            <artifactId>javafx-fxml</artifactId>
-            <version>21</version>
-        </dependency>
         <dependency>
             <groupId>org.java-websocket</groupId>
             <artifactId>Java-WebSocket</artifactId>
@@ -112,12 +102,6 @@
             <artifactId>oshi-core</artifactId>
             <version>6.6.5</version>
         </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-            <version>1.18.34</version>
-        </dependency>
         <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
         <dependency>
             <groupId>com.fasterxml.jackson.dataformat</groupId>
@@ -130,6 +114,27 @@
             <artifactId>jackson-databind</artifactId>
             <version>2.18.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.10.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+            <version>1.18.34</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openjfx</groupId>
+            <artifactId>javafx-controls</artifactId>
+            <version>21</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openjfx</groupId>
+            <artifactId>javafx-fxml</artifactId>
+            <version>21</version>
+        </dependency>
     </dependencies>
 
 

+ 5 - 0
ui/pom.xml

@@ -54,6 +54,11 @@
             <optional>true</optional>
             <version>1.18.34</version>
         </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.10.2</version>
+        </dependency>
         <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
         <dependency>
             <groupId>ch.qos.logback</groupId>

+ 1 - 0
ui/src/main/java/module-info.java

@@ -8,6 +8,7 @@ module ui {
     requires org.apache.commons.io;
     requires javafx.controls;
     requires java.desktop;
+    requires org.reflections;
 
     exports xyz.tbvns.ui;
 }

+ 26 - 0
ui/src/main/java/xyz/tbvns/ui/LevelEditor/FXTab.java

@@ -0,0 +1,26 @@
+package xyz.tbvns.ui.LevelEditor;
+
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.TabPane;
+import javafx.scene.layout.Pane;
+import xyz.tbvns.core.Objects.Level;
+import xyz.tbvns.core.UIProgressBar;
+
+public interface FXTab {
+    default Pane getPane(Level level) {
+        return new Pane();
+    }
+
+    default Pane getPane(Level level, UIProgressBar progressBar, float factor) {
+        return new Pane();
+    }
+
+    default String getTitle() {
+        return "default title";
+    }
+
+    default void setupResize(TabPane parent) {
+
+    }
+}

+ 40 - 9
ui/src/main/java/xyz/tbvns/ui/LevelEditor/MainWindow.java

@@ -5,23 +5,31 @@ import javafx.scene.control.*;
 import javafx.scene.layout.FlowPane;
 import javafx.scene.layout.Pane;
 import javafx.stage.Stage;
+import org.reflections.Reflections;
+import xyz.tbvns.core.Objects.Level;
+import xyz.tbvns.core.UIProgressBar;
 import xyz.tbvns.ui.Main;
 
+import java.util.Set;
+
 public class MainWindow {
-    public static void open(Stage stage) {
-        stage.hide();
-        Scene scene = new Scene(pane());
+    public static Level level;
+    public static Scene scene;
+    public static void open(Stage stage, Level level) {
+        MainWindow.level = level;
+        scene = new Scene(pane());
         stage.setScene(scene);
+        stage.setTitle("PowerGD: Editing " + level.getName() + " by " + level.getCreator());
         Main.setUpResizeEditMenu(scene);
         stage.show();
+        stage.setHeight(500);
+        stage.setWidth(800);
     }
 
     public static Pane pane() {
         FlowPane pane = new FlowPane();
         pane.getChildren().add(toolBar());
         pane.getChildren().add(tabPane());
-
-
         return pane;
     }
 
@@ -30,11 +38,34 @@ public class MainWindow {
         TabPane pane = new TabPane();
         tabPane = pane;
 
-        Label label = new Label("tab 1");
-        Label label1 = new Label("tab 2");
+        //Usage of reflection to generate tabs
+        Reflections reflections = new Reflections("xyz.tbvns.ui.LevelEditor.tabs");
+        Set<Class<? extends FXTab>> tabs = reflections.getSubTypesOf(FXTab.class);
+        for (Class<? extends FXTab> tab : tabs) {
+             try {
+                 FXTab tabInstance = tab.getConstructor().newInstance();
+                 Tab usableTab = new Tab(tabInstance.getTitle(), tabInstance.getPane(level));
+                 usableTab.setClosable(false);
+                 pane.getTabs().add(usableTab);
+                 tabInstance.setupResize(pane);
+             } catch (Exception e) {
+                 throw new RuntimeException(e);
+             }
+        }
+
+        tabPane.widthProperty().addListener((observableValue, number, t1) -> {
+            for (Tab tab : tabPane.getTabs()) {
+                tab.getContent().prefWidth(t1.floatValue());
+                tab.getContent().setLayoutX(t1.floatValue());
+            }
+        });
 
-        pane.getTabs().add(new Tab("tab 1 !", label));
-        pane.getTabs().add(new Tab("tab 2 !", label1));
+        tabPane.heightProperty().addListener((observableValue, number, t1) -> {
+            for (Tab tab : tabPane.getTabs()) {
+                tab.getContent().prefHeight(t1.floatValue());
+                tab.getContent().setLayoutY(t1.floatValue());
+            }
+        });
 
         return pane;
     }

+ 86 - 0
ui/src/main/java/xyz/tbvns/ui/LevelEditor/tabs/EditLevelString.java

@@ -0,0 +1,86 @@
+package xyz.tbvns.ui.LevelEditor.tabs;
+
+import javafx.scene.Node;
+import javafx.scene.control.*;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.Pane;
+import javafx.stage.FileChooser;
+import xyz.tbvns.core.Decoder;
+import xyz.tbvns.core.Objects.Level;
+import xyz.tbvns.ui.LevelEditor.FXTab;
+import xyz.tbvns.core.UIProgressBar;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+public class EditLevelString implements FXTab {
+    private FlowPane pane;
+    private TextArea area;
+    private ToolBar toolBar;
+
+    @Override
+    public Pane getPane(Level level) {
+        pane = new FlowPane();
+        String levelString = "";
+        try {
+            levelString = Decoder.decodeLevel(level.getEncodedLevelString()).replace(";", ";\n").replace("_", ",");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        area = new TextArea(levelString);
+        pane.getChildren().add(area);
+
+        Button save = new Button("Save");
+        save.setDisable(true);
+        Button export = new Button("Export");
+        export.setOnMouseClicked(mouseEvent -> {
+            export(pane, level, area.getText());
+        });
+        toolBar = new ToolBar(save, export);
+        pane.getChildren().add(toolBar);
+
+        return pane;
+    }
+
+    @Override
+    public String getTitle() {
+        return "Level string";
+    }
+
+    @Override
+    public void setupResize(TabPane parent) {
+        parent.widthProperty().addListener((observableValue, number, t1) -> {
+            toolBar.setPrefWidth(t1.floatValue());
+            area.setPrefWidth(t1.floatValue());
+        });
+
+        parent.heightProperty().addListener((observableValue, number, t1) -> {
+            area.setPrefHeight(t1.floatValue() - toolBar.getHeight() - parent.getTabMaxHeight() - 7);
+        });
+    }
+
+    public void export(Node node, Level level, String levelString) {
+        FileChooser chooser = new FileChooser();
+        chooser.setTitle("Save " + level.getName() + ".gmd");
+        chooser.setInitialFileName(level.getName() + ".gmd");
+        File file = chooser.showSaveDialog(node.getScene().getWindow());
+        if (file != null) {
+            try {
+                UIProgressBar progressBar = new UIProgressBar();
+                progressBar.openNow("Exporting level...");
+                new Thread(() -> {
+                    try {
+                        Decoder.exportGMD(level.getName(), levelString, file.getPath(), progressBar, 1);
+                        progressBar.close();
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }).start();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}

+ 18 - 0
ui/src/main/java/xyz/tbvns/ui/LevelEditor/tabs/EditModels3D.java

@@ -0,0 +1,18 @@
+package xyz.tbvns.ui.LevelEditor.tabs;
+
+import javafx.scene.Scene;
+import javafx.scene.layout.Pane;
+import xyz.tbvns.core.Objects.Level;
+import xyz.tbvns.ui.LevelEditor.FXTab;
+
+public class EditModels3D implements FXTab {
+    @Override
+    public Pane getPane(Level level) {
+        return FXTab.super.getPane(level);
+    }
+
+    @Override
+    public String getTitle() {
+        return "3D Models";
+    }
+}

+ 48 - 15
ui/src/main/java/xyz/tbvns/ui/LevelSelectScreen.java

@@ -1,5 +1,6 @@
 package xyz.tbvns.ui;
 
+import javafx.application.Platform;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
@@ -11,6 +12,7 @@ import javafx.scene.text.Font;
 import lombok.extern.slf4j.Slf4j;
 import xyz.tbvns.core.DataManager;
 import xyz.tbvns.core.Objects.Level;
+import xyz.tbvns.core.UIProgressBar;
 import xyz.tbvns.ui.LevelEditor.MainWindow;
 
 import java.util.List;
@@ -21,9 +23,10 @@ public class LevelSelectScreen {
     public static Pane pane() {
         FlowPane pane = new FlowPane();
         pane.setAlignment(Pos.TOP_CENTER);
-        pane.setPrefWidth(5000);
+        pane.setPrefWidth(400);
         pane.setMinWidth(400);
         pane.setMinHeight(400);
+        pane.setMaxHeight(500);
 
         label.setPadding(new Insets(10));
         label.setFont(Font.font(50));
@@ -42,17 +45,31 @@ public class LevelSelectScreen {
 
         scrollPane.setContent(gridPane);
         scrollPane.fitToWidthProperty().set(true);
-        gridPane.setBackground(new Background(new BackgroundFill(new Color(1, 1, 1, 1), new CornerRadii(10), Insets.EMPTY)));
+        gridPane.setBackground(new Background(new BackgroundFill(new Color(1, 1, 1, 1), new CornerRadii(0), Insets.EMPTY)));
 
-        try {
-            List<Level> levelList = DataManager.getLevels();
-            for (int i = 0; i < levelList.size(); i++) {
-                Level level = levelList.get(i);
-                gridPane.add(getLevelPane(level, i), 1, i);
+
+        UIProgressBar progressBar = new UIProgressBar();
+        progressBar.openNow("Loading levels...");
+        new Thread(() -> {
+            try {
+                List<Level> levelList = DataManager.getLevels();
+                progressBar.updateBar(0.5);
+                for (int i = 0; i < levelList.size(); i++) {
+                    Level level = levelList.get(i);
+
+                    int finalI = i;
+                    Platform.runLater(() -> gridPane.add(getLevelPane(level, finalI), 1, finalI));
+                    double factor = 1f / levelList.size() * 0.5;
+
+                    progressBar.updateBar(progressBar.getProgressBar().getProgress() + factor);
+                }
+                progressBar.updateBar(1);
+                progressBar.close();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
             }
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        }).start();
+
 
         return scrollPane;
     }
@@ -69,17 +86,33 @@ public class LevelSelectScreen {
 
         pane.setOnMouseClicked(mouseEvent -> {
             if (selected == index) {
-                log.info("Launched level {}", level.getName());
-                MainWindow.open(Main.getStage());
+                loadLevel(level);
             }
             selected = index;
             for (Node node : pane.getParent().getChildrenUnmodifiable()) {
-                ((Pane) node).setBackground(new Background(new BackgroundFill(new Color(1, 1, 1, 1), new CornerRadii(10), Insets.EMPTY)));
+                ((Pane) node).setBackground(new Background(new BackgroundFill(new Color(1, 1, 1, 1), new CornerRadii(0), Insets.EMPTY)));
             }
-            pane.setBackground(new Background(new BackgroundFill(new Color(0.8, 0.8, 0.8, 0.5), new CornerRadii(10), Insets.EMPTY)));
-            System.out.println(level.getName());
+            pane.setBackground(new Background(new BackgroundFill(new Color(0.8, 0.8, 0.8, 0.5), new CornerRadii(0), Insets.EMPTY)));
         });
 
         return pane;
     }
+
+    public static void loadLevel(Level level) {
+        UIProgressBar progressBar = new UIProgressBar();
+        progressBar.openNow("Loading level '" + level.getName() + "'...");
+        progressBar.updateBar(0.5);
+        log.info("Launched level {}", level.getName());
+        new Thread(() -> {
+            Utils.safeSleep(50);
+            Platform.runLater(() -> {
+                MainWindow.open(Main.getStage(), level);
+                progressBar.updateBar(1);
+                Platform.runLater(() -> {
+                    Utils.safeSleep(500);
+                    progressBar.close();
+                });
+            });
+        }).start();
+    }
 }

+ 11 - 0
ui/src/main/java/xyz/tbvns/ui/Utils.java

@@ -0,0 +1,11 @@
+package xyz.tbvns.ui;
+
+public class Utils {
+    public static void safeSleep(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}