Compare commits

...

2 Commits

Author SHA1 Message Date
Martin Prokoph
f58cd493bb clean: housekeeping 2025-09-09 10:20:10 +02:00
Martin Prokoph
7cbe2466d8 fix: Windows support
eww...
2025-09-08 18:27:22 +02:00
15 changed files with 110 additions and 136 deletions

View File

@@ -9,6 +9,10 @@ Können Sie meinen Highscore schlagen?
![Screenshot des Tetris-Spiels](assets/ingame.png) ![Screenshot des Tetris-Spiels](assets/ingame.png)
## Im Falle einer IllegalArgumentException
Eclipse ist unfähig Java-Konventionen zu befolgen und fügt den resources-Ordner nicht automatisch zum classpath hinzu.
Um das zu beheben, gehen Sie in die Projekteinstellungen -> Java Build Path -> Source und fügen Sie den resources-Ordner manuell hinzu.
## Rechtliche Hinweise ## Rechtliche Hinweise
»Tetris« ist eine eingetragene Marke von The Tetris Company, Inc. »Tetris« ist eine eingetragene Marke von The Tetris Company, Inc.
Die Verwendung des Namens »Tetris« und des Spielkonzepts erfolgen lediglich zu Bildungszwecken. Die Verwendung des Namens »Tetris« und des Spielkonzepts erfolgen lediglich zu Bildungszwecken.

View File

