diff --git a/pom.xml b/pom.xml index db06adb..c574289 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.piitex RenJava - 0.0.757-SNAPSHOT + 0.0.802-SNAPSHOT RenJava @@ -102,12 +102,6 @@ 9.0.4 compile - - commons-io - commons-io - 2.15.1 - compile - diff --git a/src/main/java/me/piitex/renjava/Game.java b/src/main/java/me/piitex/renjava/Game.java new file mode 100644 index 0000000..89da13f --- /dev/null +++ b/src/main/java/me/piitex/renjava/Game.java @@ -0,0 +1,17 @@ +package me.piitex.renjava; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to set default information about the game. Use this annotation to tag the ReJava class constructor. + */ +@Target(ElementType.CONSTRUCTOR) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface Game { + String name() default ("Name"); + String author() default("Author"); + String version() default("1.0"); +} diff --git a/src/main/java/me/piitex/renjava/Launch.java b/src/main/java/me/piitex/renjava/Launch.java index e854703..a7a69b7 100644 --- a/src/main/java/me/piitex/renjava/Launch.java +++ b/src/main/java/me/piitex/renjava/Launch.java @@ -15,49 +15,50 @@ import org.reflections.util.ConfigurationBuilder; import java.util.HashSet; +import java.util.stream.Collectors; public class Launch extends Application { public static void main(String[] args) { // Scans for all classes in all packages. (We need to do all packages because this allows the author the freedom to do their own package scheme.) - Collection allPackagePrefixes = Arrays.stream(Package.getPackages()).map(Package::getName) - .map(s -> s.split("\\.")[0]).distinct().map(ClasspathHelper::forPackage).reduce((c1, c2) -> { - Collection c3 = new HashSet<>(); - c3.addAll(c1); - c3.addAll(c2); - return c3; - }).get(); + Collection allPackagePrefixes = Arrays.stream(Package.getPackages()) + .map(Package::getName) + .map(s -> s.split("\\.")[0]) + .distinct() + .map(ClasspathHelper::forPackage) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); ConfigurationBuilder config = new ConfigurationBuilder().addUrls(allPackagePrefixes) .addScanners(Scanners.SubTypes); Reflections reflections = new Reflections(config); // Detect any classes that extend RenJava - Class renJavaClass = null; for (Class c : reflections.getSubTypesOf(RenJava.class)) { - - // Checks for default RenJava class: This was removed but could be re-added at a later date. - if (c.getName().contains("Example")) { - renJavaClass = c; - } else { - try { - c.getDeclaredConstructor().newInstance(); - launch(args); - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | - InvocationTargetException e) { - e.printStackTrace(); + try { + Object o = c.getDeclaredConstructor().newInstance(); + RenJava renJava = (RenJava) o; + if (c.getDeclaredConstructor().isAnnotationPresent(Game.class)) { + Game game = c.getDeclaredConstructor().getAnnotation(Game.class); + renJava.name = game.name(); + renJava.author = game.author(); + renJava.version = game.version(); + } else { + System.err.println("Please annotate your main constructor with Game.\n\t\t@Game\n\t\tpublic void " + c.getDeclaredConstructor().getName() + "() { }"); + renJava.name = "Error"; + renJava.author = "Error"; + renJava.version = "Error"; } - return; - } - } - - try { - if (renJavaClass != null) { - renJavaClass.getDeclaredConstructor().newInstance(); + renJava.init(); // Initialize game launch(args); + //c.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { + e.printStackTrace(); } - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - e.printStackTrace(); + return; } + + System.err.println("Could not initialize RenJava. Please make a class which extends 'RenJava'."); } @Override diff --git a/src/main/java/me/piitex/renjava/RenJava.java b/src/main/java/me/piitex/renjava/RenJava.java index aa8ad1b..e10d5fd 100644 --- a/src/main/java/me/piitex/renjava/RenJava.java +++ b/src/main/java/me/piitex/renjava/RenJava.java @@ -8,9 +8,10 @@ import javafx.stage.StageStyle; import me.piitex.renjava.addons.Addon; import me.piitex.renjava.addons.AddonLoader; -import me.piitex.renjava.api.builders.ButtonBuilder; import me.piitex.renjava.api.builders.ImageLoader; +import me.piitex.renjava.api.exceptions.InvalidCharacterException; import me.piitex.renjava.api.music.Tracks; +import me.piitex.renjava.api.saves.Save; import me.piitex.renjava.api.saves.data.Data; import me.piitex.renjava.api.saves.data.PersistentData; import me.piitex.renjava.api.characters.Character; @@ -27,6 +28,8 @@ import me.piitex.renjava.gui.exceptions.ImageNotFoundException; import me.piitex.renjava.gui.Menu; +import me.piitex.renjava.gui.layouts.Layout; +import me.piitex.renjava.gui.layouts.impl.HorizontalLayout; import me.piitex.renjava.gui.layouts.impl.VerticalLayout; import me.piitex.renjava.gui.overlay.ButtonOverlay; import me.piitex.renjava.gui.StageType; @@ -63,14 +66,14 @@ * Note: Do not call the `RenJava` constructor directly. The framework creates a new instance of your class automatically using reflections. */ public abstract class RenJava { - private final String name; - private final String author; - private final String version; - private final Logger logger; - private final Player player; + protected String name; + protected String author; + protected String version; + private Logger logger; + private Player player; // Audio Tracking - private final Tracks tracks; - private final AddonLoader addonLoader; + private Tracks tracks; + private AddonLoader addonLoader; private Stage stage; // Move this somewhere else. private StageType stageType; @@ -94,16 +97,28 @@ public abstract class RenJava { * Entry point for the RenJava framework. This class is designed to be extended by your own class, which will serve as the entry point for your game. *

* Note: Do not call this constructor directly. The RenJava framework creates a new instance of your class automatically using reflection. + *

+ * Make sure to use {@link Game} to specify the information of the game. + *

{@code
+     * public class YourGame extends RenJava {
      *
-     * @param name    The name of the game, used for displaying the game in the window and other various places.
-     * @param author  The author of the game.
-     * @param version The current version of the game, used to display specific information about the game.
+     *     @Game(name = "Your Game", author = "You", version = "1.0")
+     *     public YourGame() {
+     *
+     *     }
+     * }
+     * }
+ * If you do not specify the game information it will assume default values. + * + * @see Game */ - public RenJava(String name, String author, String version) { + public RenJava() { + // Super is ran first than the superior method is ran. instance = this; - this.name = name; - this.author = author; - this.version = version; + } + + protected void init() { + // Run after super this.player = new Player(); this.tracks = new Tracks(); // Load logger @@ -228,6 +243,10 @@ public Collection getCharacters() { * @see RenJava#registerCharacter(Character) */ public Character getCharacter(String id) { + if (!registeredCharacters.containsKey(id)) { + getLogger().severe(new InvalidCharacterException(id).getMessage()); + return null; + } return registeredCharacters.get(id.toLowerCase()); } @@ -304,7 +323,7 @@ public void buildStage(Stage stage) { } else { stage.setMaximized(true); } - stage.setTitle(getName()); + stage.setTitle(getConfiguration().getGameTitle()); stage.setOnHiding(windowEvent -> { getAddonLoader().disable(); @@ -394,20 +413,19 @@ public void buildStage(Stage stage) { public abstract Menu buildTitleScreen(); public Menu buildSideMenu() { - // Don't build background image Menu menu = new Menu(350, 500, new ImageLoader("gui/overlay/main_menu.png")); Font uiFont = RenJava.getInstance().getConfiguration().getUiFont().getFont(); - ButtonOverlay startButton = new ButtonOverlay(new ButtonBuilder("menu-start-button", "Start", uiFont, Color.BLACK, 1, 1)); - ButtonOverlay loadButton = new ButtonOverlay(new ButtonBuilder("menu-load-button", "Load", uiFont, Color.BLACK, 1, 1)); - ButtonOverlay optionsButton = new ButtonOverlay(new ButtonBuilder("menu-preference-button", "Preferences", uiFont, Color.BLACK, 1, 1)); - ButtonOverlay aboutButton = new ButtonOverlay(new ButtonBuilder("menu-about-button", "About", uiFont, Color.BLACK, 1, 1)); + ButtonOverlay startButton = new ButtonOverlay("menu-start-button", "Start", uiFont, Color.BLACK, Color.TRANSPARENT, Color.TRANSPARENT, Color.BLUE, 1, 1); + ButtonOverlay loadButton = new ButtonOverlay("menu-load-button", "Load", uiFont, Color.BLACK, Color.TRANSPARENT, Color.TRANSPARENT, Color.BLUE, 1, 1); + ButtonOverlay optionsButton = new ButtonOverlay("menu-preference-button", "Preferences", uiFont, Color.BLACK, Color.TRANSPARENT, Color.TRANSPARENT, Color.BLUE, 1, 1); + ButtonOverlay aboutButton = new ButtonOverlay("menu-about-button", "About", uiFont, Color.BLACK, Color.TRANSPARENT, Color.TRANSPARENT, Color.BLUE, 1, 1); // Create vbox for the buttons. You can also do an HBox VerticalLayout layout = new VerticalLayout(200, 500); - layout.setXPosition(50); - layout.setYPosition(250); + layout.setX(50); + layout.setY(250); layout.setSpacing(20); layout.addOverlays(startButton, loadButton, optionsButton, aboutButton); @@ -417,8 +435,40 @@ public Menu buildSideMenu() { return menu; } - public Menu buildLoadMenu() { + public Menu buildLoadMenu(int page) { Menu menu = new Menu(1920, 1080, new ImageLoader("gui/main_menu.png")); + // Setup pagination. + // 6 save slots per page + // 2 Rows + // 3 Columns + // Make this customizable + + int maxSavesPerPage = 6; + + int index = 1; + VerticalLayout rootLayout = new VerticalLayout(1000, 400); // The root is a vertical which stacks the two horizontal layouts. + HorizontalLayout topLayout = new HorizontalLayout(1000, 200); + HorizontalLayout bottomLayout = new HorizontalLayout(1000, 200); + while (index <= maxSavesPerPage) { + // Create a button overlay of the scene that the save file would have been on., + // This will be a little challenging, it should be possible given the api of the Save object. + Save save = new Save(index); + if (save.getFile() != null) { + if (index <= 3) { + // Top layout + + } else { + // Bottom layout + } + } else { + // Process empty slot + } + index++; + } + + rootLayout.addChildLayout(topLayout); + rootLayout.addChildLayout(bottomLayout); + return menu; } @@ -489,7 +539,7 @@ public Menu buildAboutScreen() { * Example usage: *
{@code
      *     // Get the current story from the StoryManager
-     *     Story myStory = this.getStoryManager().getStory("my-story");
+     *     Story myStory = this.getPlayer().getStory("my-story");
      *     // Start the story
      *     myStory.start();
      * }
diff --git a/src/main/java/me/piitex/renjava/RenLoader.java b/src/main/java/me/piitex/renjava/RenLoader.java index e3f25b0..3ffb0a1 100644 --- a/src/main/java/me/piitex/renjava/RenLoader.java +++ b/src/main/java/me/piitex/renjava/RenLoader.java @@ -1,45 +1,50 @@ package me.piitex.renjava; import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; import java.util.Properties; -import java.util.stream.Stream; +import javafx.application.Platform; import me.piitex.renjava.api.builders.FontLoader; import me.piitex.renjava.api.music.Track; import me.piitex.renjava.configuration.SettingsProperties; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.RegexFileFilter; public class RenLoader { private final RenJava renJava; - + boolean shutdown = false; public RenLoader(RenJava renJava) { this.renJava = renJava; renJava.getLogger().info("Starting processes..."); renJava.buildVersion = getVersion(); setupMain(); setupGame(); + if (shutdown) { + // Shutdown application. + renJava.getLogger().severe("Game assets do not exist. Please download default assets and place them inside the 'game' folder."); + Platform.exit(); + System.exit(0); + return; + } startPreProcess(); } private void setupMain() { renJava.getLogger().info("Checking game environment..."); + + File gameDirectory = new File(System.getProperty("user.dir") + "/game/"); if (gameDirectory.mkdir()) { renJava.getLogger().severe("Game directory does not exist. The game will not work properly, please move all assets into the newly created game directory."); + shutdown = true; } File renJavaDirectory = new File(System.getProperty("user.dir") + "/renjava/"); - renJavaDirectory.mkdir(); + if (renJavaDirectory.mkdir()) { + renJava.getLogger().warning("RenJava folder does not exist. User settings will be reset to defaults."); + } File logFile = new File(System.getProperty("user.dir"), "log.txt"); try { logFile.createNewFile(); } catch (IOException e) { - e.printStackTrace(); + renJava.getLogger().warning("Could not create log file. Ensure the application has read and write permissions."); } for (File file : new File(System.getProperty("user.dir")).listFiles()) { if (file.getName().endsWith(".txt.lck")) { @@ -60,11 +65,17 @@ private void setupGame() { } renJava.getLogger().info("Loaded " + audioLoaded + " audio file(s)"); File imageDirectory = new File(directory, "/images/"); - imageDirectory.mkdir(); + if (imageDirectory.mkdir()) { + renJava.getLogger().warning("Images folder does not exist, creating..."); + } File savesDirectory = new File(directory, "/saves/"); - savesDirectory.mkdir(); + if (savesDirectory.mkdir()) { + renJava.getLogger().warning("Saves folder does not exist, creating..."); + } File fontsDirectory = new File(directory, "/fonts/"); - fontsDirectory.mkdir(); + if (fontsDirectory.mkdir()) { + renJava.getLogger().warning("Fonts folder does not exist, creating..."); + } renJava.getLogger().info("Loading fonts..."); int fonts = 0; diff --git a/src/main/java/me/piitex/renjava/addons/AddonLoader.java b/src/main/java/me/piitex/renjava/addons/AddonLoader.java index 0d39e3f..7822b56 100644 --- a/src/main/java/me/piitex/renjava/addons/AddonLoader.java +++ b/src/main/java/me/piitex/renjava/addons/AddonLoader.java @@ -170,7 +170,8 @@ private void initAddon(File file, @Nullable Collection dependencies) thro addon.getDependencies().addAll(dependencies); } addons.add(addon); - clazz.getMethod("onLoad").invoke(object, null); + //clazz.getMethod("onLoad").invoke(object, null); + addon.onLoad(); // Loads addon logger.info("Loaded: " + addon.getName()); } } diff --git a/src/main/java/me/piitex/renjava/api/builders/ButtonBuilder.java b/src/main/java/me/piitex/renjava/api/builders/ButtonBuilder.java deleted file mode 100644 index db1f2e2..0000000 --- a/src/main/java/me/piitex/renjava/api/builders/ButtonBuilder.java +++ /dev/null @@ -1,248 +0,0 @@ -package me.piitex.renjava.api.builders; - -import javafx.scene.control.Button; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; -import me.piitex.renjava.RenJava; -import me.piitex.renjava.events.types.ButtonClickEvent; -import me.piitex.renjava.gui.exceptions.ImageNotFoundException; - -public class ButtonBuilder { - private final String id; - private String text; - private Font font; - private Image image; - private Color color; - - private double x = 1, y = 1; - private final double xScale, yScale; - - public ButtonBuilder(String id, String text, Color color, double xScale, double yScale) { - this.id = id; - this.text = text; - this.color = color; - this.xScale = x; - this.yScale = y; - } - - public ButtonBuilder(String id, String text, Color color, Font font, double xScale, double yScale) { - this.id = id; - this.text = text; - this.color = color; - this.font = font; - this.xScale = x; - this.yScale = y; - } - - /** - * Create a button with only text. - * - * @param id Identifier for the button. - * @param text Text that will be displayed inside the button. - * @param color Color of the text. - * @param x X-Axis position of the button. - * @param y Y-Axis position of the button. - * @param xScale X-Axis scale of the button. - * @param yScale Y-Axis scale of the button. - */ - public ButtonBuilder(String id, String text, Color color, double x, double y, double xScale, double yScale) { - this.id = id; - this.text = text; - this.color = color; - this.x = x; - this.y = y; - this.xScale = xScale; - this.yScale = yScale; - } - - /** - * Create a button with only text with a specific font. - * - * @param id Identifier for the button. - * @param text Text that will be displayed inside the button. - * @param font Font to be used for the text. - * @param color Color of the text. - * @param x X-Axis position of the button. - * @param y Y-Axis position of the button. - * @param xScale X-Axis scale of the button. - * @param yScale Y-Axis scale of the button. - */ - public ButtonBuilder(String id, String text, Font font, Color color, double x, double y, double xScale, double yScale) { - this.id = id; - this.text = text; - this.font = font; - this.color = color; - this.x = x; - this.y = y; - this.xScale = xScale; - this.yScale = yScale; - } - - /** - * Create a button with only text with a specific font. - * - * @param id Identifier for the button. - * @param text Text that will be displayed inside the button. - * @param font Font to be used for the text. - * @param color Color of the text. - * @param xScale X-Axis scale of the button. - * @param yScale Y-Axis scale of the button. - */ - public ButtonBuilder(String id, String text, Font font, Color color, double xScale, double yScale) { - this.id = id; - this.text = text; - this.font = font; - this.color = color; - this.xScale = xScale; - this.yScale = yScale; - } - - /** - * Create a button with only an image. - * - * @param id Identifier for the button. - * @param imageLoader Image to be displayed inside the button. - * @param x X-Axis position of the button. - * @param y Y-Axis position of the button. - * @param xScale X-Axis scale of the button. - * @param yScale Y-Axis scale of the button. - */ - public ButtonBuilder(String id, ImageLoader imageLoader, double x, double y, double xScale, double yScale) { - this.id = id; - try { - this.image = imageLoader.build(); - } catch (ImageNotFoundException e) { - throw new RuntimeException(e); - } - this.x = x; - this.y = y; - this.xScale = xScale; - this.yScale = yScale; - } - - /** - * Create a button with image and text - * - * @param id Identifier for the button. - * @param imageLoader Image to be displayed inside the button. - * @param text Text to be displayed inside the button. - * @param x X-Axis position of the button. - * @param y Y-Axis position of the button. - * @param xScale X-Axis scale of the button. - * @param yScale Y-Axis scale of the button. - */ - public ButtonBuilder(String id, ImageLoader imageLoader, String text, double x, double y, double xScale, double yScale) { - this.id = id; - try { - this.image = imageLoader.build(); - } catch (ImageNotFoundException e) { - throw new RuntimeException(e); - } - this.text = text; - this.x = x; - this.y = y; - this.xScale = xScale; - this.yScale = yScale; - } - - public String getId() { - return id; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public Font getFont() { - return font; - } - - public void setFont(Font font) { - this.font = font; - } - - public Image getImage() { - return image; - } - - public void setImage(Image image) { - this.image = image; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public double getX() { - return x; - } - - public void setX(double x) { - this.x = x; - } - - public double getY() { - return y; - } - - public void setY(int y) { - this.y = y; - } - - public double getXScale() { - return xScale; - } - - public double getYScale() { - return yScale; - } - - public Button build() { - Button button = new Button(); - button.setId(id); - if (image != null) { - ImageView imageView = new ImageView(image); - button.setGraphic(imageView); - } - if (text != null && !text.isEmpty()) { - button.setText(text); - } - if (font != null) { - button.setFont(font); - } else { - // Set default font - button.setFont(RenJava.getInstance().getConfiguration().getUiFont().getFont()); - } - if (color != null) { - button.setTextFill(color); - } - if (x != 0 && y != 0) { - button.setTranslateX(x); - button.setTranslateY(y); - } - button.setScaleX(xScale); - button.setScaleY(yScale); - - button.setOnAction(actionEvent -> { - ButtonClickEvent event = new ButtonClickEvent(RenJava.getInstance().getPlayer().getCurrentScene(), button); - RenJava.callEvent(event); - }); - return button; - } - - public static ButtonBuilder copyOf(String id, ButtonBuilder builder) { - ButtonBuilder toReturn = new ButtonBuilder(id, builder.getText(), builder.getFont(), builder.getColor(), builder.getX(), builder.getY(), builder.getXScale(), builder.getYScale()); - toReturn.setImage(builder.getImage()); - return toReturn; - } -} \ No newline at end of file diff --git a/src/main/java/me/piitex/renjava/api/builders/FontLoader.java b/src/main/java/me/piitex/renjava/api/builders/FontLoader.java index 284a2c1..99bbe7e 100644 --- a/src/main/java/me/piitex/renjava/api/builders/FontLoader.java +++ b/src/main/java/me/piitex/renjava/api/builders/FontLoader.java @@ -19,6 +19,12 @@ public class FontLoader { private static final Map cachedFonts = new HashMap<>(); + public FontLoader(FontLoader font, double size) { + this.name = font.getName(); + this.size = size; + this.font = Font.font(font.getFont().getFamily(), size); + } + public FontLoader(Font font, double size) { this.name = font.getName(); this.size = size; @@ -39,7 +45,7 @@ public FontLoader(Font font, FontPosture posture, double size) { this.font = Font.font(font.getFamily(), posture, size); } - public FontLoader(String name, int size) { + public FontLoader(String name, double size) { this.name = name; File directory = new File(System.getProperty("user.dir") + "/game/fonts/"); File file = new File(directory, name); diff --git a/src/main/java/me/piitex/renjava/api/builders/InputFieldBuilder.java b/src/main/java/me/piitex/renjava/api/builders/InputFieldBuilder.java deleted file mode 100644 index d0c8831..0000000 --- a/src/main/java/me/piitex/renjava/api/builders/InputFieldBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.piitex.renjava.api.builders; - -import javafx.scene.control.TextField; - - -public class InputFieldBuilder { - private final double x; - private final double y; - private final FontLoader fontLoader; - - public InputFieldBuilder(double x, double y, FontLoader fontLoader) { - this.x = x; - this.y = y; - this.fontLoader = fontLoader; - } - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public FontLoader getFontLoader() { - return fontLoader; - } - - public TextField build() { - TextField textField = new TextField(); - textField.setTranslateX(x); - textField.setTranslateY(y); - textField.setStyle(""); - textField.setStyle("-fx-control-inner-background: transparent; -fx-background-color transparent;"); - return textField; - } -} diff --git a/src/main/java/me/piitex/renjava/api/builders/TextFlowBuilder.java b/src/main/java/me/piitex/renjava/api/builders/TextFlowBuilder.java deleted file mode 100644 index 3a9a97a..0000000 --- a/src/main/java/me/piitex/renjava/api/builders/TextFlowBuilder.java +++ /dev/null @@ -1,53 +0,0 @@ -package me.piitex.renjava.api.builders; - -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; - -import java.util.LinkedList; - -public class TextFlowBuilder { - private LinkedList texts = new LinkedList<>(); - - private final int width, height; - - public TextFlowBuilder(String text, int width, int height) { - this.width = width; - this.height = height; - texts.add(new Text(text)); - } - - public TextFlowBuilder(Text text, int width, int height) { - this.width = width; - this.height = height; - texts.add(text); - } - - public TextFlowBuilder(LinkedList texts, int width, int height) { - this.width = width; - this.height = height; - this.texts = texts; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public LinkedList getTexts() { - return texts; - } - - public TextFlow build() { - TextFlow textFlow = new TextFlow(); - for (Text text : texts) { - textFlow.getChildren().add(text); - } - - textFlow.setPrefSize(width, height); - - return textFlow; - } -} diff --git a/src/main/java/me/piitex/renjava/api/exceptions/InvalidCharacterException.java b/src/main/java/me/piitex/renjava/api/exceptions/InvalidCharacterException.java new file mode 100644 index 0000000..cfd4729 --- /dev/null +++ b/src/main/java/me/piitex/renjava/api/exceptions/InvalidCharacterException.java @@ -0,0 +1,8 @@ +package me.piitex.renjava.api.exceptions; + +public class InvalidCharacterException extends Exception { + + public InvalidCharacterException(String characterID) { + super("Character '" + characterID + "' does not exist. Make sure the character is registered and created within the framework."); + } +} diff --git a/src/main/java/me/piitex/renjava/api/exceptions/InvalidStoryException.java b/src/main/java/me/piitex/renjava/api/exceptions/InvalidStoryException.java new file mode 100644 index 0000000..d2591b3 --- /dev/null +++ b/src/main/java/me/piitex/renjava/api/exceptions/InvalidStoryException.java @@ -0,0 +1,8 @@ +package me.piitex.renjava.api.exceptions; + +public class InvalidStoryException extends Exception { + + public InvalidStoryException(String id) { + super("Story '" + id + "' does not exist and thus could not be started. Ensure that the story class is registered within the framework. `new MyStoryClass()`"); + } +} diff --git a/src/main/java/me/piitex/renjava/api/music/Track.java b/src/main/java/me/piitex/renjava/api/music/Track.java index 599c20e..167bbe3 100644 --- a/src/main/java/me/piitex/renjava/api/music/Track.java +++ b/src/main/java/me/piitex/renjava/api/music/Track.java @@ -47,7 +47,7 @@ public boolean isLoop() { return loop; } - public void stop() { + protected void stop() { if (player != null) { player.stop(); } diff --git a/src/main/java/me/piitex/renjava/api/music/Tracks.java b/src/main/java/me/piitex/renjava/api/music/Tracks.java index 84b3215..d910d73 100644 --- a/src/main/java/me/piitex/renjava/api/music/Tracks.java +++ b/src/main/java/me/piitex/renjava/api/music/Tracks.java @@ -49,7 +49,7 @@ public void play(String fileName, boolean loop) { } public void play(Track track, boolean loop) { - if (currentTrack != null) { + if (getCurrentTrack() != null) { getCurrentTrack().stop(); } setPlaying(true); diff --git a/src/main/java/me/piitex/renjava/api/player/Player.java b/src/main/java/me/piitex/renjava/api/player/Player.java index 488f262..0f491cd 100644 --- a/src/main/java/me/piitex/renjava/api/player/Player.java +++ b/src/main/java/me/piitex/renjava/api/player/Player.java @@ -1,16 +1,15 @@ package me.piitex.renjava.api.player; +import me.piitex.renjava.RenJava; import me.piitex.renjava.api.APINote; import me.piitex.renjava.api.builders.ImageLoader; +import me.piitex.renjava.api.exceptions.InvalidStoryException; import me.piitex.renjava.api.saves.data.Data; import me.piitex.renjava.api.saves.data.PersistentData; import me.piitex.renjava.api.scenes.RenScene; import me.piitex.renjava.api.stories.Story; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; /** * Class that stores player data such as game progress and what scenes they have viewed. Some of the information stored is only useful to the framework but feel free to explore. @@ -19,22 +18,26 @@ public class Player implements PersistentData { private boolean rightClickMenu; @Data private String currentScene; @Data private String currentStory; - private ImageLoader lastDisplayedImage; + + // Entry to map the story for the image + private Map.Entry lastDisplayedImage; private boolean transitionPlaying = false; private boolean uiToggled = true; private boolean skipAutoScene = false; - private final LinkedHashMap viewedStories = new LinkedHashMap<>(); // Ordered map of what stories the player has viewed. + //StoryID + @Data private LinkedHashSet viewedStories = new LinkedHashSet<>(); // Ordered map of what stories the player has viewed. private final Map viewedStoriesIndex = new HashMap<>(); // Indexing of the viewedStories - private final Map, RenScene> viewedScenes = new HashMap<>(); + // StoryID, SceneID + @Data private Map viewedScenes = new HashMap<>(); private final Map storyIdMap = new HashMap<>(); public boolean hasSeenScene(Story story, String sceneID) { - return viewedScenes.containsValue(story.getScene(sceneID)); + return viewedScenes.containsKey(story.getId()) && viewedScenes.containsValue(sceneID); } public RenScene getCurrentScene() { @@ -44,6 +47,14 @@ public RenScene getCurrentScene() { return null; // No story set has the game started? } + public String getCurrentSceneID() { + return currentScene; + } + + public String getCurrentStoryID() { + return currentStory; + } + public void setCurrentScene(String currentSceneID) { this.currentScene = currentSceneID; } @@ -55,7 +66,7 @@ public Story getCurrentStory() { public void setCurrentStory(String currentStoryID) { this.currentStory = currentStoryID; Story story = getStory(currentStoryID); - viewedStories.put(currentStoryID, story); // When setting story update the viewedStory for rollback. + viewedStories.add(currentStoryID); // When setting story update the viewedStory for rollback. int index = viewedStoriesIndex.size(); viewedStoriesIndex.put(index, story); } @@ -77,14 +88,28 @@ public Story getPreviousStory() { return viewedStoriesIndex.get(viewedStoriesIndex.size()); // Get last story } - public LinkedHashMap getViewedStories() { + public LinkedHashSet getViewedStories() { return viewedStories; } - public Map, RenScene> getViewedScenes() { + public Map getViewedScenes() { return viewedScenes; } + public Map getStoryIdMap() { + return storyIdMap; + } + + public void startStory(String id) { + if (!storyIdMap.containsKey(id)) { + RenJava.getInstance().getLogger().severe(new InvalidStoryException(id).getMessage()); + return; + } + RenJava.getInstance().getLogger().info("Starting story '" + id + "'"); + RenJava.getInstance().getPlayer().setCurrentStory(id); + getStory(id).start(); + } + public boolean isRightClickMenu() { return rightClickMenu; } @@ -93,11 +118,11 @@ public void setRightClickMenu(boolean rightClickMenu) { this.rightClickMenu = rightClickMenu; } - public ImageLoader getLastDisplayedImage() { + public Map.Entry getLastDisplayedImage() { return lastDisplayedImage; } - public void setLastDisplayedImage(ImageLoader lastDisplayedImage) { + public void setLastDisplayedImage(Map.Entry lastDisplayedImage) { this.lastDisplayedImage = lastDisplayedImage; } @@ -127,7 +152,7 @@ public void setTransitionPlaying(boolean transitionPlaying) { public void updateScene(RenScene renScene) { setCurrentScene(renScene.getId()); // Update the scene. - getViewedScenes().put(new AbstractMap.SimpleEntry<>(renScene.getStory(), renScene.getId()), renScene); + getViewedScenes().put(renScene.getStory().getId(), renScene.getId()); setCurrentStory(renScene.getStory()); } } diff --git a/src/main/java/me/piitex/renjava/api/saves/Load.java b/src/main/java/me/piitex/renjava/api/saves/Load.java deleted file mode 100644 index b24e825..0000000 --- a/src/main/java/me/piitex/renjava/api/saves/Load.java +++ /dev/null @@ -1,177 +0,0 @@ -package me.piitex.renjava.api.saves; - -import me.piitex.renjava.RenJava; -import me.piitex.renjava.api.saves.data.PersistentData; -import me.piitex.renjava.api.saves.exceptions.SaveFileNotFound; -import me.piitex.renjava.api.saves.file.SectionKeyValue; -import me.piitex.renjava.api.stories.Story; - -import java.io.File; -import java.io.FileNotFoundException; -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.HashSet; -import java.util.Scanner; -import java.util.logging.Logger; - -/** - * Loads a save file. - */ -public class Load { - - public Load(int slot) throws SaveFileNotFound { - File directory = new File(System.getProperty("user.dir") + "/game/saves/" + slot + "/"); - File file = new File(directory,"/save-" + slot + ".dat"); - if (!file.exists()) { - throw new SaveFileNotFound(); - } - - // Mapping - Collection keyValues = new HashSet<>(); - - // Story and Scene - String story = ""; - String scene = ""; - - // Music stuff - String currentTrack = ""; - boolean isPlaying = false; - boolean isLooping = false; - - Logger logger = RenJava.getInstance().getLogger(); - try { - Scanner scanner = new Scanner(file); - SectionKeyValue sectionKeyValue = null; - - // Flags - boolean config = false; - boolean musicTracker = false; - - while (scanner.hasNextLine()) { - // classname@field1;value@field2;value@ect..@ect..;clasname2@field;value@field;value@field;value - String data = scanner.nextLine(); - - if (data.startsWith("configuration")) { - config = true; - } else if (data.contains("me.piitex.renjava.api.music.Tracks")) { - musicTracker = true; - } else { - if (!data.startsWith(" ")) { - data = data.trim(); - if (sectionKeyValue != null) { - keyValues.add(sectionKeyValue); - } - sectionKeyValue = new SectionKeyValue(data.replace(":", "").trim()); - } else if (sectionKeyValue != null) { - String key = data.split(": ")[0].trim(); - String value = data.split(": ")[1].trim(); - sectionKeyValue.addKeyValue(key, value); - } - } - - if (data.startsWith(" ")) { - if (config) { - data = data.trim(); - String[] pairs = data.split(": "); - String key = pairs[0]; - String value = pairs[1]; - if (key.equalsIgnoreCase("storyID")) { - story = value; - } - if (key.equalsIgnoreCase("sceneID")) { - logger.info("Key: " + key); - logger.info("Value: " + value); - scene = value; - // End config - } - if (!story.isEmpty() && !scene.isEmpty()) { - logger.info("Story: " + story); - logger.info("Scene: " + scene); - config = false; - } - } - if (musicTracker) { - data = data.trim(); - String[] pairs = data.split(": "); - String key = pairs[0]; - String value = pairs[1]; - - if (key.equalsIgnoreCase("currentTrack")) { - currentTrack = value; - } - - if (key.equalsIgnoreCase("isPlaying")) { - isPlaying = Boolean.parseBoolean(value); - } - - if (key.equalsIgnoreCase("loop")) { - isLooping = Boolean.parseBoolean(value); - } - } - } - } - // Once the loop is done add the final section - keyValues.add(sectionKeyValue); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - - for (PersistentData data : RenJava.getInstance().getRegisteredData()) { - // Loop through data and check if it matches any of the section key data - logger.info("Class: " + data.getClass().getName()); - for (SectionKeyValue sectionKeyValue : keyValues) { - if (sectionKeyValue.getSection().equalsIgnoreCase(data.getClass().getName())) { - sectionKeyValue.getKeyValueMap().forEach((string, string2) -> { - logger.info("Setting fields..."); - - try { - Field field = data.getClass().getField(string); - setField(field, data, string2); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchFieldException e) { - // If its no such field see if its a declared field - try { - Field field = data.getClass().getDeclaredField(string); - setField(field, data, string2); - } catch (IllegalAccessException | NoSuchFieldException ignored) { - // This is ignored because it will throw NoSuchFieldException as it loops through ALL saved data in the file. - } - } - }); - } - - keyValues.remove(sectionKeyValue); // this might error - } - } - Story loadedStory = RenJava.getInstance().getPlayer().getStory(story); - loadedStory.init(); // Add scenes and stuff - loadedStory.displayScene(scene); - if (isPlaying) { - RenJava.getInstance().getTracks().play(currentTrack, isLooping); - } - } - - private void setField(Field field, PersistentData data, String string2) throws NoSuchFieldException, IllegalAccessException { - field.setAccessible(true); - Type type = field.getGenericType(); - if (type.getTypeName().toLowerCase().contains("string")) { - field.set(data, string2); - } else if (type.getTypeName().toLowerCase().contains("int")) { - field.set(data, Integer.parseInt(string2)); - } else if (type.getTypeName().toLowerCase().contains("boolean")) { - field.set(data, Boolean.parseBoolean(string2)); - } else if (type.getTypeName().toLowerCase().contains("double")) { - field.set(data, Double.parseDouble(string2)); - } else if (type.getTypeName().toLowerCase().contains("float")) { - field.set(data, Float.parseFloat(string2)); - } else if (type.getTypeName().toLowerCase().contains("long")) { - field.set(data, Long.parseLong(string2)); - } else if (type.getTypeName().toLowerCase().contains("short")) { - field.set(data, Short.parseShort(string2)); - } else if (type.getTypeName().toLowerCase().contains("byte")) { - field.set(data, Byte.parseByte(string2)); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/piitex/renjava/api/saves/Save.java b/src/main/java/me/piitex/renjava/api/saves/Save.java index ef2908b..a793b30 100644 --- a/src/main/java/me/piitex/renjava/api/saves/Save.java +++ b/src/main/java/me/piitex/renjava/api/saves/Save.java @@ -1,82 +1,103 @@ package me.piitex.renjava.api.saves; + +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; import me.piitex.renjava.RenJava; +import me.piitex.renjava.api.builders.ImageLoader; import me.piitex.renjava.api.saves.data.Data; import me.piitex.renjava.api.saves.data.PersistentData; +import me.piitex.renjava.api.saves.file.SectionKeyValue; import me.piitex.renjava.api.scenes.RenScene; import me.piitex.renjava.api.stories.Story; +import me.piitex.renjava.gui.Menu; +import me.piitex.renjava.gui.exceptions.ImageNotFoundException; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.*; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * Represents a save slot. All data is stored via a .dat file. - */ +// Class which represents a save file. public class Save { - private final Story story; - private final RenScene scene; - - /** - * Creates a current save for the desired slot. - * @param slot Slot to be saved, there is no limit on slots. - */ - public Save(int slot, String storyID, String sceneID) { - this.story = RenJava.getInstance().getPlayer().getStory(storyID); - this.scene = story.getScene(sceneID); - // Slot is needed for the save slot. - File directory = new File(System.getProperty("user.dir") + "/game/saves/" + slot + "/"); - directory.mkdir(); - File file = new File(directory,"/save-" + slot + ".dat"); - if (!file.exists()) { - try { - file.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } + private final File file; + private int slot; + + // Some ghetto code + // Map the scene when the load function is called. Easier way to get preview. + private SectionKeyValue sceneSection; + + public Save(File file) { + this.file = file; + } + + public Save(int slot) { + this.slot = slot; + this.file = new File(System.getProperty("user.dir") + "/game/saves/save-" + slot + ".dat"); + } + + // Writes save file + public void write() { + // First get all PersistentData to write. + // me.piitex.MyDataClass: + // field1: data1 + // map: + // key1: value1 + // key2: value2 + StringBuilder appendString = new StringBuilder(); - Logger logger = RenJava.getInstance().getLogger(); - appendString.append("configuration").append("@@@@").append("storyID").append("!!!!").append(storyID).append("@@@@").append("sceneID").append("!!!!").append(sceneID).append(";;;;"); for (PersistentData data : RenJava.getInstance().getRegisteredData()) { + SectionKeyValue rootSection = new SectionKeyValue(data.getClass().getName()); Class claz = data.getClass(); - appendString.append(claz.getName()); + if (appendString.toString().contains(claz.getName())) { + continue; + } List fields = new ArrayList<>(List.of(claz.getDeclaredFields())); fields.addAll(List.of(claz.getFields())); for (Field field : fields) { + field.setAccessible(true); if (field.isAnnotationPresent(Data.class)) { - appendString.append("@@@@"); - appendString.append(field.getName()); - appendString.append("!!!!"); - field.setAccessible(true); + SectionKeyValue mapSection = handleMap(data, field); + if (mapSection != null) { + System.out.println("Map Section: "); + + System.out.println(mapSection.toString()); + rootSection.addSubSection(mapSection); + + continue; + } + // Handle fields try { + System.out.println("Processing field: " + field.getName()); Object object = field.get(data); - appendString.append(object.toString()); + if (object == null) { + RenJava.getInstance().getLogger().warning("Value for '" + field.getName() + "' is null. Will not process data."); + continue; + } + rootSection.addKeyValue(field.getName(), object.toString()); } catch (IllegalAccessException e) { - e.printStackTrace(); + throw new RuntimeException(e); + } catch (IllegalArgumentException ignored) { + rootSection.addKeyValue(field.getName(), "null"); } } } - appendString.append(";;;;"); + appendString.append(rootSection); } - // The appendString won't be suitable for the save file. We can still use it to format our data but its best if we do a file format. YAML is a good example - String toWriteToFile = SaveFileUtils.toFormat(appendString.toString()); - logger.info("File: " + toWriteToFile); - FileWriter writer = null; + + FileWriter fileWriter = null; try { - writer = new FileWriter(file); - writer.write(toWriteToFile); + fileWriter = new FileWriter(file); + fileWriter.write(appendString.toString()); } catch (IOException e) { e.printStackTrace(); } finally { - if (writer != null) { + if (fileWriter != null) { try { - writer.close(); + fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } @@ -84,11 +105,256 @@ public Save(int slot, String storyID, String sceneID) { } } - public Story getStory() { - return story; + private SectionKeyValue handleMap(PersistentData data, Field field) { + if (field.getGenericType().getTypeName().contains("Map<")) { + try { + System.out.println("Map type: " + field.getGenericType().getTypeName()); + SectionKeyValue sectionKeyValue = new SectionKeyValue(field.getName()); + reconstructMap(sectionKeyValue, data, field); + return sectionKeyValue; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return null; + } + + private void reconstructMap(SectionKeyValue sectionKeyValue, PersistentData data, Field field) throws IllegalAccessException { + Map map = (Map) field.get(data); + map.entrySet().forEach(objectObjectEntry -> { + System.out.println("Reconstructing entry..."); + sectionKeyValue.addKeyValue(objectObjectEntry.getKey().toString(), objectObjectEntry.getValue().toString()); + }); + } + + + // Loads save file + public void load(boolean process) { + // Collect and set string data to class data. + // First loop the registered data and find the string data which corresponds with the data. + + String fullData = null; + try { + fullData = new Scanner(file).useDelimiter("\\Z").next(); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } finally { + if (fullData == null) { + RenJava.getInstance().getLogger().severe("Save file does not exist."); + return; + } + } + + for (PersistentData persistentData : RenJava.getInstance().getRegisteredData()) { + String clazzName = persistentData.getClass().getName(); + SectionKeyValue rootSection = new SectionKeyValue(clazzName); + SectionKeyValue mapSection = null; + + String[] classSplit = fullData.split(clazzName + ":"); + String fields = classSplit[1]; + System.out.println("Class Split: " + classSplit[1]); + String[] fieldSplit = fields.split("\n"); + for (String field : fieldSplit) { + System.out.println("Field: " + field); + if (field.trim().isEmpty()) continue; + String[] keyValueSplit = field.split(":"); + String key = keyValueSplit[0]; + if (keyValueSplit.length == 1) { + if (key.startsWith(" ") || key.startsWith("\t")) { + System.out.println("Mapping found: " + key.trim()); + mapSection = new SectionKeyValue(key.trim()); + rootSection.addSubSection(mapSection); + continue; + } else { + break; + } + } + String value = keyValueSplit[1]; + if ((key.startsWith(" ") || key.startsWith("\t")) && value.trim().isEmpty()) { + System.out.println("Mapping found: " + key.trim()); + mapSection = new SectionKeyValue(key.trim()); + rootSection.addSubSection(mapSection); + } else if (value.trim().isEmpty()) { + break; + } else if (key.startsWith("\t\t") || key.startsWith(" ")) { + if (mapSection != null) { + mapSection.addKeyValue(key.trim(), value.trim()); + } + System.out.println("Mapping entry found: " + key.trim() + "," + value.trim()); + } else if (key.startsWith("\t") || key.startsWith(" ")){ + // Handle generic entry + + // Check if entry is an array + if (value.contains(",")) { + if (value.contains("[")) { + value = value.replace("[", "").replace("]", ""); + } + String[] arraySplit = value.trim().split(","); + rootSection.addArray(key.trim(), arraySplit); + continue; + } + rootSection.addKeyValue(key.trim(), value.trim()); + } + } + if (process) { + processSection(persistentData, rootSection); + } else { + if (rootSection.getSection().contains("me.piitex.renjava.api.player.Player")) { + System.out.println("Mapping scene..."); + sceneSection = rootSection; + } + } + } + } + + + public void processSection(PersistentData persistentData, SectionKeyValue rootSection) { + // Data is the full data string + // me.piitex.SomeData: + // field1: value1 + // map: + // key: value + // + + System.out.println("================================================"); + System.out.println(); + System.out.println(rootSection.toString()); + System.out.println(); + System.out.println("================================================"); + + // Next set the mapping to the fields + List fields = new ArrayList<>(List.of(persistentData.getClass().getDeclaredFields())); + fields.addAll(List.of(persistentData.getClass().getFields())); + for (Field field : fields) { + if (field.isAnnotationPresent(Data.class)) { + System.out.println("Processing Field: " + field.getName()); + field.setAccessible(true); + if (field.getGenericType().getTypeName().contains("Map<")) { + // This is a map load. Scan for subsections if the field name matches. Add all data + for (SectionKeyValue subSection : rootSection.getSubSections()) { + if (subSection.getSection().equalsIgnoreCase(field.getName())) { + // Convert Map to whatever the map of the object is + + // Set the current values to whatever the load file is + deconstructMap(subSection, persistentData, field); + + try { + System.out.println("Map: " + field.get(persistentData).toString()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + } + } + } + + String keyToSet = (String) rootSection.getKeyValueMap().keySet().stream().filter(key -> key.toString().equalsIgnoreCase(field.getName())).findAny().orElse(null); + if (keyToSet != null) { + System.out.println("Key To Set: " + keyToSet); + try { + + // Casting string might not be a good idea. + String value = (String) rootSection.getKeyValueMap().get(keyToSet); + + System.out.println("Setting values for: " + field.getName()); + setField(field, persistentData, value.strip()); + + // Testing checks + if (field.getName().equalsIgnoreCase("currentStory")) { + System.out.println("Current Story: " + field.get(persistentData)); + } + if (field.getName().equalsIgnoreCase("currentScene")) { + System.out.println("Current Scene: " + field.get(persistentData)); + } + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + System.err.println("Could not set field: " + field.getName()); + } + } + } + } + + private void deconstructMap(SectionKeyValue subSection, PersistentData data, Field field) { + Map objectMap; + try { + objectMap = (Map) field.get(data); + } catch (IllegalAccessException e) { + objectMap = new HashMap<>(); + } + + if (objectMap == null) { + System.out.println("Map was null. Defaulting..."); + objectMap = new HashMap<>(); + } + + + // TODO: 3/3/2024 Convert generic map type to actual type using the Mapper class + Map finalObjectMap = objectMap; + subSection.getKeyValueMap().forEach((key, value) -> { + System.out.println("Setting map..."); + System.out.println(key + ": " + value); + finalObjectMap.put(key, value); + }); + } + + private void setField(Field field, PersistentData data, String string2) throws NoSuchFieldException, IllegalAccessException { + field.setAccessible(true); + Type type = field.getGenericType(); + if (type.getTypeName().toLowerCase().contains("string")) { + field.set(data, string2); + } else if (type.getTypeName().toLowerCase().contains("int")) { + field.set(data, Integer.parseInt(string2)); + } else if (type.getTypeName().toLowerCase().contains("boolean")) { + field.set(data, Boolean.parseBoolean(string2)); + } else if (type.getTypeName().toLowerCase().contains("double")) { + field.set(data, Double.parseDouble(string2)); + } else if (type.getTypeName().toLowerCase().contains("float")) { + field.set(data, Float.parseFloat(string2)); + } else if (type.getTypeName().toLowerCase().contains("long")) { + field.set(data, Long.parseLong(string2)); + } else if (type.getTypeName().toLowerCase().contains("short")) { + field.set(data, Short.parseShort(string2)); + } else if (type.getTypeName().toLowerCase().contains("byte")) { + field.set(data, Byte.parseByte(string2)); + } + } + + // Builds the preview for saving and loading + public Pane buildPreview() { + Pane pane = new Pane(); + // Get the current scene the save is on. + // Build the scene. + // Scale it to a small box. + if (sceneSection == null) { + // Default image + ImageLoader saveImage = new ImageLoader("gui/button/slot_idle_background.png"); + try { + pane.getChildren().add(new ImageView(saveImage.build())); + } catch (ImageNotFoundException e) { + RenJava.getInstance().getLogger().severe(e.getMessage()); + } + } else { + Story story = RenJava.getInstance().getPlayer().getStory((String) sceneSection.get("currentStory")); + RenScene currentScene = story.getScene((String) sceneSection.get("currentScene")); + Menu menu = currentScene.build(true); + pane = menu.getPane(); + } + + // Scale the pane to fit a small box. + + // 414 x 309 + // 1920 1080 + // 0.2, 0.28 + pane.setMaxWidth(414); + pane.setMaxHeight(309); + + + return pane; } - public RenScene getScene() { - return scene; + public File getFile() { + return file; } -} \ No newline at end of file +} diff --git a/src/main/java/me/piitex/renjava/api/saves/SaveFileUtils.java b/src/main/java/me/piitex/renjava/api/saves/SaveFileUtils.java deleted file mode 100644 index 640bbdd..0000000 --- a/src/main/java/me/piitex/renjava/api/saves/SaveFileUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.piitex.renjava.api.saves; - -public class SaveFileUtils { - - public static String toFormat(String data) { - StringBuilder builder = new StringBuilder(); - String[] clasz = data.split(";;;;"); - for (String s : clasz) { - String classname = "Unknown"; - String[] fields = s.split("@@@@"); - boolean clazDetect = false; - for (String s1 : fields) { - if (!clazDetect) { - classname = s1; - builder.append(classname).append(":").append("\n"); - clazDetect = true; - } else { - String field = s1.split("!!!!")[0]; - String value = s1.split("!!!!")[1]; - builder.append(" ").append(field).append(": ").append(value); - builder.append("\n"); - System.out.println("Class: " + classname); - System.out.println("Field: " + field); - System.out.println("Value: " + value); - } - } - } - return builder.toString(); - } -} diff --git a/src/main/java/me/piitex/renjava/api/saves/data/Mapper.java b/src/main/java/me/piitex/renjava/api/saves/data/Mapper.java new file mode 100644 index 0000000..9916f7f --- /dev/null +++ b/src/main/java/me/piitex/renjava/api/saves/data/Mapper.java @@ -0,0 +1,200 @@ +package me.piitex.renjava.api.saves.data; + +import java.util.HashMap; +import java.util.Map; + +public class Mapper { + + public static Map toStringMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), objectObjectEntry.getValue().toString()); + }); + return toReturn; + } + + public static Map toStringIntegerMap(Map map) { + System.out.println("Reconstructing map..."); + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Integer) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringBooleanMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Boolean) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringDoubleMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Double) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringLongMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Long) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringFloatMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Float) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringShortMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Short) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toStringByteMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put(objectObjectEntry.getKey().toString(), (Byte) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntergerStringMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), objectObjectEntry.getValue().toString()); + }); + return toReturn; + } + + public static Map toInterMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Integer) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntergerBooleanMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Boolean) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntegerDoubleMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Double) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntegerLong(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Long) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntegerFloatMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Float) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntegerShortMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Short) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toIntegerByteMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Integer) objectObjectEntry.getKey(), (Byte) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleStringMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), objectObjectEntry.getValue().toString()); + }); + return toReturn; + } + + public static Map toDoubleIntergerMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Integer) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleBooleanMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Boolean) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Double) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleLongMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Long) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleFloatMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Float) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleShortMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Short) objectObjectEntry.getValue()); + }); + return toReturn; + } + + public static Map toDoubleByteMap(Map map) { + Map toReturn = new HashMap<>(); + map.entrySet().forEach(objectObjectEntry -> { + toReturn.put((Double) objectObjectEntry.getKey(), (Byte) objectObjectEntry.getValue()); + }); + return toReturn; + } +} diff --git a/src/main/java/me/piitex/renjava/api/saves/file/SectionKeyValue.java b/src/main/java/me/piitex/renjava/api/saves/file/SectionKeyValue.java index 5cc89d5..3bb2f29 100644 --- a/src/main/java/me/piitex/renjava/api/saves/file/SectionKeyValue.java +++ b/src/main/java/me/piitex/renjava/api/saves/file/SectionKeyValue.java @@ -1,11 +1,13 @@ package me.piitex.renjava.api.saves.file; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class SectionKeyValue { private final String section; - private final Map keyValueMap = new HashMap<>(); + private final Map keyValueMap = new HashMap<>(); + private final Collection subSection = new HashSet<>(); + + private final Map> arrayMap = new HashMap<>(); public SectionKeyValue(String section) { this.section = section; @@ -15,11 +17,63 @@ public String getSection() { return section; } - public void addKeyValue(String key, String value) { + public void addKeyValue(String key, Object value) { keyValueMap.put(key, value); } - public Map getKeyValueMap() { + public void addSubSection(SectionKeyValue sectionKeyValue) { + subSection.add(sectionKeyValue); + } + + public void addArray(String field, Object... values) { + ArrayList array = new ArrayList<>(List.of(values)); + arrayMap.put(field, array); + } + + public ArrayList getArray(String key) { + return arrayMap.get(key); + } + + public Collection getSubSections() { + return subSection; + } + + public Map> getArrayMap() { + return arrayMap; + } + + public Map getKeyValueMap() { return keyValueMap; } -} + + public Object get(String key) { + return keyValueMap.get(key); + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(section).append(":"); + keyValueMap.entrySet().forEach(stringStringEntry -> { + stringBuilder.append("\n").append("\t"); + stringBuilder.append(stringStringEntry.getKey()).append(": ").append(stringStringEntry.getValue()); + }); + arrayMap.entrySet().forEach(stringArrayListEntry -> { + stringBuilder.append("\n\t"); + stringBuilder.append(stringArrayListEntry.getKey()).append(": "); + for (int i = 0; i < stringArrayListEntry.getValue().size(); i++) { + stringBuilder.append(stringArrayListEntry.getValue().get(i).toString()); + if (i != stringArrayListEntry.getValue().size()) { + stringBuilder.append(","); + } + } + }); + if (!subSection.isEmpty()) { + for (SectionKeyValue sectionKeyValue : subSection) { + stringBuilder.append("\n\t"); + stringBuilder.append(sectionKeyValue.toString().replace("\t", "\t\t")); + } + } else { + stringBuilder.append("\n"); + } + return stringBuilder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/me/piitex/renjava/api/scenes/RenScene.java b/src/main/java/me/piitex/renjava/api/scenes/RenScene.java index 994c877..6c3adea 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/RenScene.java +++ b/src/main/java/me/piitex/renjava/api/scenes/RenScene.java @@ -1,9 +1,5 @@ package me.piitex.renjava.api.scenes; -import javafx.scene.Group; -import javafx.scene.control.Button; -import javafx.scene.image.ImageView; -import javafx.scene.text.Text; import me.piitex.renjava.RenJava; import me.piitex.renjava.api.scenes.animation.AnimationBuilder; import me.piitex.renjava.api.scenes.transitions.Transitions; @@ -19,11 +15,7 @@ import me.piitex.renjava.gui.StageType; import me.piitex.renjava.api.builders.ImageLoader; -import me.piitex.renjava.gui.overlay.ButtonOverlay; -import me.piitex.renjava.gui.overlay.ImageOverlay; import me.piitex.renjava.gui.overlay.Overlay; -import me.piitex.renjava.gui.overlay.TextOverlay; - import java.io.File; import java.util.Collection; @@ -47,7 +39,7 @@ */ public abstract class RenScene extends Container { private final String id; - private final ImageLoader backgroundImage; + private ImageLoader backgroundImage; private Story story; private int index; private SceneStartInterface startInterface; @@ -68,6 +60,7 @@ public abstract class RenScene extends Container { public RenScene(String id, ImageLoader backgroundImage) { this.id = id; this.backgroundImage = backgroundImage; + setStory(RenJava.getInstance().getPlayer().getCurrentStory()); // Update the current story. } public RenScene onStart(SceneStartInterface sceneInterface) { @@ -120,6 +113,10 @@ public ImageLoader getBackgroundImage() { return backgroundImage; } + public void setBackgroundImage(ImageLoader backgroundImage) { + this.backgroundImage = backgroundImage; + } + public SceneStartInterface getStartInterface() { return startInterface; } diff --git a/src/main/java/me/piitex/renjava/api/scenes/text/StringFormatter.java b/src/main/java/me/piitex/renjava/api/scenes/text/StringFormatter.java index 1251828..9c49f3f 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/text/StringFormatter.java +++ b/src/main/java/me/piitex/renjava/api/scenes/text/StringFormatter.java @@ -17,6 +17,7 @@ public static LinkedList formatText(String dialogue) { boolean italic = false; boolean bold = false; + boolean strikeOut = false; int formatBeginChar = 0; LinkedList parts = new LinkedList<>(); @@ -29,24 +30,33 @@ public static LinkedList formatText(String dialogue) { } else if (c == '{' && dialogue.charAt(i + 1) == 'b') { formatBeginChar = i + 1; bold = true; + } else if (c == '{' && dialogue.charAt(i + 1) == 's') { + formatBeginChar = i + 1; + strikeOut = true; } else if (c == '{' && italic) { String italicText = dialogue.substring(formatBeginChar, i); - parts.add(beforeText.replace(italicText, "").replace("/i}", "").replace("/b}", "")); + parts.add(beforeText.replace(italicText, "").replace("/i}", "").replace("/b}", "").replace("/s}", "")); parts.add("iiii: " + italicText.replace("i}", "")); beforeText = ""; italic = false; } else if (c == '{' && bold) { String boldText = dialogue.substring(formatBeginChar, i); - parts.add(beforeText.replace(boldText, "").replace("/i}", "").replace("/b}", "")); + parts.add(beforeText.replace(boldText, "").replace("/i}", "").replace("/b}", "").replace("/s}", "")); parts.add("bbbb: " + boldText.replace("b}", "")); beforeText = ""; bold = false; + } else if (c == '{' && strikeOut) { + String strikeOutText = dialogue.substring(formatBeginChar, i); + parts.add(beforeText.replace(strikeOutText, "").replace("/s}", "").replace("/b}", "").replace("/i}", "")); + parts.add("ssss: " + strikeOutText.replace("s}", "")); + beforeText = ""; + strikeOut = false; } else { // Process text that is not formatted. beforeText += c; } } - beforeText = beforeText.replace("/i}", "").replace("/b}", ""); + beforeText = beforeText.replace("/i}", "").replace("/b}", "").replace("/s}", ""); parts.add(beforeText); LinkedList texts = new LinkedList<>(); @@ -67,6 +77,12 @@ public static LinkedList formatText(String dialogue) { Text text1 = new Text(s); text1.setFont(italicFont); texts.add(text1); + } else if (s.startsWith("ssss: ")) { + s = s.replace("ssss: ", ""); + Text text1 = new Text(s); + text1.setFont(currentFont); + text1.setStrikethrough(true); + texts.add(text1); } else { Text text1 = new Text(s); text1.setFont(currentFont); @@ -78,10 +94,11 @@ public static LinkedList formatText(String dialogue) { // Testing function. Should be removed later public static void main(String[] args) { - String data = "{i}Heey{/i} I've been waiting for you. You were {b}SUPPOSED{/b} to be here by now."; + String data = "{i}Heey...{/i} {s}I've been waiting for you.{/s} You were {b}SUPPOSED{/b} to be here by now."; boolean italic = false; boolean bold = false; + boolean strikeOut = false; int formatBeginChar = 0; @@ -95,10 +112,13 @@ public static void main(String[] args) { } else if (c == '{' && data.charAt(i + 1) == 'b') { formatBeginChar = i + 1; bold = true; + } else if (c == '{' && data.charAt(i + 1) == 's') { + formatBeginChar = i + 1; + strikeOut = true; } else if (c == '{' && italic) { String italicText = data.substring(formatBeginChar, i); System.out.println("Italic Text: " + italicText); - parts.add(beforeText.replace(italicText, "").replace("/i}", "").replace("/b}", "")); + parts.add(beforeText.replace(italicText, "").replace("/i}", "").replace("/b}", "").replace("/s}", "")); parts.add(italicText.replace("i}", "")); beforeText = ""; italic = false; @@ -106,10 +126,18 @@ public static void main(String[] args) { String boldText = data.substring(formatBeginChar, i); System.out.println("Bold Text: " + boldText); System.out.println("Before Text: " + beforeText); - parts.add(beforeText.replace(boldText, "").replace("/i}", "").replace("/b}", "")); + parts.add(beforeText.replace(boldText, "").replace("/i}", "").replace("/b}", "").replace("/s}", "")); parts.add(boldText.replace("b}", "")); beforeText = ""; bold = false; + } else if (c == '{' && strikeOut) { + String strikeOutText = data.substring(formatBeginChar, i); + System.out.println("StrikeOut Text: " + strikeOutText); + System.out.println("Before Text: " + beforeText); + parts.add(beforeText.replace(strikeOutText, "").replace("/s}", "").replace("/b}", "").replace("/i}", "")); + parts.add(strikeOutText.replace("s}", "")); + beforeText = ""; + strikeOut = false; } else { // Process text that is not formatted. beforeText += c; diff --git a/src/main/java/me/piitex/renjava/api/scenes/types/ImageScene.java b/src/main/java/me/piitex/renjava/api/scenes/types/ImageScene.java index e4a78ae..c8cd128 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/types/ImageScene.java +++ b/src/main/java/me/piitex/renjava/api/scenes/types/ImageScene.java @@ -1,32 +1,24 @@ package me.piitex.renjava.api.scenes.types; -import javafx.animation.Animation; -import javafx.animation.Timeline; -import javafx.scene.image.Image; import javafx.scene.text.*; -import javafx.stage.Stage; import me.piitex.renjava.RenJava; -import me.piitex.renjava.api.builders.TextFlowBuilder; import me.piitex.renjava.api.characters.Character; import me.piitex.renjava.api.scenes.RenScene; -import me.piitex.renjava.api.scenes.animation.AnimationBuilder; import me.piitex.renjava.api.scenes.text.StringFormatter; -import me.piitex.renjava.api.scenes.transitions.Transitions; import me.piitex.renjava.configuration.RenJavaConfiguration; -import me.piitex.renjava.events.types.SceneAnimationStartEvent; import me.piitex.renjava.events.types.SceneBuildEvent; import me.piitex.renjava.events.types.SceneStartEvent; import me.piitex.renjava.gui.Menu; import me.piitex.renjava.gui.StageType; import me.piitex.renjava.api.builders.FontLoader; import me.piitex.renjava.api.builders.ImageLoader; -import me.piitex.renjava.gui.exceptions.ImageNotFoundException; import me.piitex.renjava.gui.overlay.*; import org.jetbrains.annotations.Nullable; import java.io.File; import java.net.MalformedURLException; +import java.util.AbstractMap; import java.util.LinkedList; @@ -58,8 +50,8 @@ public class ImageScene extends RenScene { private Character character; private String dialogue; - private final ImageLoader backgroundImage; - + private ImageLoader backgroundImage; + private Font font; private String characterDisplayName; private final RenJavaConfiguration configuration; @@ -80,16 +72,26 @@ public ImageScene(String id, @Nullable Character character, String dialogue, @Nu super(id, loader); this.character = character; this.dialogue = dialogue; - if (loader == null) { - backgroundImage = renJava.getPlayer().getLastDisplayedImage(); - } else { + if (loader != null) { this.backgroundImage = loader; - renJava.getPlayer().setLastDisplayedImage(backgroundImage); + renJava.getLogger().info("Story: " + getStory().getId()); + renJava.getPlayer().setLastDisplayedImage(new AbstractMap.SimpleEntry<>(getStory().getId(), loader)); } if (character != null) { this.characterDisplayName = character.getDisplayName(); } configuration = renJava.getConfiguration(); + font = configuration.getDialogueFont().getFont(); + } + + public ImageScene(String id, @Nullable Character character, String dialogue) { + super(id, null); + this.character = character; + this.dialogue = dialogue; + backgroundImage = renJava.getPlayer().getLastDisplayedImage().getValue(); + setBackgroundImage(backgroundImage); + configuration = renJava.getConfiguration(); + font = configuration.getDialogueFont().getFont(); } public Character getCharacter() { @@ -108,13 +110,21 @@ public void setDialogue(String dialogue) { this.dialogue = dialogue; } + public Font getDialogueFont() { + return font; + } + + public void setDialogueFont(Font font) { + this.font = font; + } + @Override public Menu build(boolean ui) { Menu rootMenu = new Menu(configuration.getWidth(), configuration.getHeight(), backgroundImage); if (ui) { - Text characterDisplay = null; - if (dialogue != null && !dialogue.isEmpty()) { + Text characterDisplay; + if (character != null) { if (getCharacterNameDisplay() != null) { // Set character display characterDisplay = new Text(getCharacterNameDisplay()); @@ -122,47 +132,45 @@ public Menu build(boolean ui) { characterDisplay = new Text(character.getDisplayName()); } characterDisplay.setFill(character.getColor()); - } - if (dialogue != null && !dialogue.isEmpty()) { - Image textbox = null; - try { - textbox = new ImageLoader("gui/textbox.png").build(); - } catch (ImageNotFoundException e) { - renJava.getLogger().severe(e.getMessage()); - } finally { - if (textbox != null) { - Menu textboxMenu = new Menu(configuration.getWidth(), configuration.getHeight() - textbox.getHeight()); - - try { - ImageOverlay textBoxImage = new ImageOverlay(new ImageLoader("gui/textbox.png").build(), configuration.getDialogueBoxX() + configuration.getDialogueOffsetX(), configuration.getDialogueBoxY() + configuration.getDialogueOffsetY()); - textboxMenu.addOverlay(textBoxImage); - } catch (ImageNotFoundException e) { - renJava.getLogger().severe(e.getMessage()); - } - - LinkedList texts = StringFormatter.formatText(dialogue); - TextFlowBuilder textFlowBuilder; - if (texts.isEmpty()) { - Text text = new Text(dialogue); - text.setFont(renJava.getConfiguration().getDialogueFont().getFont()); - textFlowBuilder = new TextFlowBuilder(text, configuration.getDialogueBoxWidth(), configuration.getDialogueBoxHeight()); - } else { - textFlowBuilder = new TextFlowBuilder(texts, configuration.getDialogueBoxWidth(), configuration.getDialogueBoxHeight()); - } - textboxMenu.addOverlay(new TextFlowOverlay(textFlowBuilder, configuration.getTextX() + configuration.getTextOffsetX(), configuration.getTextY() + configuration.getTextOffsetY())); - - characterDisplay.setFont(new FontLoader(renJava.getConfiguration().getDefaultFont().getFont(), configuration.getCharacterTextSize()).getFont()); - characterDisplay.setFill(character.getColor()); - characterDisplay.setX(configuration.getCharacterTextX() + configuration.getCharacterTextOffsetX()); - characterDisplay.setY(configuration.getCharacterTextY() + configuration.getCharacterTextOffsetY()); - - textboxMenu.addOverlay(new TextOverlay(characterDisplay, characterDisplay.getX(), characterDisplay.getY())); - rootMenu.addMenu(textboxMenu); + if (dialogue != null && !dialogue.isEmpty()) { + ImageLoader textbox = new ImageLoader("gui/textbox.png"); + Menu textboxMenu = new Menu(configuration.getDialogueBoxWidth(), configuration.getDialogueBoxHeight()); + + ImageOverlay textBoxImage = new ImageOverlay(textbox, configuration.getDialogueBoxX() + configuration.getDialogueOffsetX(), configuration.getDialogueBoxY() + configuration.getDialogueOffsetY()); + textboxMenu.addOverlay(textBoxImage); + + LinkedList texts = StringFormatter.formatText(dialogue); + TextFlowOverlay textFlowOverlay; + if (texts.isEmpty()) { + Text text = new Text(dialogue); + text.setFont(renJava.getConfiguration().getDialogueFont().getFont()); + textFlowOverlay = new TextFlowOverlay(text, configuration.getDialogueBoxWidth(), configuration.getDialogueBoxHeight()); + } else { + textFlowOverlay = new TextFlowOverlay(texts, configuration.getDialogueBoxWidth(), configuration.getDialogueBoxHeight()); } + textFlowOverlay.setX(configuration.getTextX() + configuration.getTextOffsetX()); + textFlowOverlay.setY(configuration.getTextY() + configuration.getTextOffsetY()); + textFlowOverlay.setTextColor(configuration.getDialogueColor()); + textFlowOverlay.setFont(font); + textboxMenu.addOverlay(textFlowOverlay); + + characterDisplay.setFill(character.getColor()); + TextOverlay characterText = new TextOverlay(characterDisplay, new FontLoader(configuration.getDefaultFont().getFont(), configuration.getCharacterTextSize()), + configuration.getCharacterTextX() + configuration.getCharacterTextOffsetX(), + configuration.getCharacterTextY() + configuration.getCharacterTextOffsetY()); + + characterDisplay.setX(configuration.getCharacterTextX() + configuration.getCharacterTextOffsetX()); + characterDisplay.setY(configuration.getCharacterTextY() + configuration.getCharacterTextOffsetY()); + + textboxMenu.addOverlay(characterText); + + rootMenu.addMenu(textboxMenu); } } } + + for (File file : getStyleSheets()) { try { RenJava.getInstance().getStage().getScene().getStylesheets().add(file.toURI().toURL().toExternalForm()); @@ -185,7 +193,6 @@ public void render(Menu menu) { SceneStartEvent event = new SceneStartEvent(this); RenJava.callEvent(event); - } @Override diff --git a/src/main/java/me/piitex/renjava/api/scenes/types/choices/Choice.java b/src/main/java/me/piitex/renjava/api/scenes/types/choices/Choice.java index ab18c6b..1571d37 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/types/choices/Choice.java +++ b/src/main/java/me/piitex/renjava/api/scenes/types/choices/Choice.java @@ -1,6 +1,6 @@ package me.piitex.renjava.api.scenes.types.choices; -import me.piitex.renjava.api.builders.ButtonBuilder; +import me.piitex.renjava.gui.overlay.ButtonOverlay; /** * The Choice class represents a choice in a ChoiceScene within the RenJava framework. @@ -23,7 +23,7 @@ * @see ChoiceScene */ public class Choice { - private ButtonBuilder builder; + private ButtonOverlay buttonOverlay; private final String id; private String text; // This can be final, but maybe someone wants to modify the text in some way? I don't know but that could be cool to see @@ -38,8 +38,8 @@ public Choice(String id, String text) { this.text = text; } - public ButtonBuilder getBuilder() { - return builder; + public ButtonOverlay getBuilder() { + return buttonOverlay; } public String getId() { diff --git a/src/main/java/me/piitex/renjava/api/scenes/types/choices/ChoiceScene.java b/src/main/java/me/piitex/renjava/api/scenes/types/choices/ChoiceScene.java index 90e8a2f..848c89d 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/types/choices/ChoiceScene.java +++ b/src/main/java/me/piitex/renjava/api/scenes/types/choices/ChoiceScene.java @@ -8,16 +8,17 @@ import me.piitex.renjava.RenJava; import me.piitex.renjava.api.scenes.RenScene; import me.piitex.renjava.events.types.ButtonClickEvent; +import me.piitex.renjava.events.types.ChoiceButtonBuildEvent; import me.piitex.renjava.events.types.SceneStartEvent; import me.piitex.renjava.gui.Menu; import me.piitex.renjava.gui.StageType; -import me.piitex.renjava.api.builders.ButtonBuilder; import me.piitex.renjava.api.builders.ImageLoader; import me.piitex.renjava.gui.exceptions.ImageNotFoundException; import me.piitex.renjava.gui.layouts.impl.VerticalLayout; import me.piitex.renjava.gui.overlay.ButtonOverlay; import java.util.LinkedHashSet; +import java.util.Map; /** * The ChoiceScene class represents a scene in the RenJava framework that presents the player with multiple choices. @@ -62,7 +63,7 @@ * @see ChoiceSelectInterface */ public class ChoiceScene extends RenScene { - private final ImageLoader backgroundImage; + private ImageLoader backgroundImage; private ChoiceSelectInterface selectInterface; @@ -84,6 +85,17 @@ public ChoiceScene(String id, ImageLoader backgroundImage) { this.backgroundImage = backgroundImage; } + /** + * Creates a ChoiceScene object with the specified identifier. + * + * @param id The unique identifier for the scene. + */ + public ChoiceScene(String id) { + super(id, null); + this.backgroundImage = RenJava.getInstance().getPlayer().getLastDisplayedImage().getValue(); + setBackgroundImage(backgroundImage); + } + public ChoiceScene addChoice(Choice choice) { choices.add(choice); return this; @@ -139,8 +151,13 @@ public Menu build(boolean ui) { if (ui) { VerticalLayout layout = new VerticalLayout(500, 500); - layout.setXPosition(((RenJava.getInstance().getConfiguration().getWidth() - layout.getWidth()) / 2) - 600); - layout.setYPosition(((RenJava.getInstance().getConfiguration().getHeight() - layout.getHeight()) / 2) - 200); + //layout.setX(((double) (RenJava.getInstance().getConfiguration().getWidth() - layout.getWidth()) / 2) - 600); + //layout.setY(((double) (RenJava.getInstance().getConfiguration().getHeight() - layout.getHeight()) / 2) - 200); + Map.Entry midPoint = RenJava.getInstance().getConfiguration().getMidPoint(); + System.out.println("Set X: " + midPoint.getKey()); + System.out.println("Set Y: " + midPoint.getValue()); + layout.setX(midPoint.getKey() - 600); + layout.setY(midPoint.getValue() - 200); layout.setSpacing(20.0); ImageLoader choiceBoxImage = new ImageLoader("gui/button/choice_idle_background.png"); @@ -150,7 +167,7 @@ public Menu build(boolean ui) { buttonOverlay = new ButtonOverlay(getChoiceButton(choice, choiceBoxImage.build())); layout.addOverlays(buttonOverlay); } catch (ImageNotFoundException e) { - throw new RuntimeException(e); + RenJava.getInstance().getLogger().severe(e.getMessage()); } } menu.addLayout(layout); @@ -168,8 +185,16 @@ public void render(Menu menu) { } private Button getChoiceButton(Choice choice, Image image) { - ButtonBuilder builder = new ButtonBuilder(choice.getId(), choice.getText(), RenJava.getInstance().getConfiguration().getDefaultFont().getFont(), Color.BLACK, 0, 0, 1, 1); - Button button = builder.build(); + ButtonOverlay buttonOverlay = new ButtonOverlay(choice.getId(), choice.getText(), RenJava.getInstance().getConfiguration().getDefaultFont().getFont(), Color.BLACK, 0, 0, 1, 1); + buttonOverlay.setBorderColor(Color.TRANSPARENT); + buttonOverlay.setBackgroundColor(Color.TRANSPARENT); + buttonOverlay.setHover(true); + buttonOverlay.setTextFill(Color.WHITE); + buttonOverlay.setHoverColor(Color.BLUE); + + + ChoiceButtonBuildEvent choiceButtonBuildEvent = new ChoiceButtonBuildEvent(buttonOverlay); + Button button = choiceButtonBuildEvent.getButtonOverlay().build(); ImageView imageView = new ImageView(image); imageView.setPreserveRatio(true); diff --git a/src/main/java/me/piitex/renjava/api/scenes/types/input/InputScene.java b/src/main/java/me/piitex/renjava/api/scenes/types/input/InputScene.java index 410dea9..a672f35 100644 --- a/src/main/java/me/piitex/renjava/api/scenes/types/input/InputScene.java +++ b/src/main/java/me/piitex/renjava/api/scenes/types/input/InputScene.java @@ -4,8 +4,6 @@ import javafx.scene.text.Text; import me.piitex.renjava.RenJava; import me.piitex.renjava.api.builders.FontLoader; -import me.piitex.renjava.api.builders.InputFieldBuilder; -import me.piitex.renjava.api.characters.Character; import me.piitex.renjava.api.scenes.RenScene; import me.piitex.renjava.api.scenes.types.ImageScene; import me.piitex.renjava.events.types.SceneStartEvent; @@ -73,8 +71,8 @@ public Menu build(boolean ui) { for (Menu otherMenu : menu.getChildren()) { textFlowOverlay = (TextFlowOverlay) otherMenu.getOverlays().stream().filter(overlay -> overlay instanceof TextFlowOverlay).findFirst().orElse(null); if (textFlowOverlay != null) { - Text beforeText = textFlowOverlay.getTextFlowBuilder().getTexts().getLast(); - InputFieldOverlay inputFieldOverlay = new InputFieldOverlay(new InputFieldBuilder(beforeText.getTranslateY() - 30.0, beforeText.getY() + 210.0, new FontLoader(RenJava.getInstance().getConfiguration().getDefaultFont().getFont(), 24.0))); + Text beforeText = textFlowOverlay.getTexts().getLast(); + InputFieldOverlay inputFieldOverlay = new InputFieldOverlay(beforeText.getTranslateY() - 30.0, beforeText.getY() + 210.0, new FontLoader(RenJava.getInstance().getConfiguration().getDefaultFont().getFont(), 24.0)); otherMenu.addOverlay(inputFieldOverlay); } } diff --git a/src/main/java/me/piitex/renjava/api/stories/Story.java b/src/main/java/me/piitex/renjava/api/stories/Story.java index 934aac1..a641497 100644 --- a/src/main/java/me/piitex/renjava/api/stories/Story.java +++ b/src/main/java/me/piitex/renjava/api/stories/Story.java @@ -112,22 +112,22 @@ public String getId() { */ public void start() { + // Update RenJava Player BEFORE the scenes are added + renJava.getPlayer().setCurrentStory(this.getId()); + + clear(); // Clear previous mappings init(); // Initialize when starting logger.info("Building scene..."); RenScene renScene = getScene(0); // Gets the first scene index. + renJava.getPlayer().updateScene(renScene); // Set to current scene. Menu menu = renScene.build(true); - renJava.getPlayer().updateScene(renScene); // Set to current scene. - SceneBuildEvent buildEvent = new SceneBuildEvent(renScene, menu); RenJava.callEvent(buildEvent); renScene.render(menu); - - // Update RenJava Player - renJava.getPlayer().setCurrentStory(this.getId()); } /** @@ -152,6 +152,11 @@ public void refresh(String sceneID) { scenes.replace(sceneID, scene, scene); } + public void clear() { + scenes.clear(); + sceneIndexMap.clear(); + } + /** * Scenes are ordered the same way they are created. The first scene in a story is the first scene that was created. * @param scene Scene to add the story. @@ -166,7 +171,6 @@ public void addScene(RenScene scene) { int index = sceneIndexMap.size(); sceneIndexMap.put(index, scene); scene.setIndex(index); - scene.setStory(this); // Updates the scene data. } /** @@ -179,7 +183,6 @@ public void addScenes(RenScene... scenes) { int index = sceneIndexMap.size(); sceneIndexMap.put(index, renScene); renScene.setIndex(index); - renScene.setStory(this); } } @@ -275,11 +278,8 @@ public void displayScene(RenScene scene) { } public void displayNextScene() { - SceneEndEvent event = new SceneEndEvent(getPreviousSceneFromCurrent()); - RenJava.callEvent(event); RenScene renScene = getNextSceneFromCurrent(); - RenJava.getInstance().getPlayer().updateScene(renScene); - renScene.render(renScene.build(true)); + displayScene(renScene); } public LinkedHashMap getScenes() { diff --git a/src/main/java/me/piitex/renjava/configuration/RenJavaConfiguration.java b/src/main/java/me/piitex/renjava/configuration/RenJavaConfiguration.java index 2d3d3e2..e768da3 100644 --- a/src/main/java/me/piitex/renjava/configuration/RenJavaConfiguration.java +++ b/src/main/java/me/piitex/renjava/configuration/RenJavaConfiguration.java @@ -16,7 +16,8 @@ public class RenJavaConfiguration { private FontLoader defaultFont; private FontLoader dialogueFont; private FontLoader uiFont; - private Paint dialogueColor = Color.BLACK; + private FontLoader characterDisplayFont; + private Color dialogueColor = Color.BLACK; private int dialogueBoxWidth = 1000; private int dialogueBoxHeight = 600; @@ -34,8 +35,8 @@ public class RenJavaConfiguration { private int textOffsetX = 0; private int textOffsetY = 0; - private int characterTextX = 500; - private int characterTextY = 850; + private int characterTextX = 100; + private int characterTextY = 440; private int characterTextOffsetX = 0; private int characterTextOffsetY = 0; @@ -105,11 +106,19 @@ public void setUiFont(FontLoader uiFont) { this.uiFont = uiFont; } - public Paint getDialogueColor() { + public FontLoader getCharacterDisplayFont() { + return characterDisplayFont; + } + + public void setCharacterDisplayFont(FontLoader characterDisplayFont) { + this.characterDisplayFont = characterDisplayFont; + } + + public Color getDialogueColor() { return dialogueColor; } - public void setDialogueColor(Paint dialogueColor) { + public void setDialogueColor(Color dialogueColor) { this.dialogueColor = dialogueColor; } @@ -257,7 +266,7 @@ public void setCharacterTextOffsetY(int characterTextOffsetY) { // bottom left is 0 on the x and max on the y public Map.Entry getBottomLeft() { - return Map.entry(5, getCurrentHeight()); + return Map.entry(0, getCurrentHeight()); } // Bottom right is max on both @@ -268,11 +277,22 @@ public Map.Entry getBottomRight() { // Top Left is 0,0 public Map.Entry getTopLeft() { - return Map.entry(5, 15); + return Map.entry(0, 0); } + // Top right is max width public Map.Entry getTopRight() { - return Map.entry(getCurrentWidth(), 5); + return Map.entry(getCurrentWidth(), 0); + } + + // Middle point of the screen. + public Map.Entry getMidPoint() { + Map.Entry bottomRight = getBottomRight(); + Map.Entry topLeft = getTopLeft(); + int centerX = (bottomRight.getKey() + topLeft.getKey()) / 2; + int centerY = (bottomRight.getValue() + topLeft.getValue()) / 2; + + return Map.entry(centerX, centerY); } public double getHeightScale() { diff --git a/src/main/java/me/piitex/renjava/events/defaults/GameFlowEventListener.java b/src/main/java/me/piitex/renjava/events/defaults/GameFlowEventListener.java index 2d8d3af..e7ba27b 100644 --- a/src/main/java/me/piitex/renjava/events/defaults/GameFlowEventListener.java +++ b/src/main/java/me/piitex/renjava/events/defaults/GameFlowEventListener.java @@ -78,7 +78,7 @@ public void onMouseClick(MouseClickEvent event) { menu.render(null, null); player.setRightClickMenu(true); - MainMenuRenderEvent renderEvent = new MainMenuRenderEvent(menu); + MainMenuRenderEvent renderEvent = new MainMenuRenderEvent(menu, true); RenJava.callEvent(renderEvent); } else { diff --git a/src/main/java/me/piitex/renjava/events/defaults/MenuClickEventListener.java b/src/main/java/me/piitex/renjava/events/defaults/MenuClickEventListener.java index 499f2db..fc77b39 100644 --- a/src/main/java/me/piitex/renjava/events/defaults/MenuClickEventListener.java +++ b/src/main/java/me/piitex/renjava/events/defaults/MenuClickEventListener.java @@ -4,12 +4,13 @@ import javafx.scene.control.Button; import me.piitex.renjava.RenJava; -import me.piitex.renjava.api.saves.Load; import me.piitex.renjava.api.saves.Save; import me.piitex.renjava.api.saves.exceptions.SaveFileNotFound; +import me.piitex.renjava.api.stories.Story; import me.piitex.renjava.events.EventListener; import me.piitex.renjava.events.Listener; import me.piitex.renjava.events.types.ButtonClickEvent; +import me.piitex.renjava.events.types.GameStartEvent; import me.piitex.renjava.gui.Menu; public class MenuClickEventListener implements EventListener { @@ -20,15 +21,38 @@ public void onButtonClick(ButtonClickEvent event) { Button button = event.getButton(); if (button.getId().equalsIgnoreCase("menu-start-button")) { renJava.getLogger().info("Creating new game..."); + renJava.createBaseData(); + renJava.createStory(); + + // Call GameStartEvent + GameStartEvent event1 = new GameStartEvent(renJava); + RenJava.callEvent(event1); + renJava.start(); } if (button.getId().equalsIgnoreCase("menu-load-button")) { // NOTE: 10/20/2023 new LoadScreenView(new ImageLoader("gui/overlay/game_menu.png")).build(renJava.getStage(), true); - try { - new Load(1); - } catch (SaveFileNotFound e) { - throw new RuntimeException(e); + new Save(1).load(true); + + + // After loading play the current scene and story + String storyID = renJava.getPlayer().getCurrentStoryID(); + if (storyID == null) { + renJava.getLogger().severe("Save file could not be loaded. The data is either not formatted or corrupted."); + return; } + + System.out.println("Story: " + renJava.getPlayer().getCurrentStoryID()); + + renJava.createStory(); + + // Force update fields + renJava.getPlayer().setCurrentStory(storyID); + renJava.getPlayer().getCurrentStory().init(); // Re-initialize story + + renJava.getPlayer().setCurrentScene(renJava.getPlayer().getCurrentSceneID()); + + renJava.getPlayer().getCurrentStory().displayScene(renJava.getPlayer().getCurrentSceneID()); } if (button.getId().equalsIgnoreCase("menu-preference-button")) { //new PreferenceScreenView(new ImageLoader("gui/overlay/game_menu.png")).build(renJava.getStage(), true); @@ -44,7 +68,8 @@ public void onButtonClick(ButtonClickEvent event) { about.render(null, null); } if (button.getId().equalsIgnoreCase("menu-save-button")) { - new Save(1, renJava.getPlayer().getCurrentStory().getId(), renJava.getPlayer().getCurrentScene().getId()); + //new Save(1, renJava.getPlayer().getCurrentStory().getId(), renJava.getPlayer().getCurrentScene().getId()); + new Save(1).write(); // Writes the save. } if (button.getId().equalsIgnoreCase("menu-quit-button")) { renJava.getAddonLoader().disable(); diff --git a/src/main/java/me/piitex/renjava/events/defaults/StoryHandlerEventListener.java b/src/main/java/me/piitex/renjava/events/defaults/StoryHandlerEventListener.java index 3df1a19..8208142 100644 --- a/src/main/java/me/piitex/renjava/events/defaults/StoryHandlerEventListener.java +++ b/src/main/java/me/piitex/renjava/events/defaults/StoryHandlerEventListener.java @@ -23,7 +23,7 @@ public void onSceneStartEvent(SceneStartEvent event) { scene.getStartInterface().onStart(event); } if (story == null) return; - player.getViewedStories().put(story.getId(), story); + player.getViewedStories().add(story.getId()); // Check to see if this scene is the first scene in the story. if (story.getSceneIndex(scene) == 0) { // 0 means the first entry. // Update the story tracker diff --git a/src/main/java/me/piitex/renjava/events/types/ChoiceButtonBuildEvent.java b/src/main/java/me/piitex/renjava/events/types/ChoiceButtonBuildEvent.java new file mode 100644 index 0000000..c8ac659 --- /dev/null +++ b/src/main/java/me/piitex/renjava/events/types/ChoiceButtonBuildEvent.java @@ -0,0 +1,16 @@ +package me.piitex.renjava.events.types; + +import me.piitex.renjava.events.Event; +import me.piitex.renjava.gui.overlay.ButtonOverlay; + +public class ChoiceButtonBuildEvent extends Event { + private final ButtonOverlay buttonOverlay; + + public ChoiceButtonBuildEvent(ButtonOverlay buttonOverlay) { + this.buttonOverlay = buttonOverlay; + } + + public ButtonOverlay getButtonOverlay() { + return buttonOverlay; + } +} diff --git a/src/main/java/me/piitex/renjava/events/types/MainMenuRenderEvent.java b/src/main/java/me/piitex/renjava/events/types/MainMenuRenderEvent.java index 5d99407..394786f 100644 --- a/src/main/java/me/piitex/renjava/events/types/MainMenuRenderEvent.java +++ b/src/main/java/me/piitex/renjava/events/types/MainMenuRenderEvent.java @@ -5,12 +5,22 @@ public class MainMenuRenderEvent extends Event { private final Menu menu; + private boolean rightClicked = false; public MainMenuRenderEvent(Menu menu) { this.menu = menu; } + public MainMenuRenderEvent(Menu menu, boolean rightClicked) { + this.menu = menu; + this.rightClicked = rightClicked; + } + public Menu getMenu() { return menu; } + + public boolean isRightClicked() { + return rightClicked; + } } diff --git a/src/main/java/me/piitex/renjava/gui/Element.java b/src/main/java/me/piitex/renjava/gui/Element.java index ea14d90..5686ea6 100644 --- a/src/main/java/me/piitex/renjava/gui/Element.java +++ b/src/main/java/me/piitex/renjava/gui/Element.java @@ -6,6 +6,7 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.Pane; +import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; import me.piitex.renjava.api.scenes.transitions.Transitions; @@ -26,6 +27,10 @@ public Element(Overlay overlay) { this.node = imageView; } else if (overlay instanceof TextOverlay textOverlay) { Text text = textOverlay.getText(); + if (textOverlay.getFontLoader() != null) { + Font font = textOverlay.getFontLoader().getFont(); + text.setFont(font); + } text.setTranslateX(textOverlay.x()); text.setTranslateY(textOverlay.y()); this.node = text; @@ -35,7 +40,7 @@ public Element(Overlay overlay) { button.setTranslateY(buttonOverlay.y()); this.node = button; } else if (overlay instanceof TextFlowOverlay textFlowOverlay) { - TextFlow textFlow = textFlowOverlay.getTextFlowBuilder().build(); + TextFlow textFlow = textFlowOverlay.build(); textFlow.setTranslateX(textFlowOverlay.x()); textFlow.setTranslateY(textFlowOverlay.y()); this.node = textFlow; diff --git a/src/main/java/me/piitex/renjava/gui/GuiLoader.java b/src/main/java/me/piitex/renjava/gui/GuiLoader.java index 4e408ef..1a4e8f4 100644 --- a/src/main/java/me/piitex/renjava/gui/GuiLoader.java +++ b/src/main/java/me/piitex/renjava/gui/GuiLoader.java @@ -25,8 +25,6 @@ public GuiLoader(Stage stage, RenJava renJava, HostServices services) { this.stage = stage; this.renJava = renJava; renJava.setHost(services); - GameStartEvent event = new GameStartEvent(renJava); - RenJava.callEvent(event); buildSplashScreen(); } @@ -38,7 +36,7 @@ private void buildSplashScreen() { Menu menu = renJava.buildSplashScreen(); if (menu == null) { - renJava.getLogger().warning("Splash screen not found."); + renJava.getLogger().warning("No splash screen was rendered.."); renJavaFrameworkBuild(); return; // Don't create a splash screen if one wasn't set. } @@ -71,6 +69,7 @@ private void buildMainMenu() { renJava.getLogger().severe("No default font set."); renJava.getConfiguration().setDefaultFont(new FontLoader("Arial", 24)); renJava.getConfiguration().setUiFont(new FontLoader("Arial", 26)); + renJava.getConfiguration().setCharacterDisplayFont(new FontLoader("Arial", 26)); } stage = new Stage(); @@ -88,10 +87,8 @@ private void buildMainMenu() { try { menu.setBackgroundImage(new ImageLoader("gui/main_menu.png").build()); } catch (ImageNotFoundException e) { - throw new RuntimeException(e); + logger.severe(e.getMessage()); } - } else { - logger.info("Rendering main menu..."); } Menu sideMenu = renJava.buildSideMenu(); diff --git a/src/main/java/me/piitex/renjava/gui/LayoutMenu.java b/src/main/java/me/piitex/renjava/gui/LayoutMenu.java new file mode 100644 index 0000000..5419058 --- /dev/null +++ b/src/main/java/me/piitex/renjava/gui/LayoutMenu.java @@ -0,0 +1,92 @@ +package me.piitex.renjava.gui; + +import javafx.scene.Node; +import me.piitex.renjava.gui.layouts.Layout; +import me.piitex.renjava.gui.overlay.Overlay; + +import java.util.LinkedHashSet; + +public abstract class LayoutMenu { + private final Menu menu; + private final int width, height; + private int x, y; + + private final LinkedHashSet nodes = new LinkedHashSet<>(); + private final LinkedHashSet layouts = new LinkedHashSet<>(); + private final LinkedHashSet overlays = new LinkedHashSet<>(); + private final LinkedHashSet children = new LinkedHashSet<>(); + + public LayoutMenu(Menu menu, int width, int height) { + this.menu = menu; + this.width = width; + this.height = height; + menu.addParent(this); + } + + public Menu getMenu() { + return menu; + } + + public abstract void render(); + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + public LinkedHashSet getNodes() { + return nodes; + } + + public void addNode(Node node) { + this.nodes.add(node); + } + + public LinkedHashSet getLayouts() { + return layouts; + } + + public LayoutMenu addLayout(Layout layout) { + layouts.add(layout); + return this; + } + + public LinkedHashSet getOverlays() { + return overlays; + } + + public LayoutMenu addOverlay(Overlay overlay) { + overlays.add(overlay); + return this; + } + + public LinkedHashSet getChildren() { + return children; + } + + /* Rendering functions */ + + public LayoutMenu addMenu(Menu menu) { + this.children.add(menu); + return this; + } +} diff --git a/src/main/java/me/piitex/renjava/gui/Menu.java b/src/main/java/me/piitex/renjava/gui/Menu.java index ebda313..3f08c94 100644 --- a/src/main/java/me/piitex/renjava/gui/Menu.java +++ b/src/main/java/me/piitex/renjava/gui/Menu.java @@ -5,7 +5,6 @@ import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.layout.*; -import javafx.scene.paint.Color; import javafx.stage.Stage; import me.piitex.renjava.RenJava; @@ -18,8 +17,6 @@ import me.piitex.renjava.gui.overlay.*; import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.net.MalformedURLException; import java.util.LinkedHashSet; import java.util.logging.Logger; @@ -39,7 +36,7 @@ public class Menu { private Image backgroundImage; private final LinkedHashSet nodes = new LinkedHashSet<>(); - + private final LinkedHashSet parents = new LinkedHashSet<>(); private final LinkedHashSet layouts = new LinkedHashSet<>(); private final LinkedHashSet overlays = new LinkedHashSet<>(); private final LinkedHashSet children = new LinkedHashSet<>(); @@ -54,10 +51,12 @@ public Menu(double width, double height) { } public Menu(double width, double height, ImageLoader imageLoader) { - try { - this.backgroundImage = imageLoader.build(); - } catch (ImageNotFoundException e) { - e.printStackTrace(); + if (imageLoader != null) { + try { + this.backgroundImage = imageLoader.build(); + } catch (ImageNotFoundException e) { + e.printStackTrace(); + } } this.width = width; this.height = height; @@ -135,6 +134,14 @@ public Menu addOverlay(Overlay overlay) { return this; } + public LinkedHashSet getParents() { + return parents; + } + + public void addParent(LayoutMenu layoutMenu) { + parents.add(layoutMenu); + } + public LinkedHashSet getChildren() { return children; } @@ -158,8 +165,6 @@ public Menu addMenu(Menu menu) { * @param renScene The RenScene that is being used. If null, it will be assumed this is a main menu screen. */ public Pane render(@Nullable Pane root, @Nullable RenScene renScene) { - // TODO: 2/13/2024 Make an element class which can render every overlay instead of this spaghettiti code. - Logger logger = renJava.getLogger(); if (root == null) { @@ -168,21 +173,43 @@ public Pane render(@Nullable Pane root, @Nullable RenScene renScene) { root.setTranslateX(x); root.setTranslateY(y); + root.setPrefSize(width, height); - Element backgroundImgElement = new Element(new ImageOverlay(backgroundImage, 0, 0)); + // Background fill is used for fade ins. + BackgroundFill backgroundFill = new BackgroundFill(BLACK, new CornerRadii(1), new Insets(0,0,0,0)); + root.setBackground(new Background(backgroundFill)); - backgroundImgElement.render(root); + if (backgroundImage != null) { + Element backgroundImgElement = new Element(new ImageOverlay(backgroundImage, 0, 0)); + backgroundImgElement.render(root); + } logger.info("Rendering layouts..."); for (Layout layout : layouts) { for (Overlay overlay : layout.getOverlays()) { new Element(overlay).render(layout.getPane()); } - + for (Layout child : layout.getChildLayouts()) { + // A child layout should be added to a main layout. + for (Overlay overlay : child.getOverlays()) { + new Element(overlay).render(child.getPane()); + } + + Pane childPane = layout.getPane(); + childPane.setTranslateX(child.getX()); + childPane.setTranslateY(child.getY()); + childPane.setPrefSize(child.getWidth(), child.getHeight()); + if (childPane instanceof HBox hBox) { + hBox.setSpacing(layout.getSpacing()); + } else if (childPane instanceof VBox vBox) { + vBox.setSpacing(layout.getSpacing()); + } + layout.getPane().getChildren().add(childPane); // Adds the child layout to the main layout. + } Pane box = layout.getPane(); - box.setTranslateX(layout.getXPosition()); - box.setTranslateY(layout.getYPosition()); - box.setPrefSize(layout.getWidth(), layout.getWidth()); + box.setTranslateX(layout.getX()); + box.setTranslateY(layout.getY()); + box.setPrefSize(layout.getWidth(), layout.getHeight()); if (box instanceof HBox hBox) { hBox.setSpacing(layout.getSpacing()); } else if (box instanceof VBox vBox) { @@ -193,19 +220,18 @@ public Pane render(@Nullable Pane root, @Nullable RenScene renScene) { } for (Overlay overlay : overlays) { - new Element(overlay).render(root); + new Element(overlay).render(root); } + for (Menu menu : children) { - menu.render(root, renScene); // Renders menu on top of this menu. + if (menu != null) { + menu.render(root, renScene); // Renders menu on top of this menu. + } } rootMenu = this; - // Background fill is used for fade ins. - BackgroundFill backgroundFill = new BackgroundFill(BLACK, new CornerRadii(1), new Insets(0,0,0,0)); - root.setBackground(new Background(backgroundFill)); - Scene scene; if (stage.getScene() != null) { scene = stage.getScene(); @@ -215,12 +241,6 @@ public Pane render(@Nullable Pane root, @Nullable RenScene renScene) { scene = stage.getScene(); } - try { - scene.getStylesheets().add(new File(System.getProperty("user.dir") + "/game/css/button.css").toURI().toURL().toExternalForm()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - setInputControls(scene); this.pane = root; @@ -261,5 +281,4 @@ private void setInputControls(Scene scene) { RenJava.callEvent(event); }); } - } \ No newline at end of file diff --git a/src/main/java/me/piitex/renjava/gui/layouts/Container.java b/src/main/java/me/piitex/renjava/gui/layouts/Container.java index 751c35e..840569b 100644 --- a/src/main/java/me/piitex/renjava/gui/layouts/Container.java +++ b/src/main/java/me/piitex/renjava/gui/layouts/Container.java @@ -2,8 +2,6 @@ import javafx.stage.Stage; import me.piitex.renjava.gui.Menu; -import me.piitex.renjava.gui.layouts.Layout; -import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.HashSet; diff --git a/src/main/java/me/piitex/renjava/gui/layouts/Layout.java b/src/main/java/me/piitex/renjava/gui/layouts/Layout.java index b4a27f8..280da3e 100644 --- a/src/main/java/me/piitex/renjava/gui/layouts/Layout.java +++ b/src/main/java/me/piitex/renjava/gui/layouts/Layout.java @@ -9,11 +9,12 @@ public abstract class Layout { private final Pane pane; // Get's the pane type for javafx - private final LinkedHashSet overlays = new LinkedHashSet<>(); - private double xPosition; - private double yPosition; + private double x; + private double y; private int width, height; private double spacing; + private final LinkedHashSet overlays = new LinkedHashSet<>(); + private final LinkedHashSet childLayouts = new LinkedHashSet<>(); protected Layout(Pane pane) { this.pane = pane; @@ -23,20 +24,20 @@ public Pane getPane() { return pane; } - public double getXPosition() { - return xPosition; + public double getX() { + return x; } - public void setXPosition(int xPosition) { - this.xPosition = xPosition; + public void setX(double x) { + this.x = x; } - public double getYPosition() { - return yPosition; + public double getY() { + return y; } - public void setYPosition(int yPosition) { - this.yPosition = yPosition; + public void setY(double y) { + this.y = y; } public int getWidth() { @@ -70,4 +71,12 @@ public Collection getOverlays() { public void addOverlays(Overlay... overlays) { this.overlays.addAll(List.of(overlays)); } + + public void addChildLayout(Layout layout) { + this.childLayouts.add(layout); + } + + public LinkedHashSet getChildLayouts() { + return childLayouts; + } } diff --git a/src/main/java/me/piitex/renjava/gui/layouts/ScrollPaneMenu.java b/src/main/java/me/piitex/renjava/gui/layouts/ScrollPaneMenu.java new file mode 100644 index 0000000..80aa92a --- /dev/null +++ b/src/main/java/me/piitex/renjava/gui/layouts/ScrollPaneMenu.java @@ -0,0 +1,25 @@ +package me.piitex.renjava.gui.layouts; + +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.Pane; + +import me.piitex.renjava.gui.Menu; +import me.piitex.renjava.gui.LayoutMenu; + +public class ScrollPaneMenu extends LayoutMenu { + + public ScrollPaneMenu(Menu menu, int width, int height) { + super(menu, width, height); + } + + @Override + public void render() { + Pane pane = getMenu().getPane(); + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setPrefSize(getWidth(), getHeight()); + scrollPane.setTranslateX(getX()); + scrollPane.setTranslateY(getY()); + + pane.getChildren().add(scrollPane); // Adds to menu + } +} diff --git a/src/main/java/me/piitex/renjava/gui/layouts/impl/HorizontalLayout.java b/src/main/java/me/piitex/renjava/gui/layouts/impl/HorizontalLayout.java index b527d8c..44168f8 100644 --- a/src/main/java/me/piitex/renjava/gui/layouts/impl/HorizontalLayout.java +++ b/src/main/java/me/piitex/renjava/gui/layouts/impl/HorizontalLayout.java @@ -2,7 +2,6 @@ import javafx.scene.layout.HBox; import me.piitex.renjava.gui.layouts.Layout; -import me.piitex.renjava.gui.overlay.Overlay; /** * Groups overlays and elements horizontally. diff --git a/src/main/java/me/piitex/renjava/gui/overlay/ButtonOverlay.java b/src/main/java/me/piitex/renjava/gui/overlay/ButtonOverlay.java index 56e95bd..48b176f 100644 --- a/src/main/java/me/piitex/renjava/gui/overlay/ButtonOverlay.java +++ b/src/main/java/me/piitex/renjava/gui/overlay/ButtonOverlay.java @@ -1,29 +1,309 @@ package me.piitex.renjava.gui.overlay; import javafx.scene.control.Button; -import me.piitex.renjava.api.builders.ButtonBuilder; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import me.piitex.renjava.RenJava; +import me.piitex.renjava.api.builders.ImageLoader; import me.piitex.renjava.api.scenes.transitions.Transitions; +import me.piitex.renjava.events.types.ButtonClickEvent; +import me.piitex.renjava.gui.exceptions.ImageNotFoundException; + +import java.util.concurrent.atomic.AtomicReference; public class ButtonOverlay implements Overlay { - private final Button button; + private Button button; private Transitions transitions; + private final String id; + private String text; + private Font font; + private Image image; + private Color textFill; + private Color backgroundColor; + private Color borderColor; + private Color hoverColor; + private boolean hover; + private int borderWidth = 0; + private int backgroundRadius = 0; + + private double x = 1, y = 1; + private final double xScale, yScale; + + public ButtonOverlay(String id, String text, Color textFill, double xScale, double yScale) { + this.id = id; + this.text = text; + this.textFill = textFill; + this.xScale = x; + this.yScale = y; + } + + public ButtonOverlay(String id, String text, Color textFill, Font font, double xScale, double yScale) { + this.id = id; + this.text = text; + this.textFill = textFill; + this.font = font; + this.xScale = x; + this.yScale = y; + } + + /** + * Create a button with only text. + * + * @param id Identifier for the button. + * @param text Text that will be displayed inside the button. + * @param textFill Color of the text. + * @param x X-Axis position of the button. + * @param y Y-Axis position of the button. + * @param xScale X-Axis scale of the button. + * @param yScale Y-Axis scale of the button. + */ + public ButtonOverlay(String id, String text, Color textFill, double x, double y, double xScale, double yScale) { + this.id = id; + this.text = text; + this.textFill = textFill; + this.x = x; + this.y = y; + this.xScale = xScale; + this.yScale = yScale; + } + + /** + * Create a button with only text with a specific font. + * + * @param id Identifier for the button. + * @param text Text that will be displayed inside the button. + * @param font Font to be used for the text. + * @param textFill Color of the text. + * @param x X-Axis position of the button. + * @param y Y-Axis position of the button. + * @param xScale X-Axis scale of the button. + * @param yScale Y-Axis scale of the button. + */ + public ButtonOverlay(String id, String text, Font font, Color textFill, double x, double y, double xScale, double yScale) { + this.id = id; + this.text = text; + this.font = font; + this.textFill = textFill; + this.x = x; + this.y = y; + this.xScale = xScale; + this.yScale = yScale; + } + + /** + * Create a button with only text with a specific font. + * + * @param id Identifier for the button. + * @param text Text that will be displayed inside the button. + * @param font Font to be used for the text. + * @param textFill Color of the text. + * @param xScale X-Axis scale of the button. + * @param yScale Y-Axis scale of the button. + */ + public ButtonOverlay(String id, String text, Font font, Color textFill, double xScale, double yScale) { + this.id = id; + this.text = text; + this.font = font; + this.textFill = textFill; + this.xScale = xScale; + this.yScale = yScale; + } + + public ButtonOverlay(String id, String text, Font font, Color textFill, Color backgroundColor, Color borderColor, double xScale, double yScale) { + this.id = id; + this.text = text; + this.font = font; + this.textFill = textFill; + this.xScale = xScale; + this.yScale = yScale; + this.backgroundColor = backgroundColor; + this.borderColor = borderColor; + } + + public ButtonOverlay(String id, String text, Font font, Color textFill, Color backgroundColor, Color borderColor, boolean hover, double xScale, double yScale) { + this.id = id; + this.text = text; + this.font = font; + this.textFill = textFill; + this.xScale = xScale; + this.yScale = yScale; + this.backgroundColor = backgroundColor; + this.borderColor = borderColor; + this.hover = hover; + } + + public ButtonOverlay(String id, String text, Font font, Color textFill, Color backgroundColor, Color borderColor, Color hoverColor, double xScale, double yScale) { + this.id = id; + this.text = text; + this.font = font; + this.textFill = textFill; + this.xScale = xScale; + this.yScale = yScale; + this.backgroundColor = backgroundColor; + this.borderColor = borderColor; + this.hover = true; + this.hoverColor = hoverColor; + } + + /** + * Create a button with only an image. + * + * @param id Identifier for the button. + * @param imageLoader Image to be displayed inside the button. + * @param x X-Axis position of the button. + * @param y Y-Axis position of the button. + * @param xScale X-Axis scale of the button. + * @param yScale Y-Axis scale of the button. + */ + public ButtonOverlay(String id, ImageLoader imageLoader, double x, double y, double xScale, double yScale) { + this.id = id; + try { + this.image = imageLoader.build(); + } catch (ImageNotFoundException e) { + throw new RuntimeException(e); + } + this.x = x; + this.y = y; + this.xScale = xScale; + this.yScale = yScale; + } + + /** + * Create a button with image and text + * + * @param id Identifier for the button. + * @param imageLoader Image to be displayed inside the button. + * @param text Text to be displayed inside the button. + * @param x X-Axis position of the button. + * @param y Y-Axis position of the button. + * @param xScale X-Axis scale of the button. + * @param yScale Y-Axis scale of the button. + */ + public ButtonOverlay(String id, ImageLoader imageLoader, String text, double x, double y, double xScale, double yScale) { + this.id = id; + try { + this.image = imageLoader.build(); + } catch (ImageNotFoundException e) { + throw new RuntimeException(e); + } + this.text = text; + this.x = x; + this.y = y; + this.xScale = xScale; + this.yScale = yScale; + this.button = build(); + } + public ButtonOverlay(Button button) { this.button = button; + this.id = button.getId(); + this.xScale = button.getScaleX(); + this.yScale = button.getScaleY(); + } + + public String getId() { + return id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + + public Image getImage() { + return image; } - public ButtonOverlay(ButtonBuilder builder) { - this.button = builder.build(); + public void setImage(Image image) { + this.image = image; + } + + public Color getTextFill() { + return textFill; + } + + public void setTextFill(Color color) { + this.textFill = color; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + public Color getHoverColor() { + return hoverColor; + } + + public void setHoverColor(Color hoverColor) { + this.hoverColor = hoverColor; + } + + public boolean isHover() { + return hover; + } + + public void setHover(boolean hover) { + this.hover = hover; + } + + public int getBorderWidth() { + return borderWidth; + } + + public void setBorderWidth(int borderWidth) { + this.borderWidth = borderWidth; + } + + public int getBackgroundRadius() { + return backgroundRadius; + } + + public void setBackgroundRadius(int backgroundRadius) { + this.backgroundRadius = backgroundRadius; } @Override public double x() { - return button.getTranslateX(); + return x; + } + + public void setX(double x) { + this.x = x; } @Override public double y() { - return button.getTranslateY(); + return y; + } + + public void setY(double y) { + this.y = y; } @Override @@ -35,7 +315,88 @@ public void setTransitions(Transitions transitions) { this.transitions = transitions; } + public double getXScale() { + return xScale; + } + + public double getYScale() { + return yScale; + } + public Button build() { + if (button != null) { + return button; + } + Button button = new Button(); + button.setId(id); + if (image != null) { + ImageView imageView = new ImageView(image); + button.setGraphic(imageView); + } + if (text != null && !text.isEmpty()) { + button.setText(text); + } + if (font != null) { + button.setFont(font); + } else { + // Set default font + button.setFont(RenJava.getInstance().getConfiguration().getUiFont().getFont()); + } + if (textFill != null) { + button.setTextFill(textFill); + } + String inLine = ""; + if (backgroundColor != null) { + inLine += "-fx-background-color: " + cssColor(backgroundColor) + "; "; + } + if (borderColor != null) { + inLine += "-fx-border-color: " + cssColor(borderColor) + "; "; + } + inLine += "-fx-border-width: " + borderWidth + "; "; + inLine += "-fx-background-radius: " + backgroundRadius + ";"; + + // https://stackoverflow.com/questions/30680570/javafx-button-border-and-hover + if (hover) { + AtomicReference attomicInLine = new AtomicReference<>(inLine); + button.setOnMouseEntered(mouseEvent -> { + button.setTextFill(hoverColor); + button.setStyle(attomicInLine.get()); + }); + button.setOnMouseExited(mouseEvent -> { + button.setTextFill(textFill); + button.setStyle(attomicInLine.get()); + }); + } + + button.setStyle(inLine); + + if (x != 0 && y != 0) { + button.setTranslateX(x); + button.setTranslateY(y); + } + button.setScaleX(xScale); + button.setScaleY(yScale); + + button.setOnAction(actionEvent -> { + ButtonClickEvent event = new ButtonClickEvent(RenJava.getInstance().getPlayer().getCurrentScene(), button); + RenJava.callEvent(event); + }); return button; } + + // Helper css function + public String cssColor(Color color) { + String webFormat = String.format("rgba(%d, %d, %d, %f)", + (int) (255 * color.getRed()), + (int) (255 * color.getGreen()), + (int) (255 * color.getBlue()), + color.getOpacity()); + return webFormat; + } + + public static ButtonOverlay copyOf(String id, ButtonOverlay builder) { + ButtonOverlay toReturn = new ButtonOverlay(id, builder.getText(), builder.getFont(), builder.getTextFill(), builder.x(), builder.y(), builder.getXScale(), builder.getYScale()); + toReturn.setImage(builder.getImage()); + return toReturn; + } } diff --git a/src/main/java/me/piitex/renjava/gui/overlay/ImageOverlay.java b/src/main/java/me/piitex/renjava/gui/overlay/ImageOverlay.java index 6fc093d..4e8584b 100644 --- a/src/main/java/me/piitex/renjava/gui/overlay/ImageOverlay.java +++ b/src/main/java/me/piitex/renjava/gui/overlay/ImageOverlay.java @@ -10,6 +10,7 @@ public class ImageOverlay implements Overlay { private final Image image; private double x; private double y; + private final String fileName; private Transitions transitions; @@ -17,11 +18,13 @@ public ImageOverlay(Image image, int x, int y) { this.image = image; this.x = x; this.y = y; + this.fileName = "Unknown"; } public ImageOverlay(ImageLoader imageLoader, double x, double y) { try { this.image = imageLoader.build(); + this.fileName = imageLoader.getFile().getName(); } catch (ImageNotFoundException e) { RenJava.getInstance().getLogger().severe(e.getMessage()); throw new RuntimeException(); @@ -34,6 +37,10 @@ public Image getImage() { return image; } + public String getFileName() { + return fileName; + } + @Override public double x() { return x; diff --git a/src/main/java/me/piitex/renjava/gui/overlay/InputFieldOverlay.java b/src/main/java/me/piitex/renjava/gui/overlay/InputFieldOverlay.java index 0aca54e..cb3cd41 100644 --- a/src/main/java/me/piitex/renjava/gui/overlay/InputFieldOverlay.java +++ b/src/main/java/me/piitex/renjava/gui/overlay/InputFieldOverlay.java @@ -1,28 +1,29 @@ package me.piitex.renjava.gui.overlay; -import me.piitex.renjava.api.builders.InputFieldBuilder; +import javafx.scene.control.TextField; +import me.piitex.renjava.api.builders.FontLoader; import me.piitex.renjava.api.scenes.transitions.Transitions; public class InputFieldOverlay implements Overlay { - private final InputFieldBuilder inputFieldBuilder; + private final double x; + private final double y; + private final FontLoader fontLoader; private Transitions transitions; - public InputFieldOverlay(InputFieldBuilder inputFieldBuilder) { - this.inputFieldBuilder = inputFieldBuilder; - } - - public InputFieldBuilder getInputFieldBuilder() { - return inputFieldBuilder; + public InputFieldOverlay(double x, double y, FontLoader fontLoader) { + this.x = x; + this.y = y; + this.fontLoader = fontLoader; } @Override public double x() { - return inputFieldBuilder.getX(); + return x; } @Override public double y() { - return inputFieldBuilder.getY(); + return y; } @Override @@ -33,4 +34,17 @@ public Transitions getTransition() { public void setTransitions(Transitions transitions) { this.transitions = transitions; } + + public FontLoader getFontLoader() { + return fontLoader; + } + + public TextField build() { + TextField textField = new TextField(); + textField.setTranslateX(x); + textField.setTranslateY(y); + textField.setStyle(""); + textField.setStyle("-fx-control-inner-background: transparent; -fx-background-color transparent;"); + return textField; + } } diff --git a/src/main/java/me/piitex/renjava/gui/overlay/TextFlowOverlay.java b/src/main/java/me/piitex/renjava/gui/overlay/TextFlowOverlay.java index 2f7568f..9ce93eb 100644 --- a/src/main/java/me/piitex/renjava/gui/overlay/TextFlowOverlay.java +++ b/src/main/java/me/piitex/renjava/gui/overlay/TextFlowOverlay.java @@ -1,22 +1,41 @@ package me.piitex.renjava.gui.overlay; -import me.piitex.renjava.api.builders.TextFlowBuilder; +import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javafx.scene.text.TextFlow; import me.piitex.renjava.api.scenes.transitions.Transitions; +import java.util.LinkedList; + public class TextFlowOverlay implements Overlay { - private final TextFlowBuilder textFlowBuilder; private double x; private double y; private Transitions transitions; + private Font font; + private Color textColor; - public TextFlowOverlay(TextFlowBuilder textFlowBuilder, double x, double y) { - this.textFlowBuilder = textFlowBuilder; - this.x = x; - this.y = y; + private LinkedList texts = new LinkedList<>(); + + private final int width, height; + + public TextFlowOverlay(String text, int width, int height) { + this.width = width; + this.height = height; + texts.add(new Text(text)); + } + + public TextFlowOverlay(Text text, int width, int height) { + this.width = width; + this.height = height; + texts.add(text); } - public TextFlowBuilder getTextFlowBuilder() { - return textFlowBuilder; + public TextFlowOverlay(LinkedList texts, int width, int height) { + this.width = width; + this.height = height; + this.texts = texts; } @Override @@ -24,11 +43,35 @@ public double x() { return x; } + public void setX(double x) { + this.x = x; + } + @Override public double y() { return y; } + public void setY(double y) { + this.y = y; + } + + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + + public Color getTextColor() { + return textColor; + } + + public void setTextColor(Color textColor) { + this.textColor = textColor; + } + @Override public Transitions getTransition() { return transitions; @@ -37,4 +80,31 @@ public Transitions getTransition() { public void setTransitions(Transitions transitions) { this.transitions = transitions; } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public LinkedList getTexts() { + return texts; + } + + public TextFlow build() { + TextFlow textFlow = new TextFlow(); + for (Text text : texts) { + if (font != null) { + text.setFont(font); + } + text.setFill(textColor); + textFlow.getChildren().add(text); + } + + textFlow.setPrefSize(width, height); + + return textFlow; + } } diff --git a/src/main/java/me/piitex/renjava/gui/overlay/TextOverlay.java b/src/main/java/me/piitex/renjava/gui/overlay/TextOverlay.java index 81b91ce..17f7959 100644 --- a/src/main/java/me/piitex/renjava/gui/overlay/TextOverlay.java +++ b/src/main/java/me/piitex/renjava/gui/overlay/TextOverlay.java @@ -2,10 +2,12 @@ import javafx.scene.text.Text; +import me.piitex.renjava.api.builders.FontLoader; import me.piitex.renjava.api.scenes.transitions.Transitions; public class TextOverlay implements Overlay { private final Text text; + private FontLoader fontLoader; private double x; private double y; private Transitions transitions; @@ -16,6 +18,13 @@ public TextOverlay(Text text, double x, double y) { this.y = y; } + public TextOverlay(Text text, FontLoader fontLoader, double x, double y) { + this.text = text; + this.fontLoader = fontLoader; + this.x = x; + this.y = y; + } + public Text getText() { return text; } @@ -30,6 +39,10 @@ public double y() { return y; } + public FontLoader getFontLoader() { + return fontLoader; + } + @Override public Transitions getTransition() { return transitions; diff --git a/src/main/resources/game/css/button.css b/src/main/resources/game/css/button.css deleted file mode 100644 index 936ba13..0000000 --- a/src/main/resources/game/css/button.css +++ /dev/null @@ -1,10 +0,0 @@ -.button{ - -fx-border-color: transparent; - -fx-border-width: 0; - -fx-background-radius: 0; - -fx-background-color: transparent; - -fx-text-fill: black -} - .button:hover { - -fx-text-fill: blue -}