From 0ce09f72f4af26412356b9699d402b52dbcfc94f Mon Sep 17 00:00:00 2001 From: sowgro Date: Sun, 28 Jul 2024 01:07:41 -0400 Subject: Finalize level API and new Json library --- README.md | 1 + flowChart.jpeg | Bin 265753 -> 0 bytes pom.xml | 18 ++- src/main/java/module-info.java | 2 +- src/main/java/net/sowgro/npehero/Driver.java | 23 +++- .../java/net/sowgro/npehero/editor/DiffEditor.java | 26 +++- .../java/net/sowgro/npehero/editor/DiffList.java | 29 +++- .../net/sowgro/npehero/editor/ErrorDisplay.java | 5 +- .../net/sowgro/npehero/editor/LevelEditor.java | 54 +++++--- .../java/net/sowgro/npehero/editor/LevelList.java | 13 +- .../net/sowgro/npehero/editor/NotesEditor.java | 12 +- .../net/sowgro/npehero/editor/NotesEditor2.java | 11 +- .../java/net/sowgro/npehero/gameplay/Block.java | 2 +- .../net/sowgro/npehero/gameplay/SongPlayer.java | 3 +- .../java/net/sowgro/npehero/gui/ControlEditor.java | 1 + src/main/java/net/sowgro/npehero/gui/GameOver.java | 14 +- .../net/sowgro/npehero/gui/LeaderboardView.java | 8 +- .../java/net/sowgro/npehero/gui/LevelDetails.java | 4 +- .../java/net/sowgro/npehero/gui/LevelSelector.java | 4 +- .../java/net/sowgro/npehero/gui/LevelSurround.java | 6 +- src/main/java/net/sowgro/npehero/gui/MainMenu.java | 5 +- .../net/sowgro/npehero/gui/SettingsEditor.java | 3 +- .../net/sowgro/npehero/levelapi/Difficulties.java | 127 +++++++++++++++++ .../net/sowgro/npehero/levelapi/Difficulty.java | 95 +++++++++++++ .../net/sowgro/npehero/levelapi/Leaderboard.java | 81 +++++++++++ .../sowgro/npehero/levelapi/LeaderboardEntry.java | 24 ++++ .../java/net/sowgro/npehero/levelapi/Level.java | 152 +++++++++++++++++++++ .../java/net/sowgro/npehero/levelapi/Levels.java | 97 +++++++++++++ .../java/net/sowgro/npehero/levelapi/Note.java | 34 +++++ .../java/net/sowgro/npehero/levelapi/Notes.java | 107 +++++++++++++++ src/main/java/net/sowgro/npehero/main/Control.java | 19 ++- .../java/net/sowgro/npehero/main/Difficulties.java | 86 ------------ .../java/net/sowgro/npehero/main/Difficulty.java | 87 ------------ .../java/net/sowgro/npehero/main/JSONFile.java | 108 --------------- .../java/net/sowgro/npehero/main/Leaderboard.java | 94 ------------- .../net/sowgro/npehero/main/LeaderboardEntry.java | 28 ---- src/main/java/net/sowgro/npehero/main/Level.java | 137 ------------------- src/main/java/net/sowgro/npehero/main/Levels.java | 88 ------------ src/main/java/net/sowgro/npehero/main/Note.java | 28 ---- src/main/java/net/sowgro/npehero/main/Notes.java | 100 -------------- .../java/net/sowgro/npehero/main/Settings.java | 28 ++-- 41 files changed, 921 insertions(+), 843 deletions(-) delete mode 100755 flowChart.jpeg create mode 100644 src/main/java/net/sowgro/npehero/levelapi/Difficulties.java create mode 100755 src/main/java/net/sowgro/npehero/levelapi/Difficulty.java create mode 100644 src/main/java/net/sowgro/npehero/levelapi/Leaderboard.java create mode 100755 src/main/java/net/sowgro/npehero/levelapi/LeaderboardEntry.java create mode 100755 src/main/java/net/sowgro/npehero/levelapi/Level.java create mode 100755 src/main/java/net/sowgro/npehero/levelapi/Levels.java create mode 100644 src/main/java/net/sowgro/npehero/levelapi/Note.java create mode 100644 src/main/java/net/sowgro/npehero/levelapi/Notes.java delete mode 100644 src/main/java/net/sowgro/npehero/main/Difficulties.java delete mode 100755 src/main/java/net/sowgro/npehero/main/Difficulty.java delete mode 100644 src/main/java/net/sowgro/npehero/main/JSONFile.java delete mode 100644 src/main/java/net/sowgro/npehero/main/Leaderboard.java delete mode 100755 src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java delete mode 100755 src/main/java/net/sowgro/npehero/main/Level.java delete mode 100755 src/main/java/net/sowgro/npehero/main/Levels.java delete mode 100644 src/main/java/net/sowgro/npehero/main/Note.java delete mode 100644 src/main/java/net/sowgro/npehero/main/Notes.java diff --git a/README.md b/README.md index 5b83c3e..250700b 100755 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Goals: Todo: - [ ] Make validation update on view - [ ] Click sounds on all buttons in editor +- [ ] Display problems on diffList and levelList # Installation Coming soon. diff --git a/flowChart.jpeg b/flowChart.jpeg deleted file mode 100755 index cd81a59..0000000 Binary files a/flowChart.jpeg and /dev/null differ diff --git a/pom.xml b/pom.xml index 3637f51..cfb8404 100644 --- a/pom.xml +++ b/pom.xml @@ -15,16 +15,18 @@ + + com.google.code.gson + gson + 2.11.0 + + org.openjfx javafx-media 22.0.2 - - com.fasterxml.jackson.core - jackson-databind - 2.17.2 - + org.openjfx javafx-controls @@ -48,6 +50,12 @@ ${junit.version} test + + org.jetbrains + annotations + 24.0.1 + compile + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 09cc9e7..02dcac8 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -3,7 +3,7 @@ module net.sowgro.npehero { requires javafx.fxml; requires javafx.media; requires java.desktop; - requires com.fasterxml.jackson.databind; + requires com.google.gson; exports net.sowgro.npehero; } \ No newline at end of file diff --git a/src/main/java/net/sowgro/npehero/Driver.java b/src/main/java/net/sowgro/npehero/Driver.java index 3e1bd6e..2845cf4 100755 --- a/src/main/java/net/sowgro/npehero/Driver.java +++ b/src/main/java/net/sowgro/npehero/Driver.java @@ -13,12 +13,12 @@ import javafx.scene.layout.*; import javafx.stage.Stage; import javafx.util.Duration; import net.sowgro.npehero.editor.ErrorDisplay; +import net.sowgro.npehero.levelapi.Levels; import net.sowgro.npehero.main.*; import net.sowgro.npehero.gui.MainMenu; -import java.io.FileNotFoundException; +import java.io.IOException; import java.net.URL; -import java.util.List; import java.util.Stack; @@ -81,21 +81,30 @@ public class Driver extends Application primaryStage.show(); Stack errors = new Stack<>(); + System.out.println("Loading settings..."); try { Settings.read(); + System.out.println("Settings loaded"); } catch (Exception e) { + e.printStackTrace(); errors.push("Failed to load settings from file\n"+e); } - try { - Levels.readData(); - } catch (FileNotFoundException e) { - errors.push("Failed to load levels: Level folder is missing\n"); - } + System.out.println("Loading controls..."); try { Control.readFromFile(); + System.out.println("Controls loaded"); } catch (Exception e) { + e.printStackTrace(); errors.push("Failed to load controls from file\n"+e); } + System.out.println("Loading levels..."); + try { + Levels.readData(); + System.out.println("Loaded " + Levels.list.size() + " levels (" + Levels.getValidList().size() + " valid)"); + } catch (IOException e) { + e.printStackTrace(); + errors.push("Failed to load levels\n"); + } Page last = new MainMenu(); while (!errors.empty()) { last = new ErrorDisplay(errors.pop(), last); diff --git a/src/main/java/net/sowgro/npehero/editor/DiffEditor.java b/src/main/java/net/sowgro/npehero/editor/DiffEditor.java index 6940485..0eb4968 100755 --- a/src/main/java/net/sowgro/npehero/editor/DiffEditor.java +++ b/src/main/java/net/sowgro/npehero/editor/DiffEditor.java @@ -11,8 +11,12 @@ import net.sowgro.npehero.gameplay.Block; import net.sowgro.npehero.gui.LevelSurround; import javafx.scene.layout.VBox; import javafx.scene.text.Text; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Note; import net.sowgro.npehero.main.*; +import java.io.IOException; + public class DiffEditor extends Page { Difficulty diff; @@ -37,13 +41,15 @@ public class DiffEditor extends Page editNotes.setOnAction(_ -> { if (diff.level.song == null) { Driver.setMenu(new ErrorDisplay("You must import a song file before editing the notes!", this)); + return; } if (diff.bpm != 0.0) { Driver.setMenu(new ErrorDisplay( - "Note:\nThe new notes editor does not support bpm and beat based songs. If you continue the beats will be converted to seconds.", + "Note:\nThe new notes editor does not support bpm and beat based songs. If you continue, the notes will be converted.", this, new NotesEditor2(diff, this) )); + return; } Driver.setMenu(new NotesEditor2(diff, this)); }); @@ -57,7 +63,15 @@ public class DiffEditor extends Page Label scoresLable = new Label("Scores"); Button editScores = new Button("Clear leaderboard"); - editScores.setOnAction(_ -> diff.leaderboard.entries.clear()); + editScores.setOnAction(_ -> { + diff.leaderboard.entries.clear(); + try { + diff.leaderboard.save(); + } catch (IOException e) { + e.printStackTrace(); + Driver.setMenu(new ErrorDisplay("Failed to clear the leaderboard:\n"+e, this)); + } + }); Button playLevel = new Button("Play level"); playLevel.setOnAction(_ -> { @@ -74,7 +88,13 @@ public class DiffEditor extends Page diff.title = title.getText(); // diff.bpm = Double.parseDouble(bpm.getText()); // diff.numBeats = Integer.parseInt(numBeats.getText()); - diff.write(); + try { + diff.writeMetadata(); + } catch (IOException e) { + e.printStackTrace(); + //TODO + throw new RuntimeException(e); + } }); HBox scrollContent = new HBox(); diff --git a/src/main/java/net/sowgro/npehero/editor/DiffList.java b/src/main/java/net/sowgro/npehero/editor/DiffList.java index 7017c32..9e2df9b 100755 --- a/src/main/java/net/sowgro/npehero/editor/DiffList.java +++ b/src/main/java/net/sowgro/npehero/editor/DiffList.java @@ -9,12 +9,13 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import net.sowgro.npehero.Driver; -import net.sowgro.npehero.main.Difficulty; -import net.sowgro.npehero.main.Level; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; import java.util.Collections; public class DiffList extends Page @@ -68,6 +69,7 @@ public class DiffList extends Page try { level.difficulties.remove(diffs.getSelectionModel().getSelectedItem()); } catch (IOException ex) { + ex.printStackTrace(); Driver.setMenu(new ErrorDisplay("Failed to remove difficulty\n"+e, this)); } }); @@ -76,7 +78,11 @@ public class DiffList extends Page Button refresh = new Button("Refresh"); refresh.setOnAction(e -> { -// level.readData(); + try { + level.difficulties.read(); + } catch (IOException ex) { + // TODO + } // diffs.setItems(level.difficulties.list.sorted()); diffs.refresh(); }); @@ -93,7 +99,12 @@ public class DiffList extends Page return; } Collections.swap(diffList, oldIndex, oldIndex-1); - level.difficulties.saveOrder(); + try { + level.difficulties.saveOrder(); + } catch (IOException e) { + e.printStackTrace(); + Driver.setMenu(new ErrorDisplay("Failed to move difficulty\n"+e,this)); + } }); Button moveDown = new Button("Move Down"); @@ -106,7 +117,12 @@ public class DiffList extends Page return; } Collections.swap(diffList, oldIndex, oldIndex+1); - level.difficulties.saveOrder(); + try { + level.difficulties.saveOrder(); + } catch (IOException e) { + e.printStackTrace(); + Driver.setMenu(new ErrorDisplay("Failed to move difficulty\n"+e,this)); + } }); VBox buttons = new VBox(); @@ -148,8 +164,11 @@ public class DiffList extends Page newLevelButton.setOnAction(_ -> { try { level.difficulties.add(newLevelEntry.getText()); + } catch (FileAlreadyExistsException e) { + Driver.setMenu(new ErrorDisplay("Failed to add level\nA difficulty already exists with the folder name " + e.getFile(), this)); } catch (IOException e) { Driver.setMenu(new ErrorDisplay("Failed to add level\n"+e, this)); + e.printStackTrace(); } newLevelEntry.clear(); refresh.fire(); diff --git a/src/main/java/net/sowgro/npehero/editor/ErrorDisplay.java b/src/main/java/net/sowgro/npehero/editor/ErrorDisplay.java index b3ec751..c07d12f 100644 --- a/src/main/java/net/sowgro/npehero/editor/ErrorDisplay.java +++ b/src/main/java/net/sowgro/npehero/editor/ErrorDisplay.java @@ -23,9 +23,11 @@ public class ErrorDisplay extends Page { public ErrorDisplay(String message, Page prev) { Label main = new Label(message); main.getStyleClass().add("box"); + main.setPadding(new Insets(10)); + main.setWrapText(true); Button exit = new Button(); - exit.setText("Back"); + exit.setText("Ok"); exit.setOnAction(e -> { Sound.playSfx(Sound.BACKWARD); Driver.setMenu(prev); @@ -50,6 +52,7 @@ public class ErrorDisplay extends Page { Label main = new Label(message); main.getStyleClass().add("box"); main.setPadding(new Insets(10)); + main.setWrapText(true); Button exit = new Button(); exit.setText("Cancel"); diff --git a/src/main/java/net/sowgro/npehero/editor/LevelEditor.java b/src/main/java/net/sowgro/npehero/editor/LevelEditor.java index b3ae2b8..ae56d44 100755 --- a/src/main/java/net/sowgro/npehero/editor/LevelEditor.java +++ b/src/main/java/net/sowgro/npehero/editor/LevelEditor.java @@ -1,6 +1,7 @@ package net.sowgro.npehero.editor; import java.io.File; +import java.io.IOException; import javafx.beans.property.ReadOnlyStringWrapper; import javafx.geometry.Pos; @@ -10,10 +11,16 @@ import javafx.scene.text.Text; import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; import net.sowgro.npehero.Driver; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.main.*; public class LevelEditor extends Page { + private final ValidIndicator songValid = new ValidIndicator(); + private final ValidIndicator diffsInvalid = new ValidIndicator(); + Level level; + private HBox content = new HBox(); private File selectedSong = null; @@ -22,6 +29,7 @@ public class LevelEditor extends Page public LevelEditor(Level level, Page prev) { + this.level = level; Text folderNameLabel = new Text("Folder name"); TextField folderName = new TextField(); if (level.dir != null) { @@ -55,10 +63,6 @@ public class LevelEditor extends Page HBox colorPickerBox = new HBox(); colorPickerBox.getChildren().addAll(colorsPickers); - ValidIndicator songValid = new ValidIndicator(); - if (level.song == null) { - songValid.setInvalid("Missing song file!"); - } HBox filesLabel = new HBox(new Text("Files"), songValid); FileChooser backgroundChooser = new FileChooser(); @@ -77,10 +81,6 @@ public class LevelEditor extends Page songButton.setOnAction(_ -> selectedSong = songChooser.showOpenDialog(Driver.primaryStage)); - ValidIndicator diffsInvalid = new ValidIndicator(); - if (level.difficulties.getValidList().isEmpty()) { - diffsInvalid.setInvalid("This level contains no valid difficulties!"); - } HBox diffLabel = new HBox(new Text("Difficulties"), diffsInvalid); diffLabel.setSpacing(5); @@ -134,18 +134,25 @@ public class LevelEditor extends Page try { if (selectedBackground != null && selectedBackground.exists()) { - level.addFile(selectedBackground, "background." + getFileExtension(selectedBackground)); + level.addFile(selectedBackground, "background"); } if (selectedPreview != null && selectedPreview.exists()) { - level.addFile(selectedPreview, "preview." + getFileExtension(selectedPreview)); + level.addFile(selectedPreview, "preview"); } if (selectedSong != null) { - level.addFile(selectedSong, "song." + getFileExtension(selectedSong)); + level.addFile(selectedSong, "song"); } - } catch (Exception _) { + } catch (Exception ex) { + // TODO + ex.printStackTrace(); + } + try { + level.writeMetadata(); + } catch (IOException ex) { // TODO + ex.printStackTrace(); } - level.writeMetadata(); + validate(); }); VBox left = new VBox(filesLabel, songButton, previewButton, backgroundButton, colorsLabel, colorPickerBox); @@ -189,12 +196,19 @@ public class LevelEditor extends Page return content; } - /** - * Get the extension of a file. - * @param file The file to return the extension of - * @return The extension of the file in the format "*.ext" - */ - public String getFileExtension(File file) { - return file.getName().substring(file.getName().lastIndexOf('.') + 1); + @Override + public void onView() { + validate(); + } + + public void validate() { + if (level.difficulties.getValidList().isEmpty()) { + diffsInvalid.setInvalid("This level contains no valid difficulties!"); + } else { + diffsInvalid.setValid(); + } + if (level.song == null) { + songValid.setInvalid("Missing song file!"); + } } } \ No newline at end of file diff --git a/src/main/java/net/sowgro/npehero/editor/LevelList.java b/src/main/java/net/sowgro/npehero/editor/LevelList.java index 1bc85dd..86c65b5 100755 --- a/src/main/java/net/sowgro/npehero/editor/LevelList.java +++ b/src/main/java/net/sowgro/npehero/editor/LevelList.java @@ -9,13 +9,14 @@ import net.sowgro.npehero.Driver; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import net.sowgro.npehero.gui.MainMenu; -import net.sowgro.npehero.main.Level; -import net.sowgro.npehero.main.Levels; +import net.sowgro.npehero.levelapi.Level; +import net.sowgro.npehero.levelapi.Levels; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; public class LevelList extends Page { @@ -71,6 +72,7 @@ public class LevelList extends Page Levels.remove(levels.getSelectionModel().getSelectedItem()); } catch (IOException ex) { Driver.setMenu(new ErrorDisplay("Failed to remove this level\n"+e.toString(), this)); + ex.printStackTrace(); } }); remove.setDisable(true); @@ -80,8 +82,9 @@ public class LevelList extends Page refresh.setOnAction(e -> { try { Levels.readData(); - } catch (FileNotFoundException ex) { + } catch (IOException ex) { Driver.setMenu(new ErrorDisplay("Failed to load levels: Level folder is missing\n"+e.toString(), this)); + ex.printStackTrace(); } levels.setItems(Levels.list); }); @@ -135,8 +138,12 @@ public class LevelList extends Page newLevelButton.setOnAction(_ -> { try { Levels.add(newLevelEntry.getText()); + } catch (FileAlreadyExistsException e) { + Driver.setMenu(new ErrorDisplay("Failed to add level\nA level already exists with the folder name " + e.getFile(), this)); + e.printStackTrace(); } catch (IOException e) { Driver.setMenu(new ErrorDisplay("Failed to create this level\n"+e.toString(), this)); + e.printStackTrace(); } newLevelEntry.clear(); refresh.fire(); diff --git a/src/main/java/net/sowgro/npehero/editor/NotesEditor.java b/src/main/java/net/sowgro/npehero/editor/NotesEditor.java index 133330f..da5af33 100755 --- a/src/main/java/net/sowgro/npehero/editor/NotesEditor.java +++ b/src/main/java/net/sowgro/npehero/editor/NotesEditor.java @@ -16,7 +16,7 @@ import javafx.scene.control.Button; import javafx.scene.layout.VBox; import javafx.scene.text.Text; import net.sowgro.npehero.main.Control; -import net.sowgro.npehero.main.Difficulty; +import net.sowgro.npehero.levelapi.Difficulty; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; @@ -64,11 +64,11 @@ public class NotesEditor extends Page content.getChildren().add(centerBox); content.setAlignment(Pos.CENTER); - try { - writer = new PrintWriter(diff.notes.getFile(), "UTF-8"); - } catch (FileNotFoundException | UnsupportedEncodingException e) { - throw new RuntimeException(e); - } +// try { +// writer = new PrintWriter(diff.notes.getFile(), "UTF-8"); +// } catch (FileNotFoundException | UnsupportedEncodingException e) { +// throw new RuntimeException(e); +// } Scene scene = Driver.primaryStage.getScene(); scene.addEventFilter(KeyEvent.KEY_PRESSED, e -> { diff --git a/src/main/java/net/sowgro/npehero/editor/NotesEditor2.java b/src/main/java/net/sowgro/npehero/editor/NotesEditor2.java index 8d17900..b6810d8 100644 --- a/src/main/java/net/sowgro/npehero/editor/NotesEditor2.java +++ b/src/main/java/net/sowgro/npehero/editor/NotesEditor2.java @@ -16,7 +16,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import javafx.scene.media.Media; import javafx.scene.media.MediaPlayer; import javafx.scene.paint.Color; import javafx.scene.shape.Line; @@ -25,9 +24,12 @@ import javafx.util.Duration; import net.sowgro.npehero.Driver; import net.sowgro.npehero.gameplay.Block; import net.sowgro.npehero.gameplay.Target; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Note; import net.sowgro.npehero.main.*; import net.sowgro.npehero.main.Control; +import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; public class NotesEditor2 extends Page { @@ -164,7 +166,12 @@ public class NotesEditor2 extends Page { save.setText("Save"); save.setOnAction(_ -> { diff.notes.list = noteList; - diff.notes.writeFile(); + try { + diff.notes.writeFile(); + } catch (IOException e) { + // TODO + throw new RuntimeException(e); + } diff.endTime = newEndTime.get(); Sound.playSfx(Sound.BACKWARD); Driver.setMenu(new DiffEditor(diff, prev.prev)); diff --git a/src/main/java/net/sowgro/npehero/gameplay/Block.java b/src/main/java/net/sowgro/npehero/gameplay/Block.java index c55a7bf..9d68ab6 100755 --- a/src/main/java/net/sowgro/npehero/gameplay/Block.java +++ b/src/main/java/net/sowgro/npehero/gameplay/Block.java @@ -6,7 +6,7 @@ import javafx.scene.effect.BlurType; import javafx.scene.effect.DropShadow; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; -import net.sowgro.npehero.main.Note; +import net.sowgro.npehero.levelapi.Note; /** * A block is a visual representation of a note on the screen. This is used both in the editor and in during the game play. diff --git a/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java index 36f706c..33f9a51 100755 --- a/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java +++ b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java @@ -1,6 +1,5 @@ package net.sowgro.npehero.gameplay; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -14,6 +13,8 @@ import javafx.event.EventHandler; import javafx.scene.input.KeyEvent; import javafx.scene.media.Media; import net.sowgro.npehero.Driver; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.main.*; import net.sowgro.npehero.gui.GameOver; import javafx.geometry.Pos; diff --git a/src/main/java/net/sowgro/npehero/gui/ControlEditor.java b/src/main/java/net/sowgro/npehero/gui/ControlEditor.java index 90161e0..7fd288b 100644 --- a/src/main/java/net/sowgro/npehero/gui/ControlEditor.java +++ b/src/main/java/net/sowgro/npehero/gui/ControlEditor.java @@ -76,6 +76,7 @@ public class ControlEditor extends Page { Control.writeToFile(); } catch (IOException e) { Driver.setMenu(new ErrorDisplay("An error occured while saving your controls\n"+e, this)); + e.printStackTrace(); } }); controlButton.setOnAction(_ -> { diff --git a/src/main/java/net/sowgro/npehero/gui/GameOver.java b/src/main/java/net/sowgro/npehero/gui/GameOver.java index dd23f5f..b66d0c6 100755 --- a/src/main/java/net/sowgro/npehero/gui/GameOver.java +++ b/src/main/java/net/sowgro/npehero/gui/GameOver.java @@ -10,11 +10,14 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; import net.sowgro.npehero.Driver; -import net.sowgro.npehero.main.Difficulty; -import net.sowgro.npehero.main.Level; +import net.sowgro.npehero.editor.ErrorDisplay; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; +import java.io.IOException; + public class GameOver extends Page { HBox content = new HBox(); @@ -67,7 +70,12 @@ public class GameOver extends Page Sound.playSfx(Sound.FORWARD); save.setDisable(true); name.setDisable(true); - diff.leaderboard.add(name.getText(), score2); + try { + diff.leaderboard.add(name.getText(), score2); + } catch (IOException e) { + e.printStackTrace(); + Driver.setMenu(new ErrorDisplay("Failed to save score to leaderboard:\n"+e, this)); + } }); BorderPane b = new BorderPane(); diff --git a/src/main/java/net/sowgro/npehero/gui/LeaderboardView.java b/src/main/java/net/sowgro/npehero/gui/LeaderboardView.java index 46ce22f..1a87e27 100755 --- a/src/main/java/net/sowgro/npehero/gui/LeaderboardView.java +++ b/src/main/java/net/sowgro/npehero/gui/LeaderboardView.java @@ -10,6 +10,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import net.sowgro.npehero.Driver; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.LeaderboardEntry; import net.sowgro.npehero.main.*; public class LeaderboardView extends Page @@ -29,9 +31,9 @@ public class LeaderboardView extends Page scores.getColumns().add(scoreCol); scores.getColumns().add(dateCol); - nameCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getName())); - scoreCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getScore() + "")); - dateCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getDate())); + nameCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().name)); + scoreCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().score + "")); + dateCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().date)); scores.setItems(diff.leaderboard.entries); diff --git a/src/main/java/net/sowgro/npehero/gui/LevelDetails.java b/src/main/java/net/sowgro/npehero/gui/LevelDetails.java index 4bd1e09..55c45bd 100755 --- a/src/main/java/net/sowgro/npehero/gui/LevelDetails.java +++ b/src/main/java/net/sowgro/npehero/gui/LevelDetails.java @@ -15,8 +15,8 @@ import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import javafx.scene.text.TextFlow; import net.sowgro.npehero.Driver; -import net.sowgro.npehero.main.Difficulty; -import net.sowgro.npehero.main.Level; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.main.Sound; public class LevelDetails extends VBox diff --git a/src/main/java/net/sowgro/npehero/gui/LevelSelector.java b/src/main/java/net/sowgro/npehero/gui/LevelSelector.java index 3c8f25f..b2c028b 100755 --- a/src/main/java/net/sowgro/npehero/gui/LevelSelector.java +++ b/src/main/java/net/sowgro/npehero/gui/LevelSelector.java @@ -9,8 +9,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import net.sowgro.npehero.Driver; -import net.sowgro.npehero.main.Level; -import net.sowgro.npehero.main.Levels; +import net.sowgro.npehero.levelapi.Level; +import net.sowgro.npehero.levelapi.Levels; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; diff --git a/src/main/java/net/sowgro/npehero/gui/LevelSurround.java b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java index ea1eb30..8ab722d 100755 --- a/src/main/java/net/sowgro/npehero/gui/LevelSurround.java +++ b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java @@ -11,8 +11,8 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; -import net.sowgro.npehero.main.Difficulty; -import net.sowgro.npehero.main.Level; +import net.sowgro.npehero.levelapi.Difficulty; +import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.gameplay.ScoreController; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; @@ -28,7 +28,7 @@ public class LevelSurround extends Page Button exit = new Button(); exit.setText("Back"); - exit.setOnAction(e -> { + exit.setOnAction(_ -> { Driver.setMenu(prev); Sound.playSfx(Sound.BACKWARD); game.cancel(); diff --git a/src/main/java/net/sowgro/npehero/gui/MainMenu.java b/src/main/java/net/sowgro/npehero/gui/MainMenu.java index 3b8c8db..6160245 100755 --- a/src/main/java/net/sowgro/npehero/gui/MainMenu.java +++ b/src/main/java/net/sowgro/npehero/gui/MainMenu.java @@ -1,5 +1,6 @@ package net.sowgro.npehero.gui; +import javafx.application.Platform; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.effect.BlurType; @@ -55,8 +56,8 @@ public class MainMenu extends Page { exit.setOnAction(_ -> { Sound.playSfx(Sound.BACKWARD); // Driver.quit(); -// Platform.exit(); - System.exit(0); + Platform.exit(); +// System.exit(0); }); VBox buttonBox = new VBox(); diff --git a/src/main/java/net/sowgro/npehero/gui/SettingsEditor.java b/src/main/java/net/sowgro/npehero/gui/SettingsEditor.java index 12555ed..efd136a 100755 --- a/src/main/java/net/sowgro/npehero/gui/SettingsEditor.java +++ b/src/main/java/net/sowgro/npehero/gui/SettingsEditor.java @@ -95,7 +95,8 @@ public class SettingsEditor extends Page try { Settings.save(); } catch (IOException ex) { - Driver.setMenu(new ErrorDisplay("Failed to save settings"+e, this)); + ex.printStackTrace(); + Driver.setMenu(new ErrorDisplay("Failed to save settings"+ex, this)); } Sound.playSfx(Sound.BACKWARD); Driver.setMenu(new MainMenu()); diff --git a/src/main/java/net/sowgro/npehero/levelapi/Difficulties.java b/src/main/java/net/sowgro/npehero/levelapi/Difficulties.java new file mode 100644 index 0000000..cffd95e --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Difficulties.java @@ -0,0 +1,127 @@ +package net.sowgro.npehero.levelapi; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +/** + * Responsible for the list of difficulties in a level + */ +public class Difficulties { + + public final ObservableList list = FXCollections.observableArrayList(); + public final HashMap problems = new HashMap<>(); + + private final Level level; + + /** + * Creates a new Difficulties object + * @param level the file path of the level + * @throws IOException If there is a problem reading in the difficulties + */ + public Difficulties(Level level) throws IOException { + this.level = level; + read(); + } + + /** + * Loads difficulties + *