@@ -1,6 +1,6 @@
package eu.midnightdust.yaytris; package eu.midnightdust.yaytris;
import eu.midnightdust.yaytris.util.NightJson; import eu.midnightdust.yaytris.util.json.NightJson;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@@ -2,24 +2,26 @@ package eu.midnightdust.yaytris;
import eu.midnightdust.yaytris.util.Difficulty; import eu.midnightdust.yaytris.util.Difficulty;
import eu.midnightdust.yaytris.util.Language; import eu.midnightdust.yaytris.util.Language;
import eu.midnightdust.yaytris.util.NightJson; import eu.midnightdust.yaytris.util.json.Comment;
import eu.midnightdust.yaytris.util.json.NightJson;
import java.util.Arrays; import java.util.Arrays;
@SuppressWarnings("unused") // Comments are unused in code, but are added to the JSON file for readability
public class Settings { public class Settings {
private static final NightJson json = new NightJson(Settings.class, "tetris_settings.json5"); private static final NightJson json = new NightJson(Settings.class, "tetris_settings.json5");
public static NightJson.Comment c1 = new NightJson.Comment("Volume of theme music (0-100)"); public static Comment c1 = new Comment("Volume of theme music (0-100)");
public static int musicVolume = 100; public static int musicVolume = 100;
public static NightJson.Comment c2 = new NightJson.Comment("Volume of sound effects (0-100)"); public static Comment c2 = new Comment("Volume of sound effects (0-100)");
public static int soundVolume = 100; public static int soundVolume = 100;
public static NightJson.Comment c3 = new NightJson.Comment("Amount the user interface should be scaled"); public static Comment c3 = new Comment("Amount the user interface should be scaled");
public static float guiScale = 3.f; public static float guiScale = 3.f;
public static NightJson.Comment c4 = new NightJson.Comment("Whether speed should scale with level (true/false)"); public static Comment c4 = new Comment("Whether speed should scale with level (true/false)");
public static boolean shouldScaleSpeed = true; public static boolean shouldScaleSpeed = true;
public static NightJson.Comment c5 = new NightJson.Comment("One of %s", Arrays.toString(Difficulty.values())); public static Comment c5 = new Comment("One of %s", Arrays.toString(Difficulty.values()));
public static Difficulty difficulty = Difficulty.NORMAL; public static Difficulty difficulty = Difficulty.NORMAL;
public static NightJson.Comment c6 = new NightJson.Comment("One of %s", Arrays.toString(Language.values())); public static Comment c6 = new Comment("One of %s", Arrays.toString(Language.values()));
public static Language language = Language.ENGLISH; public static Language language = Language.ENGLISH;
public static void load() { public static void load() {

View File

@@ -1,6 +1,6 @@
package eu.midnightdust.yaytris; package eu.midnightdust.yaytris;
import eu.midnightdust.yaytris.util.NightJson; import eu.midnightdust.yaytris.util.json.NightJson;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View File

@@ -1,16 +1,22 @@
package eu.midnightdust.yaytris.ui; package eu.midnightdust.yaytris.ui;
import eu.midnightdust.yaytris.util.CatppuccinColor;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import static eu.midnightdust.yaytris.ui.TetrisUI.scale; import static eu.midnightdust.yaytris.ui.TetrisUI.scale;
import static eu.midnightdust.yaytris.ui.TetrisUI.setFontScale;
public class AbstractMenu extends JPanel { public class AbstractMenu extends JPanel {
@Override @Override
public Component add(Component comp) { public Component add(Component comp) {
comp.setBounds(scale(60), scale(20+getSpacing()*this.getComponentCount()), scale(100), scale(20)); comp.setBounds(scale(60), scale(20+getSpacing()*this.getComponentCount()), scale(100), scale(20));
if (comp instanceof JComponent) setFontScale((JComponent) comp); if (comp instanceof JLabel) {
comp.setForeground(CatppuccinColor.TEXT.getColor());
}
if (comp instanceof JComponent) {
((JComponent) comp).setOpaque(false);
}
return super.add(comp); return super.add(comp);
} }

View File

@@ -29,11 +29,13 @@ public class HighScoreMenu extends JPanel {
highscores.sort((s1, s2) -> Integer.compare(Integer.parseInt(s2.split("")[0].replace(" ", "")), Integer.parseInt(s1.split("")[0].replace(" ", "")))); highscores.sort((s1, s2) -> Integer.compare(Integer.parseInt(s2.split("")[0].replace(" ", "")), Integer.parseInt(s1.split("")[0].replace(" ", ""))));
JList<String> highscoreList = new JList<>(highscores.toArray(String[]::new)); JList<String> highscoreList = new JList<>(highscores.toArray(String[]::new));
highscoreList.setBackground(CatppuccinColor.BASE.getColor()); highscoreList.setBackground(CatppuccinColor.BASE.getColor());
highscoreList.setForeground(CatppuccinColor.TEXT.getColor());
highscoreList.setSelectionForeground(CatppuccinColor.CRUST.getColor()); highscoreList.setSelectionForeground(CatppuccinColor.CRUST.getColor());
JScrollPane highscoreScrollPane = new JScrollPane(highscoreList); JScrollPane highscoreScrollPane = new JScrollPane(highscoreList);
highscoreScrollPane.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), 3, true)); highscoreScrollPane.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), 3, true));
this.add(highscoreScrollPane); this.add(highscoreScrollPane);
highscoreScrollPane.setBounds(scale(60), scale(43), scale(100), scale(80)); highscoreScrollPane.setBounds(scale(60), scale(43), scale(100), scale(80));
highscoreList.setBounds(scale(60), scale(43), scale(100), scale(80));
JButton backButton = new JButton(t("ui.back")); JButton backButton = new JButton(t("ui.back"));
backButton.addActionListener(ui::openMainMenu); backButton.addActionListener(ui::openMainMenu);
@@ -45,6 +47,10 @@ public class HighScoreMenu extends JPanel {
public Component add(Component comp) { public Component add(Component comp) {
if (comp instanceof JLabel) { if (comp instanceof JLabel) {
comp.setBounds(scale(60), scale(30), scale(100), scale(7)); comp.setBounds(scale(60), scale(30), scale(100), scale(7));
comp.setForeground(CatppuccinColor.TEXT.getColor());
}
if (comp instanceof JComponent) {
((JComponent) comp).setOpaque(false);
} }
return super.add(comp); return super.add(comp);
} }

View File

@@ -2,6 +2,7 @@ package eu.midnightdust.yaytris.ui;
import eu.midnightdust.yaytris.Settings; import eu.midnightdust.yaytris.Settings;
import eu.midnightdust.yaytris.Translation; import eu.midnightdust.yaytris.Translation;
import eu.midnightdust.yaytris.util.CatppuccinColor;
import eu.midnightdust.yaytris.util.Difficulty; import eu.midnightdust.yaytris.util.Difficulty;
import eu.midnightdust.yaytris.util.Language; import eu.midnightdust.yaytris.util.Language;
@@ -10,7 +11,6 @@ import java.awt.*;
import static eu.midnightdust.yaytris.Translation.t; import static eu.midnightdust.yaytris.Translation.t;
import static eu.midnightdust.yaytris.ui.TetrisUI.scale; import static eu.midnightdust.yaytris.ui.TetrisUI.scale;
import static eu.midnightdust.yaytris.ui.TetrisUI.setFontScale;
public class SettingsMenu extends JPanel { public class SettingsMenu extends JPanel {
final TetrisUI ui; final TetrisUI ui;
@@ -87,9 +87,10 @@ public class SettingsMenu extends JPanel {
comp.setBounds(scale(60), scale(20+17*this.getComponentCount()-labelAmount*10), scale(100), scale(20)); comp.setBounds(scale(60), scale(20+17*this.getComponentCount()-labelAmount*10), scale(100), scale(20));
if (comp instanceof JLabel) { if (comp instanceof JLabel) {
comp.setBounds(scale(60), scale(20+17*(this.getComponentCount())-labelAmount*10), scale(100), scale(7)); comp.setBounds(scale(60), scale(20+17*(this.getComponentCount())-labelAmount*10), scale(100), scale(7));
comp.setForeground(CatppuccinColor.TEXT.getColor());
labelAmount++; labelAmount++;
} }
if (comp instanceof JComponent) setFontScale((JComponent) comp); if (comp instanceof JComponent) ((JComponent) comp).setOpaque(false);
return super.add(comp); return super.add(comp);
} }
} }

View File

@@ -29,11 +29,11 @@ public class TetrisUI extends JFrame implements KeyListener {
public TetrisUI() { public TetrisUI() {
this.setLayout(null); this.setLayout(null);
this.setTitle("Tetris"); this.setTitle("Tetris");
this.setSize((int) (400 * guiScale), (int) (300 * guiScale)); this.setSize((int) (400 * guiScale), (int) (320 * guiScale));
this.setResizable(false); this.setResizable(false);
this.getContentPane().setBackground(CatppuccinColor.MANTLE.getColor()); this.getContentPane().setBackground(CatppuccinColor.MANTLE.getColor());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setWindowPosition(this, 0); this.setLocationRelativeTo(null);
titleLabel = new JLabel("Tetris"); titleLabel = new JLabel("Tetris");
titleLabel.setForeground(Color.WHITE); titleLabel.setForeground(Color.WHITE);
@@ -62,13 +62,11 @@ public class TetrisUI extends JFrame implements KeyListener {
* Resize all elements to match the current GUI scale. * Resize all elements to match the current GUI scale.
*/ */
private void rescale() { private void rescale() {
this.setSize((int) (400 * guiScale), (int) (300 * guiScale)); this.setSize((int) (400 * guiScale), (int) (320 * guiScale));
titleLabel.setBounds(scale(225), scale(7), scale(110), scale(30)); titleLabel.setBounds(scale(225), scale(7), scale(110), scale(30));
titleLabel.setIcon(new ImageIcon(new ImageIcon(titleImage).getImage().getScaledInstance(scale(110), scale(30), Image.SCALE_DEFAULT))); titleLabel.setIcon(new ImageIcon(new ImageIcon(titleImage).getImage().getScaledInstance(scale(110), scale(30), Image.SCALE_DEFAULT)));
gamePanel.setBounds(scale(10), scale(10), scale(150), scale(282)); gamePanel.setBounds(scale(10), scale(10), scale(150), scale(282));
for (Component comp : this.getComponents()){ this.setLocationRelativeTo(null);
if (comp instanceof JComponent) setFontScale((JComponent) comp);
}
} }
/** /**
@@ -79,9 +77,6 @@ public class TetrisUI extends JFrame implements KeyListener {
public static int scale(int bound) { public static int scale(int bound) {
return (int) (bound * guiScale); return (int) (bound * guiScale);
} }
public static void setFontScale(JComponent label) {
//if (label.getFont() != null) label.setFont(label.getFont().deriveFont((float) label.getFont().getSize() * guiScale));
}
public GameCanvas getGamePanel() { public GameCanvas getGamePanel() {
return gamePanel; return gamePanel;
@@ -108,7 +103,7 @@ public class TetrisUI extends JFrame implements KeyListener {
* *
* @param actionEvent unnecessary, but allows for more elegant lambda statements :) * @param actionEvent unnecessary, but allows for more elegant lambda statements :)
*/ */
public void openMainMenu(ActionEvent actionEvent) { public void openMainMenu(@SuppressWarnings("unused") ActionEvent actionEvent) {
if (this.menuPanel != null) this.remove(menuPanel); if (this.menuPanel != null) this.remove(menuPanel);
Tetris.resetSpace(); Tetris.resetSpace();
rescale(); rescale();
@@ -126,7 +121,7 @@ public class TetrisUI extends JFrame implements KeyListener {
* *
* @param actionEvent unnecessary, but allows for more elegant lambda statements :) * @param actionEvent unnecessary, but allows for more elegant lambda statements :)
*/ */
public void openSettings(ActionEvent actionEvent) { public void openSettings(@SuppressWarnings("unused") ActionEvent actionEvent) {
if (this.menuPanel != null) this.remove(menuPanel); if (this.menuPanel != null) this.remove(menuPanel);
menuPanel = new SettingsMenu(scale(170), scale(40), scale(220), scale(252), this); menuPanel = new SettingsMenu(scale(170), scale(40), scale(220), scale(252), this);
menuPanel.setBackground(CatppuccinColor.BASE.getColor()); menuPanel.setBackground(CatppuccinColor.BASE.getColor());
@@ -140,7 +135,7 @@ public class TetrisUI extends JFrame implements KeyListener {
* *
* @param actionEvent unnecessary, but allows for more elegant lambda statements :) * @param actionEvent unnecessary, but allows for more elegant lambda statements :)
*/ */
public void openScoreMenu(ActionEvent actionEvent) { public void openScoreMenu(@SuppressWarnings("unused") ActionEvent actionEvent) {
if (this.menuPanel != null) this.remove(menuPanel); if (this.menuPanel != null) this.remove(menuPanel);
menuPanel = new ScoreMenu(scale(170), scale(40), scale(220), scale(252), this); menuPanel = new ScoreMenu(scale(170), scale(40), scale(220), scale(252), this);
menuPanel.setBackground(CatppuccinColor.BASE.getColor()); menuPanel.setBackground(CatppuccinColor.BASE.getColor());
@@ -154,7 +149,7 @@ public class TetrisUI extends JFrame implements KeyListener {
* *
* @param actionEvent unnecessary, but allows for more elegant lambda statements :) * @param actionEvent unnecessary, but allows for more elegant lambda statements :)
*/ */
public void openHighscores(ActionEvent actionEvent) { public void openHighscores(@SuppressWarnings("unused") ActionEvent actionEvent) {
if (this.menuPanel != null) this.remove(menuPanel); if (this.menuPanel != null) this.remove(menuPanel);
menuPanel = new HighScoreMenu(scale(170), scale(40), scale(220), scale(252), this); menuPanel = new HighScoreMenu(scale(170), scale(40), scale(220), scale(252), this);
menuPanel.setBackground(CatppuccinColor.BASE.getColor()); menuPanel.setBackground(CatppuccinColor.BASE.getColor());
@@ -173,40 +168,6 @@ public class TetrisUI extends JFrame implements KeyListener {
HighScores.addScore(playerName, score); HighScores.addScore(playerName, score);
} }
/**
* Centers the game window on the given screen.
* Source: <a href="https://stackoverflow.com/a/19746437">Miss Chanandler Bong & Peter Szabo on StackOverflow</a>
*
* @param window the window to center
* @param screen the screen to center it on
*/
private void setWindowPosition(JFrame window, int screen) {
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] allDevices = env.getScreenDevices();
int topLeftX, topLeftY, screenX, screenY, windowPosX, windowPosY;
if (screen < allDevices.length && screen > -1) {
topLeftX = allDevices[screen].getDefaultConfiguration().getBounds().x;
topLeftY = allDevices[screen].getDefaultConfiguration().getBounds().y;
screenX = allDevices[screen].getDefaultConfiguration().getBounds().width;
screenY = allDevices[screen].getDefaultConfiguration().getBounds().height;
}
else {
topLeftX = allDevices[0].getDefaultConfiguration().getBounds().x;
topLeftY = allDevices[0].getDefaultConfiguration().getBounds().y;
screenX = allDevices[0].getDefaultConfiguration().getBounds().width;
screenY = allDevices[0].getDefaultConfiguration().getBounds().height;
}
windowPosX = ((screenX - window.getWidth()) / 2) + topLeftX;
windowPosY = ((screenY - window.getHeight()) / 2) + topLeftY;
window.setLocation(windowPosX, windowPosY);
}
/** /**
* Capture keyboard inputs during a game session. * Capture keyboard inputs during a game session.
* *

View File

@@ -6,7 +6,7 @@ import java.awt.*;
* Color scheme based on the <a href="https://github.com/catppuccin/catppuccin">Catppuccin Mocha</a> color palette * Color scheme based on the <a href="https://github.com/catppuccin/catppuccin">Catppuccin Mocha</a> color palette
*/ */
public enum CatppuccinColor { public enum CatppuccinColor {
CRUST(0x11111b), MANTLE(0x181825), BASE(0x1e1e2e), SURFACE0(0x313244); TEXT(0xcdd6f4), CRUST(0x11111b), MANTLE(0x181825), BASE(0x1e1e2e), SURFACE0(0x313244);
final Color color; final Color color;
CatppuccinColor(int rgb) { CatppuccinColor(int rgb) {

View File

@@ -1,9 +1,6 @@
package eu.midnightdust.yaytris.util; package eu.midnightdust.yaytris.util;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -17,21 +14,4 @@ public class FileUtil {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
public static AudioInputStream loadAudio(String location) {
try (InputStream fileStream = FileUtil.class.getResourceAsStream(location)) {
assert fileStream != null;
return AudioSystem.getAudioInputStream(fileStream);
} catch (IOException | NullPointerException | UnsupportedAudioFileException ex) {
throw new RuntimeException(ex);
}
}
public static InputStream getFileStream(String location) {
try (InputStream fileStream = FileUtil.class.getResourceAsStream(location)) {
return fileStream;
} catch (IOException | NullPointerException ex) {
throw new RuntimeException(ex);
}
}
} }

View File

@@ -0,0 +1,19 @@
package eu.midnightdust.yaytris.util.json;
/**
* Add comments to your json files.
* If you decide to use this, it's best to save with the .json5 extension, as regular json does not officially support comments.
*/
public class Comment {
final String commentString;
/**
* Add a comment to spice-up the json file :)
*
* @param commentString the string you want to write as a comment
* @param args optional formatting arguments, calls {@link String#format(String, Object...)}
*/
public Comment(String commentString, Object... args) {
this.commentString = String.format(commentString, args);
}
}

View File

@@ -1,4 +1,4 @@
package eu.midnightdust.yaytris.util; package eu.midnightdust.yaytris.util.json;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
@@ -12,8 +12,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* NightJson v0.2 by Martin Prokoph * NightJson v0.3 by Martin Prokoph
* Extremely lightweight (and incomplete) JSON library * Extremely lightweight JSON library
* Concept inspired by GSON * Concept inspired by GSON
*/ */
public class NightJson { public class NightJson {
@@ -39,28 +39,11 @@ public class NightJson {
/** /**
* Convert the current state of the java json class to actual json and save it to disk. * Convert the current state of the java json class to actual json and save it to disk.
*/ */
@SuppressWarnings("unchecked")
public void writeJson() { public void writeJson() {
if (fileLocation == null) return; if (fileLocation == null) return;
try { try {
FileWriter jsonFile = new FileWriter(fileLocation); FileWriter jsonFile = new FileWriter(fileLocation);
writeJsonToFile(jsonFile);
jsonFile.write("{\n");
Iterator<Field> it = Arrays.stream(jsonClass.getFields()).iterator();
while (it.hasNext()) {
Field field = it.next();
if (field != jsonMap) writeElement(jsonFile, field.get(null), field.getType(), field.getName(), it.hasNext());
}
if (jsonMap != null) {
Iterator<String> mapIt = ((Map<String,?>)jsonMap.get(null)).keySet().iterator();
while (mapIt.hasNext()) {
String key = mapIt.next();
Object value = jsonMap.get(key);
writeElement(jsonFile, value, value.getClass(), key, mapIt.hasNext());
}
}
jsonFile.write("}");
jsonFile.close();
} catch (IOException | IllegalAccessException e) { } catch (IOException | IllegalAccessException e) {
System.out.println("Oh no! An Error occurred whilst writing the JSON file :("); System.out.println("Oh no! An Error occurred whilst writing the JSON file :(");
//noinspection CallToPrintStackTrace //noinspection CallToPrintStackTrace
@@ -68,10 +51,30 @@ public class NightJson {
} }
} }
@SuppressWarnings("unchecked")
private void writeJsonToFile(FileWriter jsonFile) throws IOException, IllegalAccessException {
jsonFile.write("{\n");
Iterator<Field> it = Arrays.stream(jsonClass.getFields()).iterator();
while (it.hasNext()) {
Field field = it.next();
if (field != jsonMap) writeElement(jsonFile, field.get(null), field.getType(), field.getName(), it.hasNext());
}
if (jsonMap != null) {
Iterator<String> mapIt = ((Map<String,?>)jsonMap.get(null)).keySet().iterator();
while (mapIt.hasNext()) {
String key = mapIt.next();
Object value = jsonMap.get(key);
writeElement(jsonFile, value, value.getClass(), key, mapIt.hasNext());
}
}
jsonFile.write("}");
jsonFile.close();
}
/** /**
* Write the desired element into the file. * Write the desired element into the file.
*/ */
private void writeElement(FileWriter jsonFile, Object value, Class<?> type, String name, boolean hasNext) throws IOException, IllegalAccessException { private void writeElement(FileWriter jsonFile, Object value, Class<?> type, String name, boolean hasNext) throws IOException {
jsonFile.write("\t"); jsonFile.write("\t");
if (type == Comment.class) { if (type == Comment.class) {
jsonFile.write(String.format("// %s\n", ((Comment) value).commentString)); jsonFile.write(String.format("// %s\n", ((Comment) value).commentString));
@@ -120,23 +123,9 @@ public class NightJson {
/** /**
* Read the json file from disk and overwrite the json class's field values. * Read the json file from disk and overwrite the json class's field values.
*/ */
@SuppressWarnings("unchecked")
public void readJsonFromString(String jsonString) { public void readJsonFromString(String jsonString) {
try { try {
Map<String, Object> asMap = jsonToMap( readJsonString(jsonString);
jsonString.replaceAll("(//)+.*\n", ""), // Replace comment lines (Json5)
(key) -> getField(key).isPresent() ? getField(key).get().getType() : String.class); // Determine data type
for (String key : asMap.keySet()) {
Object value = asMap.get(key);
Optional<Field> field = getField(key);
if (field.isPresent()) {
field.get().set(null, value);
}
else if (jsonMap != null) {
((Map<String, Object>)jsonMap.get(null)).put(key, value);
}
}
} catch (IllegalAccessException | NoSuchElementException | ClassCastException e) { } catch (IllegalAccessException | NoSuchElementException | ClassCastException e) {
System.out.println("Oh no! An Error occurred whilst reading the JSON file :("); System.out.println("Oh no! An Error occurred whilst reading the JSON file :(");
//noinspection CallToPrintStackTrace //noinspection CallToPrintStackTrace
@@ -144,6 +133,24 @@ public class NightJson {
} }
} }
@SuppressWarnings("unchecked")
private void readJsonString(String jsonString) throws IllegalAccessException {
Map<String, Object> asMap = jsonToMap(
jsonString.replaceAll("(//)+.*\n", ""), // Replace comment lines (Json5)
(key) -> getField(key).isPresent() ? getField(key).get().getType() : String.class); // Determine data type
for (String key : asMap.keySet()) {
Object value = asMap.get(key);
Optional<Field> field = getField(key);
if (field.isPresent()) {
field.get().set(null, value);
}
else if (jsonMap != null) {
((Map<String, Object>)jsonMap.get(null)).put(key, value);
}
}
}
/** /**
* Read the json file as key-value pairs and save it as a map. * Read the json file as key-value pairs and save it as a map.
*/ */
@@ -249,20 +256,4 @@ public class NightJson {
return Optional.empty(); return Optional.empty();
} }
} }
/**
* Add comments to your json files.
* If you decide to use this, it's best to save with the .json5 extension, as regular json does not officially support comments.
*/
public static class Comment {
final String commentString;
/**
* Add a comment to spice-up the json file :)
* @param commentString the string you want to write as a comment
* @param args optional formatting arguments, calls {@link String#format(String, Object...)}
*/
public Comment(String commentString, Object... args) {
this.commentString = String.format(commentString, args);
}
}
} }

View File

@@ -65,6 +65,8 @@ public class MusicThread extends Thread {
sourceDataLine.close(); sourceDataLine.close();
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IllegalArgumentException ignored) {
// Happens when no audio device is connected
} }
} }
} }

View File

@@ -52,6 +52,8 @@ public class SoundUtil {
setVolume(audioClip, Settings.soundVolume); setVolume(audioClip, Settings.soundVolume);
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IllegalArgumentException ignored) {
// Happens when no audio device is connected
} }
} }

View File

@@ -1,10 +1,10 @@
{ {
// Volume of theme music (0-100) // Volume of theme music (0-100)
"musicVolume": 30, "musicVolume": 100,
// Volume of sound effects (0-100) // Volume of sound effects (0-100)
"soundVolume": 100, "soundVolume": 100,
// Amount the user interface should be scaled // Amount the user interface should be scaled
"guiScale": 5.7, "guiScale": 2.00,
// Whether speed should scale with level (true/false) // Whether speed should scale with level (true/false)
"shouldScaleSpeed": true, "shouldScaleSpeed": true,
// One of [Noob, Easy, Normal, Hard, Extreme, WTF] // One of [Noob, Easy, Normal, Hard, Extreme, WTF]