diff --git a/pom.xml b/pom.xml
index db06adb..c574289 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
me.piitexRenJava
- 0.0.757-SNAPSHOT
+ 0.0.802-SNAPSHOTRenJava
@@ -102,12 +102,6 @@
9.0.4compile
-
- 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