+ * Creates difficulty objects out of each subfolder in the level and adds it to the list. + * @throws IOException If there is a problem reading in the difficulties + */ + public void read() throws IOException { + list.clear(); + File[] fileList = level.dir.listFiles(); + if (fileList == null) { + throw new FileNotFoundException(); + } + for(File cur: fileList) { + if (cur.isDirectory()) { + try { + Difficulty diff = new Difficulty(cur, level); + list.add(diff); + } catch (IOException e) { + problems.put("", e); + e.printStackTrace(); + } + } + } + list.sort(Comparator.naturalOrder()); + } + + /** + * Removes a difficulty + *

+ * Recursively deletes the folder and removes it from the list + * @param diff: The difficulty to remove. + * @throws IOException If there is a problem removing the difficulty. + */ + public void remove(Difficulty diff) throws IOException { + File hold = diff.thisDir; + Files.walk(hold.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + list.remove(diff); + } + + /** + * Adds a difficulty + *

+ * Creates the directory and required files + * @param text The name of the directory + * @throws IOException If there is a problem adding the level + */ + public void add(String text) throws IOException { + File diffDir = new File(level.dir, text.toLowerCase().replaceAll("\\W+", "-")); + if (diffDir.exists()) { + throw new FileAlreadyExistsException(diffDir.getName()); + } + if (diffDir.mkdirs()) { + Difficulty temp = new Difficulty(diffDir, level); + temp.title = text; + list.add(temp); + list.sort(Comparator.naturalOrder()); + } + else { + throw new IOException(); + } + } + + /** + * Saves the order of the difficulties in the list + *

+ * Updates the order variable of each difficulty in the list to match their index in the list + * @throws IOException If there is a problem saving the difficulty's metadata file + */ + public void saveOrder() throws IOException { + for (Difficulty d : list) { + d.order = list.indexOf(d); + d.writeMetadata(); + } + } + + /** + * Get a list of only the valid difficulties in the level. + * @return A list of the valid difficulties. + */ + public List getValidList() { + ObservableList validList = FXCollections.observableArrayList(); + for (Difficulty difficulty : list) { + if (difficulty.isValid()) { + validList.add(difficulty); + } + } + return validList; + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/Difficulty.java b/src/main/java/net/sowgro/npehero/levelapi/Difficulty.java new file mode 100755 index 0000000..2e99a7a --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Difficulty.java @@ -0,0 +1,95 @@ +package net.sowgro.npehero.levelapi; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.ToNumberPolicy; + +import java.io.*; +import java.util.Map; + +/** + * Represents a difficulty + * Responsible for the data in metadata.yml + */ +public class Difficulty implements Comparable +{ + public final File thisDir; + public final Level level; + + public String title = "Unnamed"; + public Double bpm = 0.0; + public double endTime = 0; + public int order = 0; + + public final Leaderboard leaderboard; + public final Notes notes; + + private final Gson jsonParser = new GsonBuilder().serializeNulls().setPrettyPrinting().setNumberToNumberStrategy(ToNumberPolicy.DOUBLE).create(); + private final File jsonFile; + + /** + * Creates a new Difficulty + * @param newDir: The file path of the Difficulty + * @throws IOException If there are any problems reading the metadata or leaderboard files + */ + public Difficulty(File newDir, Level level) throws IOException { + thisDir = newDir; + this.level = level; + jsonFile = new File(thisDir, "metadata.json"); + readMetadata(); + notes = new Notes(new File(thisDir, "notes.txt"), this); // needs metadata first + leaderboard = new Leaderboard(new File(thisDir, "leaderboard.json")); + } + + /** + * Read in the data from metadata.json + * @throws IOException If there are any problems loading the file. + */ + public void readMetadata() throws IOException { + if (!jsonFile.exists()) { + return; + } + Map data = jsonParser.fromJson(new FileReader(jsonFile), Map.class); + + title = (String) data.getOrDefault("title", title); + bpm = (Double) data.getOrDefault("bpm", bpm); + endTime = (double) data.getOrDefault("endTime", endTime); + if (endTime == 0) { + int tmp = (int) (double) data.getOrDefault("numBeats", 0.0); + if (tmp != 0) { + endTime = Notes.beatToSecond(tmp, bpm); + } + } + order = (int) (double) data.getOrDefault("priority", (double) order); + } + + /** + * Checks the validity of the difficulty + *

+ * A valid difficulty has at least one note + * @return True if the difficulty is valid + */ + public boolean isValid() { + return !notes.list.isEmpty(); + } + + /** + * Writes metadata to json file + * @throws IOException If there is a problem writing to the file + */ + public void writeMetadata() throws IOException { + jsonFile.createNewFile(); + Map data = jsonParser.fromJson(new FileReader(jsonFile), Map.class); // start with previous values + data.put("title", title); + data.put("endTime", endTime); + data.put("priority", order); + FileWriter fileWriter = new FileWriter(jsonFile); + jsonParser.toJson(data, fileWriter); + fileWriter.close(); + } + + @Override + public int compareTo(Difficulty d) { + return order - d.order; + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/Leaderboard.java b/src/main/java/net/sowgro/npehero/levelapi/Leaderboard.java new file mode 100644 index 0000000..bb1f30c --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Leaderboard.java @@ -0,0 +1,81 @@ +package net.sowgro.npehero.levelapi; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Leaderboard { + + public final ObservableList entries = FXCollections.observableArrayList(); + private final Gson json = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + private final File file; + + public Leaderboard(File file) throws IOException{ + this.file = file; + read(); + } + + /** + * Adds new leaderboardEntry to list and updates json file + * @param name: The players name + * @param score The players score + * @throws IOException If there is a problem updating the leaderboard file. + */ + public void add(String name, int score) throws IOException { + entries.add(new LeaderboardEntry(name, score, LocalDate.now().toString())); + save(); + } + + /** + * Writes leaderboard to json file + * @throws IOException If there are problems writing to the file. + */ + public void save() throws IOException { + file.createNewFile(); + List> data = json.fromJson(new FileReader(file), List.class); + for (LeaderboardEntry cur : entries) { + Map obj = new HashMap<>(); + obj.put("name", cur.name); + obj.put("score", cur.score); + obj.put("date", cur.date); + data.add(obj); + } + FileWriter fileWriter = new FileWriter(file); + json.toJson(data, fileWriter); + fileWriter.close(); + } + + /** + * Reads in json leaderboard and assigns populates list with leaderboardEntries + * @throws IOException If there are problems reading the file + */ + public void read() throws IOException { + if (!file.exists()) { + return; + } + List> data = json.fromJson(new FileReader(file), List.class); + if (data == null) { + return; + } + for (Map cur: data) { + String name = (String) cur.getOrDefault("name", null); + int score = (int) (double) cur.getOrDefault("score", -1); + String date = (String) cur.getOrDefault("date", null); + if (name == null || score == -1 || date == null) { + System.out.println("dbg: bad entry skipped"); + continue; // discard invalid entries + } + entries.add(new LeaderboardEntry(name, score, date)); + } + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/LeaderboardEntry.java b/src/main/java/net/sowgro/npehero/levelapi/LeaderboardEntry.java new file mode 100755 index 0000000..2b98a29 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/LeaderboardEntry.java @@ -0,0 +1,24 @@ +package net.sowgro.npehero.levelapi; + +/** + * Represents one players score in the leaderboard + */ +public class LeaderboardEntry +{ + public final int score; + public final String name; + public final String date; + + /** + * Create a new LeaderboardEntry + * @param name The name the player input after completing the level + * @param score The score the player earned + * @param date The date the player earned this score + */ + public LeaderboardEntry(String name, int score, String date) + { + this.name = name; + this.score = score; + this.date = date; + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/Level.java b/src/main/java/net/sowgro/npehero/levelapi/Level.java new file mode 100755 index 0000000..218779f --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Level.java @@ -0,0 +1,152 @@ +package net.sowgro.npehero.levelapi; + +import java.io.*; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import javafx.scene.image.Image; +import javafx.scene.media.Media; +import javafx.scene.paint.Color; + +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Map; + +public class Level implements Comparable{ + + public final File dir; + + public String title = "Unnamed"; + public String artist = "Unknown"; + public String desc; + public Color[] colors = {Color.RED,Color.BLUE,Color.GREEN,Color.PURPLE,Color.YELLOW}; + public Image preview; + public Image background; + public Media song; + + public Difficulties difficulties; + + private final File jsonFile; + private final Gson jsonParser = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + + /** + * Creates a new level + * @param newDir The path of the Level + * @throws IOException If there is a problem reading the metadata file or loading the difficulties + */ + public Level(File newDir) throws IOException + { + dir = newDir; + jsonFile = new File(dir, "metadata.json"); + readFiles(); + readMetadata(); + difficulties = new Difficulties(this); + } + + /** + * Check for a song file, background file and preview image file + */ + public void readFiles() { + + File[] fileList = dir.listFiles(); + if (fileList == null) { + return; + } + for (File file : fileList) { + String fileName = file.getName(); + if (fileName.contains("song")) { + song = new Media(file.toURI().toString()); + } + else if (fileName.contains("background")) { + background = new Image(file.toURI().toString()); + } + else if (fileName.contains("preview")) { + preview = new Image(file.toURI().toString()); + } + } + + } + + /** + * Read in metadata file + * @throws IOException If there is a problem reading the file + */ + public void readMetadata() throws IOException { + if (!jsonFile.exists()) { + return; + } + Map data = jsonParser.fromJson(new FileReader(jsonFile), Map.class); + title = (String) data.getOrDefault("title", title); + artist = (String) data.getOrDefault("artist", artist); + desc = (String) data.getOrDefault("desc", desc); + colors[0] = Color.web((String) data.getOrDefault("color1", colors[0].toString())); + colors[1] = Color.web((String) data.getOrDefault("color2", colors[1].toString())); + colors[2] = Color.web((String) data.getOrDefault("color3", colors[2].toString())); + colors[3] = Color.web((String) data.getOrDefault("color4", colors[3].toString())); + colors[4] = Color.web((String) data.getOrDefault("color5", colors[4].toString())); + } + + /** + * Checks if the level is valid. + *

+ * A valid level has a song file and 1 or more valid difficulties + * @return True if the level is valid + */ + public boolean isValid() { + if (song == null) { + return false; + } + + if (difficulties.getValidList().isEmpty()) { + return false; + } + return true; + } + + /** + * Writes metadata to json file + * @throws IOException If there is a problem writing to the file. + */ + public void writeMetadata() throws IOException { + jsonFile.createNewFile(); + Map data = jsonParser.fromJson(new FileReader(jsonFile), Map.class); + data.put("title", title); + data.put("artist", artist); + data.put("desc", desc); + data.put("color1",colors[0].toString()); + data.put("color2",colors[1].toString()); + data.put("color3",colors[2].toString()); + data.put("color4",colors[3].toString()); + data.put("color5",colors[4].toString()); + FileWriter fileWriter = new FileWriter(jsonFile); + jsonParser.toJson(data, fileWriter); + fileWriter.close(); + } + + + /** + * Copies a file into the level directory with the name provided. The extension will be inherited from the source file + * @param source: the file to be copied + * @param name: the new file name EXCLUDING the extension. + * @throws IOException If there is a problem adding the file + */ + public void addFile(File source, String name) throws IOException { + name = name + "." + getFileExtension(source); + Files.copy(source.toPath(), new File(dir, name).toPath(), StandardCopyOption.REPLACE_EXISTING); + readFiles(); + } + + @Override + public int compareTo(Level other) { + return title.compareTo(other.title); + } + + /** + * Get the extension of a file. + * @param file The file to return the extension of + * @return The extension of the file in the format "*.ext" + */ + public String getFileExtension(File file) { + return file.getName().substring(file.getName().lastIndexOf('.') + 1); + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/Levels.java b/src/main/java/net/sowgro/npehero/levelapi/Levels.java new file mode 100755 index 0000000..84ffe51 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Levels.java @@ -0,0 +1,97 @@ +package net.sowgro.npehero.levelapi; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.HashMap; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Stores a list of all the levels + */ +public class Levels { + + public static final ObservableList list = FXCollections.observableArrayList(); + public static final HashMap problems = new HashMap<>(); + + private static final File dir = new File("levels"); + + /** + * Reads contents of the levels folder and creates a level form each subfolder + *

+ * All subfolders in the levels folder are assumed to be levels + * @throws FileNotFoundException If the levels folder is missing. + * @throws IOException If there is a problem reading in the levels. + */ + public static void readData() throws IOException { + list.clear(); + File[] fileList = dir.listFiles(); + if (fileList == null) { + throw new FileNotFoundException(); + } + for (File file: fileList) { + try { + Level level = new Level(file); + list.add(level); + } catch (IOException e) { + problems.put("", e); + e.printStackTrace(); + } + } + list.sort(Comparator.naturalOrder()); + } + + /** + * Creates a subfolder in the levels folder for the new level then creates the level with it + * @param text: the name of the directory and default title + * @throws IOException if there was an error adding the level + */ + public static void add(String text) throws IOException { + File levelDir = new File(dir, text.toLowerCase().replaceAll("\\W+", "-")); + if (levelDir.exists()) { + throw new FileAlreadyExistsException(levelDir.getName()); + } + if (levelDir.mkdirs()) { + Level temp = new Level(levelDir); + temp.title = text; + list.add(temp); + } + else { + throw new IOException(); + } + } + + /** + * Removes level from the filesystem then reloads this levelController + * @param level: the level to be removed + * @throws IOException If there is a problem deleting the level + */ + public static void remove(Level level) throws IOException { + File hold = level.dir; + Files.walk(hold.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + list.remove(level); + } + + /** + * Gets a list of only the valid levels. + * @return A list of the valid levels. + */ + public static ObservableList getValidList() { + ObservableList validList = FXCollections.observableArrayList(); + for (Level level : list) { + if (level.isValid()) { + validList.add(level); + } + } + return validList; + } +} \ No newline at end of file diff --git a/src/main/java/net/sowgro/npehero/levelapi/Note.java b/src/main/java/net/sowgro/npehero/levelapi/Note.java new file mode 100644 index 0000000..ab93885 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Note.java @@ -0,0 +1,34 @@ +package net.sowgro.npehero.levelapi; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +/** + * A note represents a moment in the song when the player should hit a key + *

+ * The key corresponding to the lane the note is in should be pressed + */ +public class Note { + + public final DoubleProperty time = new SimpleDoubleProperty(); + public final int lane; + + /** + * Creates a new note + * @param time The time the player should hit the note. + * @param lane The lane the note belongs to. + */ + public Note(double time, int lane) { + this.time.set(time); + this.lane = lane; + } + + /** + * Copy constructor + * @param other the note to copy from + */ + public Note(Note other) { + this.lane = other.lane; + this.time.set(other.time.get()); + } +} diff --git a/src/main/java/net/sowgro/npehero/levelapi/Notes.java b/src/main/java/net/sowgro/npehero/levelapi/Notes.java new file mode 100644 index 0000000..1df0248 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/levelapi/Notes.java @@ -0,0 +1,107 @@ +package net.sowgro.npehero.levelapi; + +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.collections.FXCollections; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; + +/** + * Stores all the notes for a difficulty. + */ +public class Notes { + + private final File file; + private final Difficulty diff; + + public ListProperty list = new SimpleListProperty<>(FXCollections.observableArrayList()); + + /** + * Create a new Notes object + * @param file The notes.txt file + * @param diff The difficulty these notes belong to + * @throws IOException If there is a problem reading the notes file + */ + public Notes(File file, Difficulty diff) throws IOException { + this.file = file; + this.diff = diff; + readFile(); + } + + /** + * Read notes.txt and add the notes to the list + * @throws IOException if there is a problem reading the file. + */ + public void readFile() throws IOException { + if (!file.exists()) { + return; + } + Scanner scan = new Scanner(file); + while (scan.hasNext()) { + String input = scan.next(); + int lane = switch (input.charAt(0)) { + case 'd' -> 0; + case 'f' -> 1; + case 's' -> 2; + case 'j' -> 3; + case 'k' -> 4; + default -> -1; + }; + if (lane == -1) { + continue; + } + double time = Double.parseDouble(input.substring(1)); + + if (diff.bpm != 0.0) { + time = beatToSecond(time, diff.bpm); + } + list.add(new Note(time, lane)); + } + } + + /** + * Writes the notes to notes.txt + * @throws IOException If there is a problem writing to the file. + */ + public void writeFile() throws IOException{ + var _ = file.createNewFile(); + PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8); + for (Note note : list) { + Character lane = switch (note.lane) { + case 0 -> 'd'; + case 1 -> 'f'; + case 2 -> 's'; + case 3 -> 'j'; + case 4 -> 'k'; + default -> null; + }; + if (lane == null) { + continue; + } + writer.println(lane + "" + note.time.get()); + } + writer.close(); + } + + /** + * Converts a beat to a second using the levels bpm + * @param beat The beat to convert to seconds + * @param bpm The beats per minute to use for conversion + * @return The time in seconds the beat was at + */ + public static double beatToSecond(double beat, double bpm) { + return beat/(bpm/60); + } + + /** + * Performs a deep copy of the notes list. + * @return a new list of notes with the same notes. + */ + public ListProperty deepCopyList() { + ListProperty ret = new SimpleListProperty<>(FXCollections.observableArrayList()); + list.forEach(e -> ret.add(new Note(e))); + return ret; + } +} diff --git a/src/main/java/net/sowgro/npehero/main/Control.java b/src/main/java/net/sowgro/npehero/main/Control.java index 6e608ec..ece88ac 100644 --- a/src/main/java/net/sowgro/npehero/main/Control.java +++ b/src/main/java/net/sowgro/npehero/main/Control.java @@ -1,5 +1,7 @@ package net.sowgro.npehero.main; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.input.KeyCode; @@ -36,7 +38,8 @@ public enum Control { entry("Legacy Editor", List.of(LEGACY_PRINT, LEGACY_STOP)) ); - private static final JSONFile jsonFile = new JSONFile(new File("controls.json")); + private static final File file = new File("controls.json"); + private static final Gson json = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); Control(String label, KeyCode key) { this.label = label; @@ -80,19 +83,21 @@ public enum Control { } public static void writeToFile() throws IOException { + Map data = new HashMap<>(); for (Control control : Control.values()) { - jsonFile.set(control.toString(), control.getKey().toString()); + data.put(control.toString(), control.getKey().toString()); } - jsonFile.write(); + FileWriter fileWriter = new FileWriter(file); + json.toJson(data, fileWriter); + fileWriter.close(); } public static void readFromFile() throws Exception { - jsonFile.read(); + Map data = json.fromJson(new FileReader(file), Map.class); for (Control control : Control.values()) { - if (jsonFile.containsKey(control.toString())) { - control.setKey(KeyCode.valueOf(jsonFile.getString(control.toString(), null))); + if (data.containsKey(control.toString())) { + control.setKey(KeyCode.valueOf((String) data.getOrDefault(control.toString(), null))); } } } - } diff --git a/src/main/java/net/sowgro/npehero/main/Difficulties.java b/src/main/java/net/sowgro/npehero/main/Difficulties.java deleted file mode 100644 index 9549a5a..0000000 --- a/src/main/java/net/sowgro/npehero/main/Difficulties.java +++ /dev/null @@ -1,86 +0,0 @@ -package net.sowgro.npehero.main; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Comparator; -import java.util.List; - -public class Difficulties { - - public ObservableList list = FXCollections.observableArrayList(); - Level level; - - public Difficulties(Level level) { - this.level = level; - } - - public void read() { - list.clear(); - File[] fileList = level.dir.listFiles(); - if (fileList == null) { - return; - } - for(File cur: fileList) //iterates through all files/folders in /levels/LEVEL - { - if (cur.isDirectory()) //all subfolders within a level folder are difficulties - { - Difficulty diff = new Difficulty(cur,level); - list.add(diff); - } - } - list.sort(Comparator.naturalOrder()); - } - - /** - * Removes the difficaulty from the filesystem then reloads the level - * @param diff: the difficulty to be removed - */ - public void remove(Difficulty diff) throws IOException - { - File hold = diff.thisDir; - Files.walk(hold.toPath()) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - list.remove(diff); - } - - /** - * Adds a difficulty by creating a directory and required files - * @param text: the name of the directory and default title - */ - public void add(String text) throws IOException { - File diffDir = new File(level.dir, text); - if (diffDir.mkdirs()) { - Difficulty temp = new Difficulty(diffDir, level); - temp.title = text; - list.add(temp); - list.sort(Comparator.naturalOrder()); - } - else { - throw new IOException(); - } - } - - public void saveOrder() { - for (Difficulty d : list) { - d.order = list.indexOf(d); - d.write(); - } - } - - public List getValidList() { - ObservableList validList = FXCollections.observableArrayList(); - for (Difficulty difficulty : list) { - if (difficulty.isValid()) { - validList.add(difficulty); - } - } - return validList; - } -} diff --git a/src/main/java/net/sowgro/npehero/main/Difficulty.java b/src/main/java/net/sowgro/npehero/main/Difficulty.java deleted file mode 100755 index 0308fac..0000000 --- a/src/main/java/net/sowgro/npehero/main/Difficulty.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.sowgro.npehero.main; - -import javafx.scene.media.Media; - -import java.io.File; -import java.io.IOException; - -public class Difficulty implements Comparable -{ - public File thisDir; - public Level level; - private final JSONFile metadataYaml; - - public String title = "Unnamed"; - public Double bpm = 0.0; - public double endTime = 0; - public int order = 0; - - public Leaderboard leaderboard; - public Notes notes; - - /** - * Creates a new Difficulty and gives it a file path - * @param newDir: The file path of the Difficulty - */ - public Difficulty(File newDir, Level level) { - thisDir = newDir; - this.level = level; - metadataYaml = new JSONFile(new File(thisDir, "metadata.json")); - notes = new Notes(new File(thisDir, "notes.txt"), this); - leaderboard = new Leaderboard(new File(thisDir, "leaderboard.json")); - - readData(); - } - - public void readData() { - try { - metadataYaml.read(); - } - catch (Exception e) { - System.err.println(level.title + "/" + title + ": Failed to read metadata.json"); - } - - title = metadataYaml.getString("title", title); - bpm = metadataYaml.getDouble("bpm", bpm); - endTime = metadataYaml.getDouble("endTime", endTime); - if (endTime == 0) { - int tmp = metadataYaml.getInt("numBeats", 0); - if (tmp != 0) { - endTime = beatToSecond(tmp); - } - } - order = metadataYaml.getInt("priority", order); - - } - - public boolean isValid() { - return !notes.list.isEmpty(); - } - - /** - * Writes metadata to json file - */ - public void write() { - metadataYaml.set("title", title); - metadataYaml.set("endTime", endTime); - metadataYaml.set("priority", order); - - try { - metadataYaml.write(); - } - catch (IOException e) { - System.err.println(level.title + "/" + title + ": Failed to write metadata.json"); - } - } - - @Override - public int compareTo(Difficulty d) { - return order - d.order; - } - - private double beatToSecond(double beat) { - return beat/(bpm/60); - } - - -} diff --git a/src/main/java/net/sowgro/npehero/main/JSONFile.java b/src/main/java/net/sowgro/npehero/main/JSONFile.java deleted file mode 100644 index d06ca1f..0000000 --- a/src/main/java/net/sowgro/npehero/main/JSONFile.java +++ /dev/null @@ -1,108 +0,0 @@ -package net.sowgro.npehero.main; - - - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import java.io.*; - -/** - * An ergonomic JSON API wrapper inspired by the Bukkit YAML API - */ -public class JSONFile { - - private final File file; - ObjectMapper objectMapper = new ObjectMapper(); - ObjectNode writeNode = objectMapper.createObjectNode(); - JsonNode readNode; - - public JSONFile(File file) { - try { - file.createNewFile(); - } catch (IOException e) { - throw new RuntimeException(e); - } - this.file = file; - } - - public String getString(String key, String def) { - if (!readNode.has(key)) { - return def; - } - return readNode.get(key).asText(); - } - - public int getInt(String key, int def) { - if (!readNode.has(key)) { - return def; - } - try { - return Integer.parseInt(readNode.get(key).asText()); - } - catch (NumberFormatException e) { - return def; - } - } - - public double getDouble(String key, double def) { - if (!readNode.has(key)) { - return def; - } - try { - return Double.parseDouble(readNode.get(key).asText()); - } - catch (NumberFormatException e) { - return def; - } - } - - public boolean getBoolean(String key, boolean def) { - if (!readNode.has(key)) { - return def; - } - try { - return Boolean.parseBoolean(readNode.get(key).asText()); - } - catch (NumberFormatException e) { - return def; - } - } - - public void set(String key, String value) { - if (value == null) { - return; - } - writeNode.put(key, value); - } - - public void set(String key, int value) { - writeNode.put(key, value); - } - - public void set(String key, double value) { - writeNode.put(key, value); - } - - public void set(String key, boolean value) { - writeNode.put(key, value); - } - - public boolean containsKey(String key) { - return writeNode.has(key); - } - - public void read() throws Exception { - if (file.length() == 0) { - readNode = objectMapper.createObjectNode(); - return; - } - readNode = objectMapper.readTree(file); - } - - public void write() throws IOException { - objectMapper.writeValue(file, writeNode); - } - -} diff --git a/src/main/java/net/sowgro/npehero/main/Leaderboard.java b/src/main/java/net/sowgro/npehero/main/Leaderboard.java deleted file mode 100644 index eb4e5f5..0000000 --- a/src/main/java/net/sowgro/npehero/main/Leaderboard.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.sowgro.npehero.main; - -import com.fasterxml.jackson.databind.JsonNode; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDate; - -public class Leaderboard { - - public ObservableList entries = FXCollections.observableArrayList(); -// private final JSONFile jsonFile; - private File file; - - public Leaderboard(File file) { -// jsonFile = new JSONFile(file); - this.file = file; - } - - /** - * Adds new leaderboardEntry to list and updates json file - * @param name: The players name - * @param score The players score - */ - public void add(String name, int score) { - new LeaderboardEntry(name, score, ""+ LocalDate.now()); - } - - /** - * Writes leaderboard to json file - */ -// public void save() -// { -// FileWriter fileWriter; -// try -// { -// fileWriter = new FileWriter(file); -// //write the settings JSONObject instance to the file -// JSONArray jsonArray = new JSONArray(); -// for (LeaderboardEntry cur: entries) -// { -// JsonNode obj = new ; -// obj.put("name", cur.getName()); -// obj.put("score", cur.getScore()); -// obj.put("date",cur.getDate()); -// jsonArray.add(obj); -// } -// jsonArray.writeJSONString(fileWriter); -// fileWriter.flush(); -// -// } -// catch (IOException e) { -// e.printStackTrace(); -// } -// } -// -// /** -// * Reads in json leaderboard and assigns populates list with leaderboardEntries -// */ -// public boolean parseLeaderboard() -// { -// boolean isValid = true; -// JSONParser jsonParser = new JSONParser(); //parser to read the file -// -// try(FileReader reader = new FileReader(file)) -// { -// Object obj = jsonParser.parse(reader); -// -// JSONArray leaderboardStuff = (JSONArray)(obj); //converts read object to a JSONArray -// -// for (Object cur: leaderboardStuff) -// { -// JSONObject cur2 = (JSONObject) cur; -// -// String name = (String) cur2.get("name"); -// int score = Integer.parseInt(""+cur2.get("score")); -// String date = (String) cur2.get("date"); -// entries.add(new LeaderboardEntry(name, score, date)); -// } -// } -// catch (Exception e) -// { -// isValid = false; -// e.printStackTrace(); -// } -// return isValid; -// } - - -} diff --git a/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java b/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java deleted file mode 100755 index 18e657c..0000000 --- a/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.sowgro.npehero.main; - -public class LeaderboardEntry -{ - private int score; - private String name; - private String date; - - public LeaderboardEntry(String name, int score, String date) - { - this.name = name; - this.score = score; - this.date = date; - } - - public int getScore() { - return score; - } - - public String getName() { - return name; - } - - public String getDate() - { - return date; - } -} diff --git a/src/main/java/net/sowgro/npehero/main/Level.java b/src/main/java/net/sowgro/npehero/main/Level.java deleted file mode 100755 index 6f66893..0000000 --- a/src/main/java/net/sowgro/npehero/main/Level.java +++ /dev/null @@ -1,137 +0,0 @@ -package net.sowgro.npehero.main; - -import java.io.File; - -import javafx.scene.image.Image; -import javafx.scene.media.Media; -import javafx.scene.paint.Color; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; - -public class Level implements Comparable{ - - public File dir; - - public String title = "Unnamed"; - public String artist = "Unknown"; - public String desc; - public Color[] colors = {Color.RED,Color.BLUE,Color.GREEN,Color.PURPLE,Color.YELLOW};//optional, have default colors - - public Image preview; //optional - public Image background; //optional - public Media song; - - public Difficulties difficulties; - - private JSONFile metadataJson; - - /** - * Creates a new level - * @param newDir: The path of the Level - */ - public Level(File newDir) - { - dir = newDir; - metadataJson = new JSONFile(new File(dir, "metadata.json")); - difficulties = new Difficulties(this); - difficulties.read(); - readData(); - } - - /** - * Check for a song file, background file and preview image file - * Parse metadata.json - */ - public void readData() { - - var fileList = dir.listFiles(); - if (fileList == null) { - return; - } - for (File file : fileList) { - String fileName = file.getName(); - if (fileName.contains("song")) { - song = new Media(file.toURI().toString()); - } - else if (fileName.contains("background")) { - background = new Image(file.toURI().toString()); - } - else if (fileName.contains("preview")) { - preview = new Image(file.toURI().toString()); - } - } - - try { - metadataJson.read(); - } - catch (Exception e) { - // TODO - } - title = metadataJson.getString("title", title); - artist = metadataJson.getString("artist", artist); - desc = metadataJson.getString("desc", desc); - colors[0] = Color.web(metadataJson.getString("color1", colors[0].toString())); - colors[1] = Color.web(metadataJson.getString("color2", colors[1].toString())); - colors[2] = Color.web(metadataJson.getString("color3", colors[2].toString())); - colors[3] = Color.web(metadataJson.getString("color4", colors[3].toString())); - colors[4] = Color.web(metadataJson.getString("color5", colors[4].toString())); - } - - /** - * Checks if the level is valid. - * A valid level has a song file and 1 or more valid difficulties - * @return true if the level is valid - */ - public boolean isValid() { - if (song == null) { -// System.out.println(dir +" is missing song file"); - return false; - } - - if (difficulties.getValidList().isEmpty()) { -// System.out.println(dir +" contains no valid difficulties"); - return false; - } - return true; - } - - /** - * Writes metadata to json file - */ - public void writeMetadata() - { - metadataJson.set("title", title); - metadataJson.set("artist", artist); - metadataJson.set("desc", desc); - metadataJson.set("color1",colors[0].toString()); - metadataJson.set("color2",colors[1].toString()); - metadataJson.set("color3",colors[2].toString()); - metadataJson.set("color4",colors[3].toString()); - metadataJson.set("color5",colors[4].toString()); - try { - metadataJson.write(); - } - catch (IOException e) { - // TODO - } - } - - - /** - * Copies a file into the level directory - * @param newFile: the file to be copied - * @param name: the new file name - * @throws IOException if there was an error adding the file - */ - public void addFile(File newFile, String name) throws IOException { - Files.copy(newFile.toPath(), new File(dir, name).toPath(), StandardCopyOption.REPLACE_EXISTING); - readData(); - } - - @Override - public int compareTo(Level other) { - return title.compareTo(other.title); - } -} diff --git a/src/main/java/net/sowgro/npehero/main/Levels.java b/src/main/java/net/sowgro/npehero/main/Levels.java deleted file mode 100755 index ce720c6..0000000 --- a/src/main/java/net/sowgro/npehero/main/Levels.java +++ /dev/null @@ -1,88 +0,0 @@ -package net.sowgro.npehero.main; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Comparator; -import java.util.List; - -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; - -public class Levels -{ - private static final File dir = new File("levels"); - public static ObservableList list = FXCollections.observableArrayList(); - - /** - * Reads contents of the levels folder and creates a level form each subfolder - * All subfolders in the levels folder are assumed to be levels - * @throws FileNotFoundException when the levels folder is not present - */ - public static void readData() throws FileNotFoundException - { - list.clear(); - File[] fileList = dir.listFiles(); - if (fileList == null) { - throw new FileNotFoundException(); - } - for (File file: fileList) - { - Level level = new Level(file); - level.readData(); - list.add(level); - } - list.sort(Comparator.naturalOrder()); - } - - /** - * Creates a subfolder in the levels folder for the new level then creates the level with it - * @param text: the name of the directory and default title - * @throws IOException if there was an error adding the level - */ - public static void add(String text) throws IOException - { - File levelDir = new File(dir,text); - if (levelDir.mkdirs()) { - Level temp = new Level(levelDir); - temp.title = text; - list.add(temp); - } - else { - throw new IOException(); - } - } - - /** - * Removes level from the filesystem then reloads this levelController - * @param level: the level to be removed - * @throws IOException if there was an error deleting the level - */ - public static void remove(Level level) throws IOException - { - File hold = level.dir; - list.remove(level); - - // delete files recursively - // TODO clean this up - Files.walk(hold.toPath()) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - - list.remove(level); - } - - public static ObservableList getValidList() { - ObservableList validList = FXCollections.observableArrayList(); - for (Level level : list) { - if (level.isValid()) { - validList.add(level); - } - } - return validList; - } -} \ No newline at end of file diff --git a/src/main/java/net/sowgro/npehero/main/Note.java b/src/main/java/net/sowgro/npehero/main/Note.java deleted file mode 100644 index c2c9015..0000000 --- a/src/main/java/net/sowgro/npehero/main/Note.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.sowgro.npehero.main; - -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; - -/** - * A note represents a moment in the song when the player should hit a key - * The key corresponding to the lane the note is in should be pressed - */ -public class Note { - - public DoubleProperty time = new SimpleDoubleProperty(); - public int lane; - - public Note(double time, int lane) { - this.time.set(time); - this.lane = lane; - } - - /** - * Copy constructor - * @param other the note to copy from - */ - public Note(Note other) { - this.lane = other.lane; - this.time.set(other.time.get()); - } -} diff --git a/src/main/java/net/sowgro/npehero/main/Notes.java b/src/main/java/net/sowgro/npehero/main/Notes.java deleted file mode 100644 index 62a602e..0000000 --- a/src/main/java/net/sowgro/npehero/main/Notes.java +++ /dev/null @@ -1,100 +0,0 @@ -package net.sowgro.npehero.main; - -import javafx.beans.property.ListProperty; -import javafx.beans.property.SimpleListProperty; -import javafx.collections.FXCollections; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.Scanner; - -public class Notes { - private File file; - private Difficulty diff; - - public ListProperty list = new SimpleListProperty<>(FXCollections.observableArrayList()); - - public Notes(File f, Difficulty diff) { - try { - f.createNewFile(); - } catch (IOException e) { - throw new RuntimeException(e); - } - this.file = f; - this.diff = diff; - readFile(); - } - - public void readFile() { - Scanner scan = null; //file reader for reading in the notes from a notes.txt file - try { - scan = new Scanner(file); - } - catch (FileNotFoundException e) { - // TODO handle error - throw new RuntimeException(e); - } - - while (scan.hasNext()) { - String input = scan.next(); - - int lane = switch (input.charAt(0)) { - case 'd' -> 0; - case 'f' -> 1; - case 's' -> 2; - case 'j' -> 3; - case 'k' -> 4; - default -> -1; - }; - - if (lane == -1) { - // TODO handle error - continue; - } - - double time = Double.parseDouble(input.substring(1)); - if (diff.bpm != 0.0) { - time = beatToSecond(time, diff.bpm); - } - list.add(new Note(time, lane)); - } - } - - public void writeFile() { - try (PrintWriter writer = new PrintWriter(diff.notes.getFile(), StandardCharsets.UTF_8)) { - for (Note note : list) { - char lane = switch (note.lane) { - case 0 -> 'd'; - case 1 -> 'f'; - case 2 -> 's'; - case 3 -> 'j'; - case 4 -> 'k'; - default -> 'e'; - }; - - if (lane == 'e') { - // TODO handle error - } - - writer.println(lane + "" + note.time.get()); - } - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private double beatToSecond(double beat, double bpm) { - return beat/(bpm/60); - } - - public File getFile() { - return file; - } - - public ListProperty deepCopyList() { - ListProperty ret = new SimpleListProperty<>(FXCollections.observableArrayList()); - list.forEach(e -> ret.add(new Note(e))); - return ret; - } -} diff --git a/src/main/java/net/sowgro/npehero/main/Settings.java b/src/main/java/net/sowgro/npehero/main/Settings.java index 8cba8f7..43dce5a 100755 --- a/src/main/java/net/sowgro/npehero/main/Settings.java +++ b/src/main/java/net/sowgro/npehero/main/Settings.java @@ -1,8 +1,14 @@ package net.sowgro.npehero.main; import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; @@ -12,25 +18,29 @@ public class Settings public static SimpleDoubleProperty musicVol = new SimpleDoubleProperty(1); public static SimpleBooleanProperty enableMenuMusic = new SimpleBooleanProperty(true); - private static final JSONFile jsonFile = new JSONFile(new File("settings.json")); + private static final Gson jsonParser = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + private static final File jsonFile = new File("settings.json"); /** * Reads json data from settings.json */ public static void read() throws Exception { - jsonFile.read(); - effectsVol.set(jsonFile.getDouble("effectsVol", 1)); - musicVol.set(jsonFile.getDouble("musicVol", 1)); - enableMenuMusic.set(jsonFile.getBoolean("enableMenuMusic", true)); + Map data = jsonParser.fromJson(new FileReader(jsonFile), Map.class); + effectsVol.set((Double) data.getOrDefault("effectsVol", 1.0)); + musicVol.set((Double) data.getOrDefault("musicVol", 1.0)); + enableMenuMusic.set((Boolean) data.getOrDefault("enableMenuMusic", true)); } /** * Writes json data to settings.json */ public static void save() throws IOException { - jsonFile.set("effectsVol", effectsVol.get()); - jsonFile.set("musicVol", musicVol.get()); - jsonFile.set("enableMenuMusic", enableMenuMusic.get()); - jsonFile.write(); + Map data = new HashMap<>(); + data.put("effectsVol", effectsVol.get()); + data.put("musicVol", musicVol.get()); + data.put("enableMenuMusic", enableMenuMusic.get()); + FileWriter fileWriter = new FileWriter(jsonFile); + jsonParser.toJson(data, fileWriter); + fileWriter.close(); } } -- cgit v1.2.3