From b60f8473df9ae2a77c0f3ee36cb00b9c90826435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20H=C3=A1la?= Date: Tue, 13 Oct 2020 15:59:20 +0200 Subject: [PATCH] Rework Track/TrackSet management - Split Tracks and their Statistics - Rewrite parsing - Migrate most of the track stuff to shared/ - Add tests for the new parser --- .../org/moparforia/editor/EditorPanel.java | 19 +- .../org/moparforia/editor/TrackEditor.java | 40 +-- .../editor/TrackPropertiesDialog.java | 4 +- pom.xml | 22 +- server/pom.xml | 8 - server/server.iml | 7 +- .../java/org/moparforia/server/Server.java | 10 +- .../org/moparforia/server/db/Database.java | 2 +- .../server/game/gametypes/GolfGame.java | 98 ++---- .../game/gametypes/golf/ChampionshipGame.java | 10 +- .../server/game/gametypes/golf/DualGame.java | 12 +- .../server/game/gametypes/golf/MultiGame.java | 11 +- .../game/gametypes/golf/TrainingGame.java | 12 +- .../net/packethandlers/golf/LobbyHandler.java | 13 +- .../moparforia/server/track/TrackManager.java | 204 ------------- .../server/util/StockTrackUploader.java | 11 +- shared/pom.xml | 32 +- shared/shared.iml | 20 +- .../java/org/moparforia/shared/Tools.java | 13 - .../java/org/moparforia/shared/Track.java | 285 ------------------ .../org/moparforia/shared/tracks/Track.java | 73 +++++ .../shared/tracks}/TrackCategory.java | 14 +- .../shared/tracks/TrackLoadException.java | 11 + .../shared/tracks/TrackManager.java | 45 +++ .../moparforia/shared/tracks}/TrackSet.java | 16 +- .../shared/tracks}/TrackSetDifficulty.java | 2 +- .../filesystem/FileSystemStatsManager.java | 76 +++++ .../filesystem/FileSystemTrackManager.java | 192 ++++++++++++ .../filesystem/FileSystemTrackStats.java | 121 ++++++++ .../tracks/filesystem/TrackFileParser.java | 108 +++++++ .../lineparser/BestTimeLineParser.java | 31 ++ .../lineparser/RatingsLineParser.java | 18 ++ .../lineparser/ScoreInfoLineParser.java | 19 ++ .../lineparser/SimpleLineParser.java | 24 ++ .../shared/tracks/stats/StatsManager.java | 32 ++ .../shared/tracks/stats/TrackStats.java | 66 ++++ .../shared/utils/CollectorUtils.java | 17 ++ .../filesystem/FileSystemExtension.java | 78 +++++ .../FileSystemStatsManagerTest.java | 62 ++++ .../FileSystemTrackManagerTest.java | 113 +++++++ .../tracks/basic/Aither-4_da_Crew.track | 9 + .../tracks/basic/Aither-5th_Street.track | 8 + .../basic/Aither-____Not_Tragedies.track | 8 + .../hio/Aither-Blunt_Force_Trauma.track | 7 + .../tracks/hio/Aither-BoomBiddyByeBye.track | 8 + .../Aither-Another_one_bites_the_mud.track | 8 + .../tracks/long/Aither-Anticandy.track | 8 + .../tracks/modern/Aither-AC_DC.track | 8 + .../tracks/modern/Aither-Absinth_II.track | 8 + .../tracks/modern/Aither-Big_Blind.track | 8 + .../tracks/modern/Aither-Blockster.track | 8 + .../resources/tracks/modern/empty_stats.track | 4 + .../test/resources/tracks/modern/single.track | 9 + .../resources/tracks/sets/birchwood.trackset | 6 + .../resources/tracks/sets/oakpark.trackset | 3 + .../tracks/short/Aither-Alchemea.track | 8 + .../tracks/short/Aither-Basement_Reflex.track | 8 + .../traditional/Aither-Audiorealism.track | 8 + .../traditional/Aither-Avoiding_ponds.track | 9 + .../Aither-Bananas_for_Banshee.track | 8 + tracks/sets/birchwood.trackset | 18 +- tracks/sets/oakpark.trackset | 36 +-- tracks/sets/onebyone.trackset | 36 +-- tracks/sets/scaryset.trackset | 18 +- tracks/sets/sprucecorpse.trackset | 18 +- tracks/sets/thefirst.trackset | 36 +-- tracks/sets/tormentfields.trackset | 36 +-- 67 files changed, 1500 insertions(+), 800 deletions(-) delete mode 100644 server/src/main/java/org/moparforia/server/track/TrackManager.java delete mode 100644 shared/src/main/java/org/moparforia/shared/Track.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/Track.java rename {server/src/main/java/org/moparforia/server/track => shared/src/main/java/org/moparforia/shared/tracks}/TrackCategory.java (54%) create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/TrackLoadException.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/TrackManager.java rename {server/src/main/java/org/moparforia/server/track => shared/src/main/java/org/moparforia/shared/tracks}/TrackSet.java (69%) rename {server/src/main/java/org/moparforia/server/track => shared/src/main/java/org/moparforia/shared/tracks}/TrackSetDifficulty.java (86%) create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManager.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackStats.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/TrackFileParser.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/BestTimeLineParser.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/RatingsLineParser.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/ScoreInfoLineParser.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/SimpleLineParser.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/stats/StatsManager.java create mode 100644 shared/src/main/java/org/moparforia/shared/tracks/stats/TrackStats.java create mode 100644 shared/src/main/java/org/moparforia/shared/utils/CollectorUtils.java create mode 100644 shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemExtension.java create mode 100644 shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManagerTest.java create mode 100644 shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManagerTest.java create mode 100644 shared/src/test/resources/tracks/basic/Aither-4_da_Crew.track create mode 100644 shared/src/test/resources/tracks/basic/Aither-5th_Street.track create mode 100644 shared/src/test/resources/tracks/basic/Aither-____Not_Tragedies.track create mode 100644 shared/src/test/resources/tracks/hio/Aither-Blunt_Force_Trauma.track create mode 100644 shared/src/test/resources/tracks/hio/Aither-BoomBiddyByeBye.track create mode 100644 shared/src/test/resources/tracks/long/Aither-Another_one_bites_the_mud.track create mode 100644 shared/src/test/resources/tracks/long/Aither-Anticandy.track create mode 100644 shared/src/test/resources/tracks/modern/Aither-AC_DC.track create mode 100644 shared/src/test/resources/tracks/modern/Aither-Absinth_II.track create mode 100644 shared/src/test/resources/tracks/modern/Aither-Big_Blind.track create mode 100644 shared/src/test/resources/tracks/modern/Aither-Blockster.track create mode 100644 shared/src/test/resources/tracks/modern/empty_stats.track create mode 100644 shared/src/test/resources/tracks/modern/single.track create mode 100644 shared/src/test/resources/tracks/sets/birchwood.trackset create mode 100644 shared/src/test/resources/tracks/sets/oakpark.trackset create mode 100644 shared/src/test/resources/tracks/short/Aither-Alchemea.track create mode 100644 shared/src/test/resources/tracks/short/Aither-Basement_Reflex.track create mode 100644 shared/src/test/resources/tracks/traditional/Aither-Audiorealism.track create mode 100644 shared/src/test/resources/tracks/traditional/Aither-Avoiding_ponds.track create mode 100644 shared/src/test/resources/tracks/traditional/Aither-Bananas_for_Banshee.track diff --git a/editor/src/main/java/org/moparforia/editor/EditorPanel.java b/editor/src/main/java/org/moparforia/editor/EditorPanel.java index 091066d4..3c76e88c 100644 --- a/editor/src/main/java/org/moparforia/editor/EditorPanel.java +++ b/editor/src/main/java/org/moparforia/editor/EditorPanel.java @@ -1,6 +1,7 @@ package org.moparforia.editor; -import org.moparforia.shared.Track; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; import javax.swing.*; import javax.swing.border.Border; @@ -207,7 +208,7 @@ public void actionPerformed(ActionEvent e) { chooser.showDialog(getThis(),"hurr"); File f = chooser.getSelectedFile(); //currentTrack = TrackStore.getTrack(f);//todo get rid of this (uses org.moparforia.server.track.TrackStore)!! - currentTrack = TrackEditor.loadTrack(f); + currentTrack = TrackEditor.loadTrack(f.toPath()); Map m = new MapDecompressor().decompress(currentTrack.getMap()); canvas.setMap(m); } catch (Exception exp) { @@ -227,10 +228,8 @@ public void actionPerformed(ActionEvent e) { if(currentTrack == null) { String data = new MapCompressor().compress(canvas.getMap()); String name = JOptionPane.showInputDialog(getThis(),"WUTS THE NAME OF THIS TRACK?"); - Track t = new Track(name, "fc", data, 7, - new int[]{1000, 1000, 2, 10}, new String[]{"fc", "sum cunt"}, new long[]{10, 3300000}, - new int[]{0, 0, 0, 0, 3, 0, 0, 0, 0, 10, 10}); - currentTrack = t; + Track track = new Track(name, "fc", data, TrackCategory.UNKNOWN); + currentTrack = track; } MapCompressor mc = new MapCompressor(); @@ -240,13 +239,9 @@ public void actionPerformed(ActionEvent e) { String save = currentTrack.toString().replace("\t", "\n"); File file = new File("tracks/custom/" + currentTrack.getName() + ".track"); - PrintStream out = null; - try { - out = new PrintStream(new FileOutputStream(file, false)); + try (PrintStream out = new PrintStream(new FileOutputStream(file, false))) { out.print(save); - } catch (Exception ee) { - } finally { - if (out != null) out.close(); + } catch (Exception ignored) { } } diff --git a/editor/src/main/java/org/moparforia/editor/TrackEditor.java b/editor/src/main/java/org/moparforia/editor/TrackEditor.java index c96d7818..e5d91f01 100644 --- a/editor/src/main/java/org/moparforia/editor/TrackEditor.java +++ b/editor/src/main/java/org/moparforia/editor/TrackEditor.java @@ -4,7 +4,10 @@ package org.moparforia.editor; -import org.moparforia.shared.Track; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; +import org.moparforia.shared.tracks.filesystem.TrackFileParser; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -15,6 +18,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.*; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Scanner; @@ -185,25 +189,9 @@ private void generateButtons() { togglePencil.setSelected(true); } - public static final Track loadTrack(File f) throws IOException { - - String name = null, author = null, data = null; - Scanner scanner = new Scanner(new FileInputStream(f)); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (line.startsWith("V ")) { - // hi - } else if (line.startsWith("S ")) { - // hi? get on it, watson - } else if (line.startsWith("A ")) { - author = line.substring(2); - } else if (line.startsWith("N ")) { - name = line.substring(2); - } else if (line.startsWith("T ")) { - data = line.substring(2); - } - } - return new Track(name, author, data, 7); + public static final Track loadTrack(Path path) throws IOException { + + return TrackFileParser.parseTrack(path, TrackCategory.UNKNOWN); } private void menuNewActionPerformed(ActionEvent e) { @@ -216,9 +204,9 @@ private void menuOpenActionPerformed(ActionEvent e) { int result = chooser.showOpenDialog(this); if (result != JFileChooser.CANCEL_OPTION) { File f = chooser.getSelectedFile(); - Track currentTrack = loadTrack(f); + Track currentTrack = loadTrack(f.toPath()); Map m = new MapDecompressor().decompress(currentTrack.getMap()); - mapCanvas.updateProperties(currentTrack.getName(), currentTrack.getCategory()); + mapCanvas.updateProperties(currentTrack.getName(), currentTrack.getCategory().getId()); mapCanvas.setMap(m); } } catch (Exception exp) { @@ -241,7 +229,7 @@ private void menuSaveActionPerformed(ActionEvent e) { return; } String data = new MapCompressor().compress(mapCanvas.getMap()); - Track t = new Track(mapCanvas.getTrackName(), "editor", data, 7); + Track track = new Track(mapCanvas.getTrackName(), "editor", data, TrackCategory.UNKNOWN); JFileChooser saver = new JFileChooser("tracks/custom/"); saver.setFileFilter(new FileFilter() { @@ -255,13 +243,13 @@ public String getDescription() { return "*.track"; } }); - saver.setSelectedFile(new File(t.getName().replaceAll(" ", "_"))); + saver.setSelectedFile(new File(track.getName().replaceAll(" ", "_"))); int result = saver.showSaveDialog(this); if (result == JFileChooser.CANCEL_OPTION) return; - t.setMap(data); - String save = t.toSaveString().replace("\t", "\n"); + track.setMap(data); + String save = FileSystemTrackManager.convertTrack(track).replace("\t", "\n"); PrintStream out = null; try { diff --git a/editor/src/main/java/org/moparforia/editor/TrackPropertiesDialog.java b/editor/src/main/java/org/moparforia/editor/TrackPropertiesDialog.java index d6b1c8d3..6f622e5c 100644 --- a/editor/src/main/java/org/moparforia/editor/TrackPropertiesDialog.java +++ b/editor/src/main/java/org/moparforia/editor/TrackPropertiesDialog.java @@ -4,6 +4,8 @@ package org.moparforia.editor; +import org.moparforia.shared.tracks.TrackCategory; + import java.awt.*; import java.awt.event.*; import javax.swing.*; @@ -26,7 +28,7 @@ public TrackPropertiesDialog(Dialog owner) { private void loadValues() { textTrackName.setText(((TrackEditor)getOwner()).getMapCanvas().getTrackName()); - comboTrackCategory.setSelectedIndex(((TrackEditor)getOwner()).getMapCanvas().getTrackCategory() - 1); + comboTrackCategory.setSelectedIndex(TrackCategory.BASIC.getId()); } private void okButtonActionPerformed(ActionEvent e) { diff --git a/pom.xml b/pom.xml index d4c23da5..ee11a246 100644 --- a/pom.xml +++ b/pom.xml @@ -97,16 +97,6 @@ 3.10.6.Final compile - - org.mongodb - mongo-java-driver - 3.6.0 - - - org.mongodb.morphia - morphia - 1.2.2 - org.moparforia shared @@ -137,6 +127,18 @@ 3.5.10 test + + com.github.marschall + memoryfilesystem + 2.1.0 + test + + + org.softsmithy.lib + softsmithy-lib-core + 2.1.1 + test + diff --git a/server/pom.xml b/server/pom.xml index ef406e0e..c6411461 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -24,14 +24,6 @@ netty compile - - org.mongodb - mongo-java-driver - - - org.mongodb.morphia - morphia - org.moparforia shared diff --git a/server/server.iml b/server/server.iml index 37695179..74f6bcf4 100644 --- a/server/server.iml +++ b/server/server.iml @@ -11,11 +11,7 @@ - - - - - + @@ -29,6 +25,5 @@ - \ No newline at end of file diff --git a/server/src/main/java/org/moparforia/server/Server.java b/server/src/main/java/org/moparforia/server/Server.java index 1ce96869..1a48fb56 100644 --- a/server/src/main/java/org/moparforia/server/Server.java +++ b/server/src/main/java/org/moparforia/server/Server.java @@ -14,7 +14,9 @@ import org.moparforia.server.game.LobbyType; import org.moparforia.server.game.Player; import org.moparforia.server.net.*; -import org.moparforia.server.track.TrackManager; +import org.moparforia.shared.tracks.TrackLoadException; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; +import org.moparforia.shared.tracks.filesystem.FileSystemStatsManager; import java.io.IOException; import java.net.InetSocketAddress; @@ -152,10 +154,10 @@ public void addPlayer(Player p) { } public void start() { - //TrackStore.LoadTracks(); // gr8 piece of engineering right here! try { - new TrackManager().load(); - } catch (IOException e) { + FileSystemTrackManager.getInstance().load(); + FileSystemStatsManager.getInstance().load(); + } catch (TrackLoadException | IOException e) { System.err.println("Unable to load tracks: " + e.getMessage()); e.printStackTrace(); return; diff --git a/server/src/main/java/org/moparforia/server/db/Database.java b/server/src/main/java/org/moparforia/server/db/Database.java index f4b818d6..bf0d391c 100644 --- a/server/src/main/java/org/moparforia/server/db/Database.java +++ b/server/src/main/java/org/moparforia/server/db/Database.java @@ -4,7 +4,7 @@ //import org.mongodb.morphia.Datastore; //import org.mongodb.morphia.Morphia; //import org.moparforia.server.util.SHA1; -//import org.moparforia.shared.Track; +//import org.moparforia.shared.tracks.Track; // ///** // * User: Johan diff --git a/server/src/main/java/org/moparforia/server/game/gametypes/GolfGame.java b/server/src/main/java/org/moparforia/server/game/gametypes/GolfGame.java index e525489d..a846d572 100644 --- a/server/src/main/java/org/moparforia/server/game/gametypes/GolfGame.java +++ b/server/src/main/java/org/moparforia/server/game/gametypes/GolfGame.java @@ -8,14 +8,20 @@ import org.moparforia.server.game.Player; import org.moparforia.server.net.Packet; import org.moparforia.server.net.PacketType; -import org.moparforia.server.track.TrackManager; import org.moparforia.shared.Tools; -import org.moparforia.shared.Track; - -import java.util.ArrayList; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackManager; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; +import org.moparforia.shared.tracks.filesystem.FileSystemStatsManager; +import org.moparforia.shared.tracks.stats.StatsManager; +import org.moparforia.shared.tracks.stats.TrackStats; + +import java.util.List; import java.util.regex.Matcher; public abstract class GolfGame extends Game { + protected static final TrackManager manager = FileSystemTrackManager.getInstance(); + protected static final StatsManager statsManager = FileSystemStatsManager.getInstance(); public static final int STROKES_UNLIMITED = 0; public static final int STROKETIMEOUT_INFINITE = 0; @@ -39,7 +45,7 @@ public abstract class GolfGame extends Game { protected int trackScoring; protected int trackScoringEnd; protected int numPlayers; - protected ArrayList tracks; + protected List tracks; protected int[] playerStrokes; protected int currentTrack = 0; @@ -67,7 +73,7 @@ public GolfGame(int gameId, LobbyType lobbyId, String name, String password, boo } - public abstract ArrayList initTracks(); + public abstract List initTracks(); @Override public boolean handlePacket(Server server, Player player, Matcher message) { @@ -112,21 +118,22 @@ protected void reset() { public void startGame() { writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "start"))); - StringBuilder buff = new StringBuilder(); // STRING BUILDER IS BEING USEDS FAGGOTS + StringBuilder buff = new StringBuilder(); for (int i = 0; i < getPlayers().size(); i++) { buff.append("t"); } playStatus = buff.toString().replace("t", "f"); - + TrackStats track = statsManager.getStats(tracks.get(0)); writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "resetvoteskip"))); - writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "starttrack", buff.toString(), gameId, tracks.get(0)))); + writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "starttrack", buff.toString(), gameId, track))); writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "startturn", 0))); } public void rateTrack(String rating) { - tracks.get(currentTrack).rate(rating); + statsManager.rate(getCurrentTrack(), Integer.parseInt(rating)); } + public void sendGameInfo(Player player) { Channel c = player.getChannel(); c.write(new Packet(PacketType.DATA, Tools.tabularize("status", "game"))); @@ -180,64 +187,12 @@ protected int getNextPlayer(String s) { protected void updateStats() { + getPlayers().stream() + .filter(p -> !p.hasSkipped()) + .forEach(player -> { + statsManager.addScore(getCurrentTrack(), player.getNick(), playerStrokes[getPlayerId(player)]); + }); - int players = 0; - int strokes = 0; - for (Player p : getPlayers()) { - if (!p.hasSkipped()) { - players++; - strokes += playerStrokes[getPlayerId(p)]; - } - } - if (players > 0) { // if someone didnt skip, update stats. - TrackManager.addStrokes(tracks.get(currentTrack), players, strokes); - checkRecord(); - } - - TrackManager.save(tracks.get(currentTrack)); - - } - - protected boolean checkRecord() { - if (getLeadingPlayer().hasSkipped()) { - return false; - } - - Track track = tracks.get(currentTrack); - if ("".equals(track.getFirstBestPlayer()) || track.getBestPar() > getLeadingPar()) { // first ever record OR beat previous - TrackManager.updateStats(track, getLeadingPlayer(), getLeadingPar(), true); - return true; - } else if (track.getBestPar() == getLeadingPar()) { // matched par, latest - TrackManager.updateStats(track, getLeadingPlayer(), getLeadingPar(), false); - return true; - } - return false; - } - - protected Player getLeadingPlayer() { - return playerForId(getLeadingPlayerId()); - } - - protected int getLeadingPlayerId() { - int minValue = playerStrokes[0]; - int id = 0; - for (int i = 1; i < playerStrokes.length; i++) { - if (playerStrokes[i] < minValue && !playerForId(id).hasSkipped()) { - minValue = playerStrokes[i]; - id = i; - } - } - return id; - } - - protected int getLeadingPar() { - int minValue = playerStrokes[0]; - for (int i = 1; i < playerStrokes.length; i++) { - if (playerStrokes[i] < minValue) { - minValue = playerStrokes[i]; - } - } - return minValue; } protected void nextTrack() { @@ -246,7 +201,7 @@ protected void nextTrack() { strokeCounter = 0; currentTrack++; if (currentTrack < tracks.size()) { // there is a next track - Track t = tracks.get(currentTrack); + TrackStats track = statsManager.getStats(tracks.get(currentTrack)); StringBuilder buff = new StringBuilder(); for (int i = 0; i < getPlayers().size(); i++) { playerStrokes[i] = 0; // todo proper id's @@ -255,7 +210,7 @@ protected void nextTrack() { } playStatus = buff.toString().replace("t", "f"); writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "resetvoteskip"))); - writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "starttrack", buff.toString(), gameId, t))); + writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "starttrack", buff.toString(), gameId, track))); writeAll(new Packet(PacketType.DATA, Tools.tabularize("game", "startturn", getFirstPlayer()))); } else { endGame(); @@ -285,7 +240,7 @@ public void voteSkip(Player p) { numberOfSkippers++; playerStrokes[getPlayerId(player)] = maxStrokes + 1; } - buff.append(playerStrokes[getPlayerId(player)] + "\t"); + buff.append(playerStrokes[getPlayerId(player)]).append("\t"); } if (needsChange && playerCount() > 1 && numberOfSkippers < playerCount()) { @@ -307,4 +262,7 @@ public String getGameString() { waterEvent, collision, trackScoring, trackScoringEnd, getPlayers().size()); } + private Track getCurrentTrack() { + return tracks.get(currentTrack); + } } diff --git a/server/src/main/java/org/moparforia/server/game/gametypes/golf/ChampionshipGame.java b/server/src/main/java/org/moparforia/server/game/gametypes/golf/ChampionshipGame.java index 75c41ca3..96474896 100644 --- a/server/src/main/java/org/moparforia/server/game/gametypes/golf/ChampionshipGame.java +++ b/server/src/main/java/org/moparforia/server/game/gametypes/golf/ChampionshipGame.java @@ -1,13 +1,13 @@ package org.moparforia.server.game.gametypes.golf; -import org.moparforia.shared.Track; +import org.moparforia.shared.tracks.Track; import org.moparforia.server.game.Lobby; import org.moparforia.server.game.LobbyType; import org.moparforia.server.game.Player; import org.moparforia.server.game.gametypes.GolfGame; -import org.moparforia.server.track.TrackManager; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; -import java.util.ArrayList; +import java.util.List; /** @@ -32,8 +32,8 @@ public ChampionshipGame(Player p, int gameId, int championshipId) { } } - public ArrayList initTracks() { - ArrayList tracks = TrackManager.getTrackSet(championshipId); + public List initTracks() { + List tracks = FileSystemTrackManager.getInstance().getTrackSet(championshipId); this.numberOfTracks = tracks.size(); // important we set this depending on set. return tracks; } diff --git a/server/src/main/java/org/moparforia/server/game/gametypes/golf/DualGame.java b/server/src/main/java/org/moparforia/server/game/gametypes/golf/DualGame.java index d4f90c4d..e26d7dda 100644 --- a/server/src/main/java/org/moparforia/server/game/gametypes/golf/DualGame.java +++ b/server/src/main/java/org/moparforia/server/game/gametypes/golf/DualGame.java @@ -1,16 +1,16 @@ package org.moparforia.server.game.gametypes.golf; -import org.moparforia.shared.Track; +import org.moparforia.shared.tracks.Track; import org.moparforia.server.game.LobbyType; import org.moparforia.server.game.Player; import org.moparforia.server.game.gametypes.GolfGame; import org.moparforia.server.net.Packet; import org.moparforia.server.net.PacketType; -import org.moparforia.server.track.TrackCategory; -import org.moparforia.server.track.TrackManager; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; import org.moparforia.shared.Tools; -import java.util.ArrayList; +import java.util.List; /** * dual shizzle @@ -35,8 +35,8 @@ public DualGame(Player challenger, Player challenged, int gameId, int numberOfTr } @Override - public ArrayList initTracks() { - return TrackManager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); + public List initTracks() { + return manager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); } @Override diff --git a/server/src/main/java/org/moparforia/server/game/gametypes/golf/MultiGame.java b/server/src/main/java/org/moparforia/server/game/gametypes/golf/MultiGame.java index 90341120..0b99edd7 100644 --- a/server/src/main/java/org/moparforia/server/game/gametypes/golf/MultiGame.java +++ b/server/src/main/java/org/moparforia/server/game/gametypes/golf/MultiGame.java @@ -1,17 +1,16 @@ package org.moparforia.server.game.gametypes.golf; -import org.moparforia.shared.Track; import org.moparforia.server.game.Lobby; import org.moparforia.server.game.LobbyType; import org.moparforia.server.game.Player; import org.moparforia.server.game.gametypes.GolfGame; import org.moparforia.server.net.Packet; import org.moparforia.server.net.PacketType; -import org.moparforia.server.track.TrackCategory; -import org.moparforia.server.track.TrackManager; import org.moparforia.shared.Tools; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; -import java.util.ArrayList; +import java.util.List; /** * multiplayerzzzz @@ -74,7 +73,7 @@ public boolean removePlayer(Player player) { } @Override - public ArrayList initTracks() { - return TrackManager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); + public List initTracks() { + return manager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); } } diff --git a/server/src/main/java/org/moparforia/server/game/gametypes/golf/TrainingGame.java b/server/src/main/java/org/moparforia/server/game/gametypes/golf/TrainingGame.java index bdeb0f7f..ee432da9 100644 --- a/server/src/main/java/org/moparforia/server/game/gametypes/golf/TrainingGame.java +++ b/server/src/main/java/org/moparforia/server/game/gametypes/golf/TrainingGame.java @@ -1,14 +1,14 @@ package org.moparforia.server.game.gametypes.golf; -import org.moparforia.shared.Track; +import org.moparforia.shared.tracks.Track; import org.moparforia.server.game.Lobby; import org.moparforia.server.game.LobbyType; import org.moparforia.server.game.Player; import org.moparforia.server.game.gametypes.GolfGame; -import org.moparforia.server.track.TrackCategory; -import org.moparforia.server.track.TrackManager; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; -import java.util.ArrayList; +import java.util.List; /** * training init @@ -31,7 +31,7 @@ public TrainingGame(Player p, int gameId, int tracksType, int numberOfTracks, in } @Override - public ArrayList initTracks() { - return TrackManager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); + public List initTracks() { + return manager.getRandomTracks(numberOfTracks, TrackCategory.getByTypeId(tracksType)); } } diff --git a/server/src/main/java/org/moparforia/server/net/packethandlers/golf/LobbyHandler.java b/server/src/main/java/org/moparforia/server/net/packethandlers/golf/LobbyHandler.java index 219d2090..69368245 100644 --- a/server/src/main/java/org/moparforia/server/net/packethandlers/golf/LobbyHandler.java +++ b/server/src/main/java/org/moparforia/server/net/packethandlers/golf/LobbyHandler.java @@ -7,11 +7,12 @@ import org.moparforia.server.net.Packet; import org.moparforia.server.net.PacketHandler; import org.moparforia.server.net.PacketType; -import org.moparforia.server.track.TrackManager; -import org.moparforia.server.track.TrackSet; import org.moparforia.shared.Tools; +import org.moparforia.shared.tracks.TrackManager; +import org.moparforia.shared.tracks.TrackSet; +import org.moparforia.shared.tracks.filesystem.FileSystemTrackManager; -import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -20,6 +21,8 @@ * 12.6.2013 */ public class LobbyHandler implements PacketHandler { + private static final TrackManager manager = FileSystemTrackManager.getInstance(); + @Override public PacketType getType() { return PacketType.DATA; @@ -55,13 +58,13 @@ public boolean handle(Server server, Packet packet, Matcher message) { } lobby.addPlayer(player, Lobby.JOIN_TYPE_NORMAL); } else if (message.group(1).equals("tracksetlist")) { - ArrayList trackSets = TrackManager.getTrackSets(); + List trackSets = manager.getTrackSets(); String[][] tracksInfo = new String[trackSets.size()][11]; for (int i = 0; i < trackSets.size(); i++) { TrackSet trackSet = trackSets.get(i); tracksInfo[i][0] = trackSet.getName(); tracksInfo[i][1] = String.valueOf(trackSet.getDifficulty().getId()); - tracksInfo[i][2] = String.valueOf(trackSet.getFilenames().size()); + tracksInfo[i][2] = String.valueOf(trackSet.getTracks().size()); for (int j = 3; j < 11; j++) {//todo track records tracksInfo[i][j] = j % 2 == 0 ? "1" : "No one"; } diff --git a/server/src/main/java/org/moparforia/server/track/TrackManager.java b/server/src/main/java/org/moparforia/server/track/TrackManager.java deleted file mode 100644 index 9c3b637c..00000000 --- a/server/src/main/java/org/moparforia/server/track/TrackManager.java +++ /dev/null @@ -1,204 +0,0 @@ -package org.moparforia.server.track; - -import org.mongodb.morphia.Datastore; -import org.moparforia.server.game.Player; -import org.moparforia.shared.Track; - -import java.io.IOException; -import java.nio.file.*; -import java.util.*; -import java.util.concurrent.*; - -/** - * Playforia - * 18.6.2013 - */ -public class TrackManager { - - private static ArrayList tracks; - private static ArrayList trackSets; - private static boolean hasLoaded; - private static final ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();; - - - public final void load() throws IOException { - tracks = new ArrayList(); - loadTracks(); - loadTrackSets(); - hasLoaded = true; -// schedule.scheduleAtFixedRate(new TrackUpdater(),5,5,TimeUnit.MINUTES); - } - -// private class TrackUpdater implements Runnable { -// -// @Override -// public void run() { -// Datastore ds = Database.getInstance().getDatastore(); -// ArrayList list = (ArrayList) ds.find(Track.class).asList(); -// int oldSize = tracks.size(); -// for(Track t : list) { -// if(!tracks.contains(t)) { -// tracks.add(t); -// } -// } -// -// System.out.println("Added "+ (tracks.size() - oldSize) +" tracks."); -// } -// } - - - //private static final void loadTracks() { - //Datastore ds = Database.getInstance().getDatastore(); - //ArrayList list = (ArrayList) ds.find(Track.class).asList(); - //tracks.addAll(list); - // System.out.println("Loaded "+tracks.size()+" tracks."); - //} - - public static void addStrokes(Track track, int numPlayers, int strokes) { - tracks.get(tracks.indexOf(track)).addStrokes(numPlayers, strokes); - } - - public static void save(Track track) { - //Database.getInstance().getDatastore().save(track); - } - - public static void updateStats(Track track, Player player, int par, boolean newRecord) { - int index = tracks.indexOf(track); - long time = (System.currentTimeMillis() / 1000L) * 1000; - - if (newRecord) { - tracks.get(index).addRecord(player.getNick(), par, time, true); - } - - tracks.get(index).addRecord(player.getNick(), par, time, false); - tracks.get(index).incBestPar(); - - } - - private static final void loadTracks() throws IOException { - // only problem i can think of is that this will overwrite maps with the same name in a type - tracks = new ArrayList(); // tracks = new ArrayList(); - FileSystem fs = FileSystems.getDefault(); - int counter = 0; - for (TrackCategory type : TrackCategory.values()) { - //if (type == TrackCategory.ALL || type == TrackCategory.CUSTOM || type == TrackCategory.UNKNOWN) { - if (type == TrackCategory.ALL || type == TrackCategory.UNKNOWN) { - continue; - } - Path tracksPath = fs.getPath("tracks", type.getDir()); - DirectoryStream directoryStream = Files.newDirectoryStream(tracksPath, new DirectoryStream.Filter() { - @Override - public boolean accept(Path entry) throws IOException { - return entry.toString().endsWith(".track"); - } - }); - for (Path filePath : directoryStream) { - String name = null, author = null, data = null; - int[] scoreInfo = null, ratings = null; - String[] bestPlayers = null, dummy = null; - long[] bestTimes = null; - Scanner scanner = new Scanner(filePath); - while (scanner.hasNextLine()) { - String line = scanner.nextLine().trim(); - if (line.startsWith("V ")) { - // hi - } else if (line.startsWith("S ")) { - // hi? get on it, watson - } else if (line.startsWith("A ")) { - author = line.substring(2); - } else if (line.startsWith("N ")) { - name = line.substring(2); - } else if (line.startsWith("T ")) { - data = line.substring(2); - } else if (line.startsWith("I ")) { - dummy = line.substring(2).split(","); - scoreInfo = new int[dummy.length]; - for (int i = 0; i < dummy.length; i++) { - scoreInfo[i] = Integer.parseInt(dummy[i]); - } - } else if (line.startsWith("B ") || line.startsWith("L ")) { - dummy = line.substring(2).split(","); - bestPlayers = new String[dummy.length]; - bestTimes = new long[dummy.length]; - int idx = line.startsWith("B ") ? 0 : 1; - bestPlayers[idx] = dummy[0]; - bestTimes[idx] = Long.valueOf(dummy[1]); - } else if (line.startsWith("R ")) { - dummy = line.substring(2).split(","); - ratings = new int[dummy.length]; - for (int i = 0; i < dummy.length; i++) { - ratings[i] = Integer.valueOf(dummy[i]); - } - } - } - String filename = filePath.getFileName().toString(); - filename = filename.substring(0, filename.lastIndexOf('.')); - tracks.add(new Track(name,author,data,type.getId(),scoreInfo,bestPlayers,bestTimes,ratings)); - } - } - System.out.println("Loaded " + tracks.size() + " tracks"); - } - - private static final void loadTrackSets() throws IOException { - if (tracks == null) { - return; - } - trackSets = new ArrayList(); - FileSystem fs = FileSystems.getDefault(); - DirectoryStream directoryStream = Files.newDirectoryStream(fs.getPath("tracks", "sets"), new DirectoryStream.Filter() { - @Override - public boolean accept(Path entry) throws IOException { - return entry.getFileName().toString().endsWith(".trackset"); - } - }); - for (Path filePath : directoryStream) { - Scanner scanner = new Scanner(filePath); - String setName = scanner.nextLine(); - TrackSetDifficulty trackSetDifficulty = TrackSetDifficulty.valueOf(scanner.nextLine()); - ArrayList fileNames = new ArrayList(); - while (scanner.hasNextLine()) { - String line = scanner.nextLine().trim(); - if (!line.isEmpty()) { - fileNames.add(line); - } - } - trackSets.add(new TrackSet(setName, trackSetDifficulty, fileNames)); - } - System.out.println("Loaded " + trackSets.size() + " track sets"); - } - - - public static final ArrayList getRandomTracks(int number, TrackCategory type) { - if (number < 1 || number > 20) { - return null; - } - ArrayList usedTracks = new ArrayList();// horrible - for (Track track : tracks) { - //if (TrackCategory.getByTypeId(track.getCategory()) == TrackCategory.ALL || TrackCategory.getByTypeId(track.getCategory()) == type) { - if (type == TrackCategory.ALL || TrackCategory.getByTypeId(track.getCategory()) == type) { - usedTracks.add(track); - } - } - ArrayList randomTracks = new ArrayList(number); - for (int i = 0; i < number; i++) { - Track track = usedTracks.get((new Random()).nextInt(usedTracks.size())); - while (randomTracks.contains(track)) { - track = usedTracks.get((new Random()).nextInt(usedTracks.size())); - } - randomTracks.add(track); - } - return randomTracks; - } - - public static final ArrayList getTrackSet(int setId) { - return new ArrayList(); - } - - public static final ArrayList getTrackSets() { - return new ArrayList(); - } - - public boolean hasLoaded() { - return hasLoaded; - } -} diff --git a/server/src/main/java/org/moparforia/server/util/StockTrackUploader.java b/server/src/main/java/org/moparforia/server/util/StockTrackUploader.java index 9daa597f..2cf4e54c 100644 --- a/server/src/main/java/org/moparforia/server/util/StockTrackUploader.java +++ b/server/src/main/java/org/moparforia/server/util/StockTrackUploader.java @@ -1,12 +1,7 @@ package org.moparforia.server.util; -import com.mongodb.BasicDBObjectBuilder; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import org.moparforia.shared.Track; -import org.moparforia.server.track.TrackCategory; -import org.moparforia.server.track.TrackSet; -import org.moparforia.server.track.TrackSetDifficulty; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; import java.io.IOException; import java.nio.file.*; @@ -62,7 +57,7 @@ public boolean accept(Path entry) throws IOException { data = line.substring(2); } } - tracks.add(new Track(name, author, data, type.getId())); + tracks.add(new Track(name, author, data, type)); } } //uploadTracks(); diff --git a/shared/pom.xml b/shared/pom.xml index c7eb7f3e..aa13a303 100644 --- a/shared/pom.xml +++ b/shared/pom.xml @@ -15,19 +15,35 @@ - org.mongodb - mongo-java-driver + info.picocli + picocli provided + - org.mongodb.morphia - morphia - provided + org.junit.jupiter + junit-jupiter-engine + test - info.picocli - picocli - provided + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + com.github.marschall + memoryfilesystem + test + + + org.softsmithy.lib + softsmithy-lib-core + test diff --git a/shared/shared.iml b/shared/shared.iml index 9d9c4dbf..b771df8a 100644 --- a/shared/shared.iml +++ b/shared/shared.iml @@ -5,14 +5,26 @@ + + - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shared/src/main/java/org/moparforia/shared/Tools.java b/shared/src/main/java/org/moparforia/shared/Tools.java index a960ce43..d5512cc6 100644 --- a/shared/src/main/java/org/moparforia/shared/Tools.java +++ b/shared/src/main/java/org/moparforia/shared/Tools.java @@ -1,10 +1,5 @@ package org.moparforia.shared; -import com.mongodb.BasicDBList; - -import java.util.Iterator; -import java.util.List; - public class Tools { private static String toString(Object o) { @@ -40,12 +35,4 @@ public static String triangelize(Object... args) {// hhhehehe public static String commaize(Object... args) {// hhhehehe return izer(",", args); } - - public static int[] toIntArray(BasicDBList list) { - int[] ret = new int[list.size()]; - int i = 0; - for (Object e : list) - ret[i++] = (Integer) e; - return ret; - } } \ No newline at end of file diff --git a/shared/src/main/java/org/moparforia/shared/Track.java b/shared/src/main/java/org/moparforia/shared/Track.java deleted file mode 100644 index 97f9763e..00000000 --- a/shared/src/main/java/org/moparforia/shared/Track.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.moparforia.shared; - -import com.mongodb.BasicDBList; -import com.mongodb.BasicDBObject; -import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Property; - -import java.util.Arrays; - -/** - * track shit - */ -@Entity(value="tracks", noClassnameStored=true) -public class Track { - - @Id - public ObjectId id; - - @Property("name") - private String trackName; - @Property("author") - private String author; - @Property("data") - private String trackData; - @Property("category") - private int category; - - @Property("num_completions") - private int totalNumberOfAttempts; - @Property("num_strokes") - private int totalStrokes; - @Property("num_best_strokes") - private int bestPar; - @Property("num_best_players") - private int numberOfBestPar; - - @Property("first_best_name") - private String firstBestPlayer; - @Property("first_best_time") - private long firstBestTime; - @Property("last_best_name") - private String lastBestPlayer; - @Property("last_best_time") - private long lastBestTime; - @Property("ratings") - private int[] ratings; - - /** - * man thats an ugly constructor - * - * @param name name of this track - * @param author the author homie that wrote this track - * @param data the track data string - * @param scoreInfo totalattempts=[0] completions=[1] - * bestPar[2] numberOfBestPar[3] - * @param bestPlayers first[0] last[1] - * @param bestTimes first[0] last[1] - * @param ratings should be a 10 element array with with number of votes 1-10 in each. - */ - public Track(String name, String author, String data, int category, int[] scoreInfo, - String[] bestPlayers, long[] bestTimes, int[] ratings) { - this.trackName = name; - this.author = author; - this.trackData = data; - this.category = category; - this.totalNumberOfAttempts = scoreInfo[0]; - this.totalStrokes = scoreInfo[1]; - this.bestPar = scoreInfo[2]; - this.numberOfBestPar = scoreInfo[3]; - this.firstBestPlayer = bestPlayers[0]; - this.lastBestPlayer = bestPlayers[1]; - this.firstBestTime = bestTimes[0]; - this.lastBestTime = bestTimes[1]; - this.ratings = ratings; - } - - public Track(String name, String author, String data, int category) { - this.trackName = name; - this.author = author; - this.trackData = data; - this.category = category; - } - - public Track() { - this("mophiatest", "fc", "data", - 7, new int[]{0, 0, 0, 0}, new String[]{"", ""}, new long[]{0, 0}, - new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); - } - - public static Track fromDb(BasicDBObject object) throws Exception{ - String name = object.getString("name"); - String author = object.getString("author"); - int category; - try { - category = object.getInt("category"); - } catch (Exception e) { - category = 7; - } - String data = object.getString("data"); - - int numCompletions = object.getInt("num_completions"); - int numAttempts = object.getInt("num_strokes"); - int bestPar = object.getInt("num_best_strokes"); - int numBestPar = object.getInt("num_best_players"); - - int[] scoreInfo = new int[]{numCompletions, numAttempts, bestPar, numBestPar}; - - String firstBestPlayer = object.getString("first_best_name"); - String lastBestPlayer = object.getString("last_best_name"); - String[] bestPlayers = new String[]{firstBestPlayer, lastBestPlayer}; - - long firstBestTime = object.getLong("first_best_time"); - long lastBestTime = object.getLong("last_best_time"); - long[] bestTimes = new long[]{firstBestTime, lastBestTime}; - - BasicDBList ratings = (BasicDBList) object.get("ratings"); - return new Track(name, author, data, category, scoreInfo, bestPlayers, bestTimes, Tools.toIntArray(ratings)); - } - - - /** - * new Track(1,"Boats and hoes","fc","B3A48DE48DE48DE48DE48DE48DEBAQQ46D3EG13DEG14DEG13D5E13DEE14DEE13D5E13DEE14DEE13D5E13DEE14DEE13D5E13DEE6DBMAQE6DEE13D5ECAAE11DEE6DBAQQE6DEE11DCBA6E13DBOAQE6DEE6DBOAQE13D5E21DEE21D5E21DEE21D5E21DEE21D5E21DEE21D4E46DEE48DE48DE48DE48DE48DE48D", - * new int[]{2629492,7166639,2,1191141},new String[] {"fc","Tiikoni"}, new int[]{1034197200000,1370170660930}, - * new int[]{1630,567,647,835,1148,3945,3755,3346,2924,2672,21566}); - */ - - public ObjectId getId() { - return id; - } - - public String getName() { - return trackName; - } - - public String getAuthor() { - return author; - } - - public String getData() { - return trackData; - } - - public int getCategory() { - return category; - } - - public String getMap() { - return trackData; - } - - public void setMap(String data) { - this.trackData = data; - } - - public int getBestPar() { - return bestPar; - } - - public int getNumberOfBestPar() { - return numberOfBestPar; - } - - public String getFirstBestPlayer() { - return firstBestPlayer; - } - - public long getFirstBestTime() { - return firstBestTime; - } - - public String getLastBestPlayer() { - return lastBestPlayer; - } - - public long getLastBestTime() { - return lastBestTime; - } - - public int getTotalStrokes() { - return totalStrokes; - } - - public void addStrokes(int numberOfPlayers, int strokesToAdd) { - totalNumberOfAttempts += numberOfPlayers; - totalStrokes += strokesToAdd; - } - - public void incBestPar() { - numberOfBestPar++; - } - - public void rate(String rating) { - ratings[Integer.parseInt(rating) - 1]++; - } - - public void addRecord(String nick, int par, long time, boolean newRecord) { - System.out.println("add record: " + getName() + " by " + nick + " by getting a " + par); - - if (newRecord) { - numberOfBestPar = 0; - this.firstBestPlayer = nick; - this.firstBestTime = time; - this.bestPar = par; - } else { - this.lastBestPlayer = nick; - this.lastBestTime = time; - } - } - - public void resetStats() { - Arrays.fill(ratings, 0); - firstBestPlayer = ""; - lastBestPlayer = ""; - firstBestTime = 0; - lastBestTime = 0; - } - - private String ratingsToString() { - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < ratings.length - 1; i++) { - buffer.append(ratings[i]).append(","); - } - return buffer.toString() + ratings[ratings.length - 1]; - } - - /** - * {track ID} - * V 1 - * A {AUTHOR OF TRACK} - * N {NAME OF TRACK} - * T data - * I {NUMBER OF PLAYERS TO COMLETE},{NUMBER OF shots?},{BEST NUMBER OF STROKES},{NUMBER OF PEOPLE THAT GOT BEST STROKE} - * B {FIRST BEST PAR PLAYER},{UNIX TIMESTAMP OF FIRST BEST PAR}000 - * L {LAST BEST PAR PLAYER},{UNIX TIMESTAMP OF LAST BEST PAR}000 - * R {RATING: 0},{RATING: 1},{RATING: 2},{RATING: 3},{RATING: 4},{RATING: 5},{RATING: 6},{RATING: 7},{RATING: 8},{RATING: 9},{RATING: 10} - */ - @Override - public String toString() { - if (firstBestPlayer == null || lastBestPlayer == null || - firstBestPlayer.equals("") || lastBestPlayer.equals("")) { // no top score!??!? - return Tools.tabularize( - "V 1", - "A " + author, - "N " + trackName, - "T " + trackData, - "I " + Tools.commaize(totalNumberOfAttempts, totalStrokes, bestPar, numberOfBestPar), - "R " + ratingsToString()); - } - return Tools.tabularize( - "V 1", - "A " + author, - "N " + trackName, - "T " + trackData, - "I " + Tools.commaize(totalNumberOfAttempts, totalStrokes, bestPar, numberOfBestPar), - "B " + Tools.commaize(firstBestPlayer, firstBestTime), - "L " + Tools.commaize(lastBestPlayer, lastBestTime), - "R " + ratingsToString()); - } - - /** - * {track ID} - * V 1 - * A {AUTHOR OF TRACK} - * N {NAME OF TRACK} - * T data - */ - public String toSaveString() { - return Tools.tabularize( - "V 1", - "A " + author, - "N " + trackName, - "T " + trackData); - } - - @Override - public boolean equals(Object o) { - if (o == null || !(o instanceof Track)) { - return false; - } - Track t = (Track) o; - return trackName.equals(t.trackName) && author.equals(t.author); - } -} \ No newline at end of file diff --git a/shared/src/main/java/org/moparforia/shared/tracks/Track.java b/shared/src/main/java/org/moparforia/shared/tracks/Track.java new file mode 100644 index 00000000..6c1692ae --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/Track.java @@ -0,0 +1,73 @@ +package org.moparforia.shared.tracks; + +import java.util.Objects; + +/** + * track shit + */ +public class Track { + + private final String track; + + private final String author; + + private String map; + + private final TrackCategory category; + + /** + * man thats an ugly constructor + * + * @param name name of this track + * @param author the author homie that wrote this track + * @param map the track data/map string + */ + public Track(String name, String author, String map, TrackCategory category) { + this.track = name; + this.author = author; + this.map = map; + this.category = category; + } + + /** + * new Track(1,"Boats and hoes","fc","B3A48DE48DE48DE48DE48DE48DEBAQQ46D3EG13DEG14DEG13D5E13DEE14DEE13D5E13DEE14DEE13D5E13DEE14DEE13D5E13DEE6DBMAQE6DEE13D5ECAAE11DEE6DBAQQE6DEE11DCBA6E13DBOAQE6DEE6DBOAQE13D5E21DEE21D5E21DEE21D5E21DEE21D5E21DEE21D4E46DEE48DE48DE48DE48DE48DE48D", + * new int[]{2629492,7166639,2,1191141},new String[] {"fc","Tiikoni"}, new int[]{1034197200000,1370170660930}, + * new int[]{1630,567,647,835,1148,3945,3755,3346,2924,2672,21566}); + */ + + public String getName() { + return track; + } + + public String getAuthor() { + return author; + } + + public TrackCategory getCategory() { + return category; + } + + public String getMap() { + return map; + } + + public void setMap(String data) { + this.map = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Track)) return false; + Track track = (Track) o; + return getName().equals(track.getName()) && + getAuthor().equals(track.getAuthor()) && + getMap().equals(track.getMap()) && + getCategory() == track.getCategory(); + } + + @Override + public int hashCode() { + return Objects.hash(track, getAuthor(), map, getCategory()); + } +} \ No newline at end of file diff --git a/server/src/main/java/org/moparforia/server/track/TrackCategory.java b/shared/src/main/java/org/moparforia/shared/tracks/TrackCategory.java similarity index 54% rename from server/src/main/java/org/moparforia/server/track/TrackCategory.java rename to shared/src/main/java/org/moparforia/shared/tracks/TrackCategory.java index 090f4ad0..134e5703 100644 --- a/server/src/main/java/org/moparforia/server/track/TrackCategory.java +++ b/shared/src/main/java/org/moparforia/shared/tracks/TrackCategory.java @@ -1,4 +1,4 @@ -package org.moparforia.server.track; +package org.moparforia.shared.tracks; /** * Playforia @@ -6,13 +6,19 @@ */ public enum TrackCategory { - //UNKNOWN("?", -1), ALL("-", 0), BASIC("basic", 1), TRADITIONAL("traditional", 2), MODERN("modern", 3), HIO("hio", 4), SHORT("short", 5), LONG("long", 6), CUSTOM("custom", 7); - UNKNOWN("?", -1), ALL("-", 0), BASIC("basic", 1), TRADITIONAL("traditional", 2), MODERN("modern", 3), HIO("hio", 4), SHORT("short", 5), LONG("long", 6); + UNKNOWN("?", -1), + ALL("-", 0), + BASIC("basic", 1), + TRADITIONAL("traditional", 2), + MODERN("modern", 3), + HIO("hio", 4), + SHORT("short", 5), + LONG("long", 6); private final String dir; private final int id; - private TrackCategory(String dir, int id) { + TrackCategory(String dir, int id) { this.dir = dir; this.id = id; } diff --git a/shared/src/main/java/org/moparforia/shared/tracks/TrackLoadException.java b/shared/src/main/java/org/moparforia/shared/tracks/TrackLoadException.java new file mode 100644 index 00000000..a388afee --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/TrackLoadException.java @@ -0,0 +1,11 @@ +package org.moparforia.shared.tracks; + +public class TrackLoadException extends Exception { + public TrackLoadException(String s) { + super(s); + } + + public TrackLoadException(String s, Throwable throwable) { + super(s, throwable); + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/TrackManager.java b/shared/src/main/java/org/moparforia/shared/tracks/TrackManager.java new file mode 100644 index 00000000..2608ff57 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/TrackManager.java @@ -0,0 +1,45 @@ +package org.moparforia.shared.tracks; + +import java.util.List; + +/** + * Interface representing Manager that provides Tracks + */ +public interface TrackManager { + + /** + * @param track Saves said track + */ + void save(Track track); + + /** + * Returns random tracks + * + * @param limit Maximum tracks that should be returned, if there are not enough tracks, it can be return less + * @param type What category should be track belong to + * @return Random tracks + */ + List getRandomTracks(int limit, TrackCategory type); + + + List getTracks(); + + TrackSet getTrackSet(String name); + + List getTrackSets(); + + Track findTrackByName(String name); + + List findAllByCategory(TrackCategory category); + + /** + * Loads all Tracks and TrackSets + * @throws TrackLoadException Exception + */ + void load() throws TrackLoadException; + + /** + * @return True, if manager is loaded + */ + boolean isLoaded(); +} diff --git a/server/src/main/java/org/moparforia/server/track/TrackSet.java b/shared/src/main/java/org/moparforia/shared/tracks/TrackSet.java similarity index 69% rename from server/src/main/java/org/moparforia/server/track/TrackSet.java rename to shared/src/main/java/org/moparforia/shared/tracks/TrackSet.java index fe9808ba..1adad433 100644 --- a/server/src/main/java/org/moparforia/server/track/TrackSet.java +++ b/shared/src/main/java/org/moparforia/shared/tracks/TrackSet.java @@ -1,6 +1,6 @@ -package org.moparforia.server.track; +package org.moparforia.shared.tracks; -import java.util.ArrayList; +import java.util.List; /** * Playforia @@ -10,12 +10,12 @@ public class TrackSet { private String name; private TrackSetDifficulty difficulty; - private ArrayList filenames; + private List tracks; - public TrackSet(String name, TrackSetDifficulty difficulty, ArrayList filenames) { + public TrackSet(String name, TrackSetDifficulty difficulty, List tracks) { this.name = name; this.difficulty = difficulty; - this.filenames = filenames; + this.tracks = tracks; } public String getName() { @@ -26,8 +26,8 @@ public TrackSetDifficulty getDifficulty() { return difficulty; } - public ArrayList getFilenames() { - return filenames; + public List getTracks() { + return tracks; } public boolean equals(Object o) { @@ -35,6 +35,6 @@ public boolean equals(Object o) { return false; } TrackSet t = (TrackSet) o; - return difficulty == t.difficulty && name.equals(t.name) && filenames.equals(t.filenames); + return difficulty == t.difficulty && name.equals(t.name) && tracks.equals(t.tracks); } } diff --git a/server/src/main/java/org/moparforia/server/track/TrackSetDifficulty.java b/shared/src/main/java/org/moparforia/shared/tracks/TrackSetDifficulty.java similarity index 86% rename from server/src/main/java/org/moparforia/server/track/TrackSetDifficulty.java rename to shared/src/main/java/org/moparforia/shared/tracks/TrackSetDifficulty.java index 335fd8cd..7239c732 100644 --- a/server/src/main/java/org/moparforia/server/track/TrackSetDifficulty.java +++ b/shared/src/main/java/org/moparforia/shared/tracks/TrackSetDifficulty.java @@ -1,4 +1,4 @@ -package org.moparforia.server.track; +package org.moparforia.shared.tracks; /** * Playforia diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManager.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManager.java new file mode 100644 index 00000000..e554a27d --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManager.java @@ -0,0 +1,76 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.stats.TrackStats; +import org.moparforia.shared.tracks.stats.StatsManager; + +import java.io.IOException; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class FileSystemStatsManager implements StatsManager { + protected final FileSystem fileSystem; + + private static FileSystemStatsManager instance; + + private Map stats; + + public FileSystemStatsManager(FileSystem fileSystem) { + this.fileSystem = fileSystem; + } + + public static FileSystemStatsManager getInstance() { + if (instance == null) { + instance = new FileSystemStatsManager(FileSystems.getDefault()); + } + return instance; + } + + public void load() throws IOException { + stats = loadStats(); + } + + public Map loadStats() throws IOException { + List tracks = new ArrayList<>(); + for (TrackCategory type : TrackCategory.values()) { + if (type == TrackCategory.ALL || type == TrackCategory.UNKNOWN) { + continue; + } + Path tracksPath = fileSystem.getPath("tracks", type.getDir()); + DirectoryStream directoryStream = Files.newDirectoryStream(tracksPath, + entry -> entry.toString().endsWith(".track")); + for (Path filePath : directoryStream) { + tracks.add(TrackFileParser.parseStats(filePath, type)); + } + } + return tracks.stream() + .collect(Collectors.toMap(TrackStats::getTrack, stats -> stats)); + } + + @Override + public TrackStats getStats(Track track) { + if (!stats.containsKey(track)) { + throw new IllegalArgumentException("Couldn't find stats for track " + track.getName() + " on filesystem"); + } + return stats.get(track); + } + + @Override + public void rate(Track track, int rating) { + // No-op, FileSystemStats are readonly + } + + @Override + public void addScore(Track track, String player, int par) { + // No-op, FileSystemStats are readonly + } + + @Override + public boolean isReadOnly() { + return true; + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java new file mode 100644 index 00000000..4dcedc7b --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java @@ -0,0 +1,192 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.moparforia.shared.Tools; +import org.moparforia.shared.tracks.*; +import org.moparforia.shared.utils.CollectorUtils; + +import java.io.IOException; +import java.nio.file.*; +import java.util.*; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Playforia + * 18.6.2013 + */ +public class FileSystemTrackManager implements TrackManager { + protected final FileSystem fileSystem; + + private final Logger logger = Logger.getLogger(FileSystemTrackManager.class.getName()); + private static FileSystemTrackManager instance; + + private List tracks; + private List trackSets; + private boolean hasLoaded; + + public FileSystemTrackManager(FileSystem fileSystem) { + this.fileSystem = fileSystem; + } + + public static FileSystemTrackManager getInstance() { + if (instance == null) { + instance = new FileSystemTrackManager(FileSystems.getDefault()); + } + return instance; + } + + @Override + public void load() throws TrackLoadException { + try { + tracks = loadTracks(); + logger.info("Loaded " + tracks.size() + " tracks"); + trackSets = loadTrackSets(); + logger.info("Loaded " + trackSets.size() + " track sets"); + } catch (IOException e) { + throw new TrackLoadException("Unable to load tracks and tracksets", e); + } + + hasLoaded = true; + } + + @Override + public boolean isLoaded() { + return hasLoaded; + } + + + public void save(Track track) { + // No-op, this implementation is only read-only + } + + public static String convertTrack(Track track) { + return Tools.tabularize( + "V 1", + "A " + track.getAuthor(), + "N " + track.getName(), + "T " + track.getMap()); + } + + private List loadTracks() throws IOException { + List tracks = new ArrayList<>(); + for (TrackCategory type : TrackCategory.values()) { + if (type == TrackCategory.ALL || type == TrackCategory.UNKNOWN) { + continue; + } + + Path tracksPath = fileSystem.getPath("tracks", type.getDir()); + if (!Files.exists(tracksPath)) { + logger.warning("Directory tracks/" + type.getDir() + " for type " + type + " was not found, ignoring."); + continue; + } + + DirectoryStream directoryStream = Files.newDirectoryStream(tracksPath, + entry -> entry.toString().endsWith(".track")); + for (Path filePath : directoryStream) { + tracks.add(TrackFileParser.parseTrack(filePath, type)); + } + } + return tracks; + } + + private List loadTrackSets() throws IOException { + List trackSets = new ArrayList<>(); + Path sets = fileSystem.getPath("tracks", "sets"); + if (!Files.exists(sets)) { + logger.warning("Can't load tracksets, directory tracks/sets does not exists, ignoring."); + return trackSets; + } + + DirectoryStream directoryStream = Files.newDirectoryStream(sets, + entry -> entry.getFileName().toString().endsWith(".trackset")); + for (Path filePath : directoryStream) { + Scanner scanner = new Scanner(filePath); + String setName = scanner.nextLine(); + TrackSetDifficulty trackSetDifficulty = TrackSetDifficulty.valueOf(scanner.nextLine()); + List trackNames = new ArrayList(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + if (!line.isEmpty()) { + trackNames.add(line); + } + } + + // Convert fileNames to already loaded tracks + List tracks = getTracks().stream() + .filter(track -> trackNames.contains(track.getName())) + .collect(Collectors.toList()); + if (tracks.size() < 1) { + logger.warning("TrackSet " + setName + " has no valid tracks associated with it, ignoring"); + continue; + } + // This is not 100% correct since the tracks contain lot of duplicates + if (tracks.size() < trackNames.size()) { + List found_tracks = tracks.stream().map(Track::getName).collect(Collectors.toList()); + trackNames.removeAll(found_tracks); + logger.warning("TrackSet " + setName + " contains not existing tracks (" + Arrays.toString(trackNames.toArray()) + ")"); + } + trackSets.add(new TrackSet(setName, trackSetDifficulty, tracks)); + } + return trackSets; + } + + + public List getRandomTracks(int limit, TrackCategory type) { + if (limit < 1) { + throw new IllegalArgumentException("Number of tracks must be at least 1"); + } + + return getTracks().stream() + .filter(track -> track.getCategory() == type || type == TrackCategory.ALL) + .collect(CollectorUtils.toShuffledStream()) + .limit(limit) + .collect(Collectors.toList()); + + } + + @Override + public List getTracks() { + return tracks; + } + + @Override + public TrackSet getTrackSet(String name) { + return getTrackSets() + .stream() + .filter(trackset -> trackset.getName().equals(name)) + .findFirst() + .orElse(null); + } + + // Tracksets are broken as far as I know, so this should cause no harm, + // kept because ChampionsipGame still needs it + public List getTrackSet(int number) { + return Collections.emptyList(); + } + + public List getTrackSets() { + return trackSets; + } + + @Override + public Track findTrackByName(String name) { + return getTracks().stream() + .filter(track -> track.getName().equals(name)) + .findFirst() + .orElse(null); + } + + @Override + public List findAllByCategory(TrackCategory category) { + if (category.equals(TrackCategory.ALL)) { + return getTracks(); + } + return getTracks().stream() + .filter(track -> track.getCategory().equals(category)) + .collect(Collectors.toList()); + } + + public boolean hasLoaded() { + return hasLoaded; + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackStats.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackStats.java new file mode 100644 index 00000000..851fa7ab --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackStats.java @@ -0,0 +1,121 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.moparforia.shared.Tools; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.stats.TrackStats; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Arrays; + +public class FileSystemTrackStats implements TrackStats { + private final int totalAttempts; + private final int strokes; + private final int bestPar; + private final double bestParPercentage; + private final int numberOfBestPar; + private final String bestPlayer; + private final LocalDate bestTime; + private final int[] ratings; + private final Track track; + + public FileSystemTrackStats(int totalAttempts, int strokes, int bestPar, double percentageofBestPar, + int numberOfBestPar, String bestPlayer, LocalDate bestTime, int[] ratings, Track track) { + this.totalAttempts = totalAttempts; + this.strokes = strokes; + this.bestPar = bestPar; + this.bestParPercentage = percentageofBestPar; + this.numberOfBestPar = numberOfBestPar; + this.bestPlayer = bestPlayer; + this.bestTime = bestTime; + this.ratings = ratings; + this.track = track; + } + + @Override + public Track getTrack() { + return track; + } + + @Override + public int getTotalAttempts() { + return totalAttempts; + } + + @Override + public int getTotalStrokes() { + return strokes; + } + + @Override + public int getBestPar() { + return bestPar; + } + + @Override + public double getPercentageOfBestPar() { + return bestParPercentage; + } + + @Override + public String getBestPlayer() { + return bestPlayer; + } + + @Override + public LocalDate getBestParTime() { + return bestTime; + } + + @Override + public int[] getRatings() { + return ratings; + } + + @Override + public double getAverageRating() { + double sum = 0; + int count = 0; + for (int i = 0; i < ratings.length; i++) { + sum += i * ratings[i]; + count += ratings[i]; + } + return sum / count; + } + + @Override + public int getNumberOfRatings() { + return Arrays.stream(ratings).sum(); + } + + // Old compatibility stuff + + private String ratingsToString() { + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < ratings.length - 1; i++) { + buffer.append(ratings[i]).append(","); + } + return buffer.toString() + ratings[ratings.length - 1]; + } + + @Override + public String toString() { + if (getBestPar() < 0) { + return Tools.tabularize( + "V 1", + "A " + getTrack().getAuthor(), + "N " + getTrack().getName(), + "T " + getTrack().getMap(), + "I " + Tools.commaize(getTotalAttempts(), getTotalStrokes(), getBestPar(), numberOfBestPar), + "R " + ratingsToString()); + } + return Tools.tabularize( + "V 1", + "A " + getTrack().getAuthor(), + "N " + getTrack().getName(), + "T " + getTrack().getMap(), + "I " + Tools.commaize(getTotalAttempts(), getTotalStrokes(), getBestPar(), numberOfBestPar), + "B " + Tools.commaize(getBestPlayer(), bestTime.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()), + "R " + ratingsToString()); + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/TrackFileParser.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/TrackFileParser.java new file mode 100644 index 00000000..2d2e2958 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/TrackFileParser.java @@ -0,0 +1,108 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.filesystem.lineparser.BestTimeLineParser; +import org.moparforia.shared.tracks.filesystem.lineparser.RatingsLineParser; +import org.moparforia.shared.tracks.filesystem.lineparser.ScoreInfoLineParser; +import org.moparforia.shared.tracks.filesystem.lineparser.SimpleLineParser; +import org.moparforia.shared.tracks.stats.TrackStats; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Class for parsing Track file in format like this. + * Allows for parsing of similar files or adding custom properties. + * + * V 1 + * A {AUTHOR OF TRACK} + * N {NAME OF TRACK} + * T data + * I {NUMBER OF PLAYERS TO COMPLETE},{NUMBER OF STROKES},{BEST NUMBER OF STROKES},{NUMBER OF PEOPLE THAT GOT BEST STROKE} + * B {FIRST BEST PAR PLAYER},{UNIX TIMESTAMP OF FIRST BEST PAR}000 + * L {LAST BEST PAR PLAYER},{UNIX TIMESTAMP OF LAST BEST PAR}000 + * R {RATING: 0},{RATING: 1},{RATING: 2},{RATING: 3},{RATING: 4},{RATING: 5},{RATING: 6},{RATING: 7},{RATING: 8},{RATING: 9},{RATING: 10} + */ +public class TrackFileParser { + private static final Map BASE_PARSERS; + private static final Map STATS_PARSERS; + + // Initialize parser with all LineParsers + static + { + HashMap tmp_map = new HashMap<>(); + tmp_map.put('A', new SimpleLineParser("author")); + tmp_map.put('N', new SimpleLineParser("name")); + tmp_map.put('T', new SimpleLineParser("data")); + BASE_PARSERS = Collections.unmodifiableMap(tmp_map); + tmp_map.put('R', new RatingsLineParser()); + tmp_map.put('I', new ScoreInfoLineParser()); + tmp_map.put('B', new BestTimeLineParser("bestTime", "bestPlayer")); +// Uncomment if you want to also parse lastTime and lastPlayer +// tmp_map.put("L", new BestTimeLineParser("lastTime", "lastPlayer")); + STATS_PARSERS = Collections.unmodifiableMap(tmp_map); + } + + public static Map parse(Map parser, Path path) throws IOException { + return Files.lines(path) + .map(line -> parseLine(parser, line)) + .flatMap(m -> m.entrySet().stream()) + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue) + ); + } + + private static Map parseLine(Map parsers, String line) { + Character character = line.charAt(0); + if (parsers.containsKey(character)) { + return parsers.get(character).apply(line.substring(2)); + } + return Collections.emptyMap(); + } + + public static Track parseTrack(Path path, TrackCategory category) throws IOException { + Map parsed = parse(BASE_PARSERS, path); + return constructTrack(category, parsed); + } + + private static Track constructTrack(TrackCategory category, Map parsed) { + String name = (String) parsed.get("name"); + String author = (String) parsed.get("author"); + String data = (String) parsed.get("data"); + return new Track(name, author, data, category); + } + + public static TrackStats parseStats(Path path, TrackCategory category) throws IOException { + Map parsed = parse(STATS_PARSERS, path); + Track track = constructTrack(category, parsed); + int[] ratings = (int[]) parsed.getOrDefault("ratings", new int[10]); + int attempts = (int) parsed.getOrDefault("attempts", 0); + int strokes = (int) parsed.getOrDefault("strokes", 0); + int bestPar = (int) parsed.getOrDefault("bestPar", -1); + + // Widen int primitive type, to support integer division resulting in double + int numberOfBestPar = (Integer) parsed.getOrDefault("numberOfBestPar", 0); + LocalDate bestTime = (LocalDate) parsed.getOrDefault("bestTime", LocalDate.now()); + String bestPlayer = (String) parsed.getOrDefault("bestPlayer", ""); + + double bestParPercentage = (double) numberOfBestPar / attempts; + + return new FileSystemTrackStats( + attempts, strokes, bestPar, bestParPercentage, numberOfBestPar, bestPlayer, bestTime, ratings, track + ); + } + + /** + * Class that takes line and returns map of parsed parameters + */ + public interface LineParser extends Function> {} +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/BestTimeLineParser.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/BestTimeLineParser.java new file mode 100644 index 00000000..693e0225 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/BestTimeLineParser.java @@ -0,0 +1,31 @@ +package org.moparforia.shared.tracks.filesystem.lineparser; + +import org.moparforia.shared.tracks.filesystem.TrackFileParser; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.HashMap; +import java.util.Map; + +public class BestTimeLineParser implements TrackFileParser.LineParser{ + + private String date_parameter; + private String player_parameter; + + public BestTimeLineParser(String date_parameter, String player_parameter) { + this.date_parameter = date_parameter; + this.player_parameter = player_parameter; + } + + @Override + public Map apply(String s) { + Map map = new HashMap<>(); + String[] parts = s.split(","); + map.put(player_parameter, parts[0]); + long epochMilli = Long.parseLong(parts[1]); + LocalDate date = Instant.ofEpochMilli(epochMilli).atZone(ZoneId.systemDefault()).toLocalDate(); + map.put(date_parameter, date); + return map; + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/RatingsLineParser.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/RatingsLineParser.java new file mode 100644 index 00000000..1f806972 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/RatingsLineParser.java @@ -0,0 +1,18 @@ +package org.moparforia.shared.tracks.filesystem.lineparser; + +import org.moparforia.shared.tracks.filesystem.TrackFileParser; + +import java.util.Collections; +import java.util.Map; + +public class RatingsLineParser implements TrackFileParser.LineParser { + @Override + public Map apply(String line) { + String[] parts = line.split(","); + int[] ratings = new int[parts.length]; + for (int i = 0; i < parts.length; i++) { + ratings[i] = Integer.parseInt(parts[i]); + } + return Collections.singletonMap("ratings", ratings); + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/ScoreInfoLineParser.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/ScoreInfoLineParser.java new file mode 100644 index 00000000..799ca1f1 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/ScoreInfoLineParser.java @@ -0,0 +1,19 @@ +package org.moparforia.shared.tracks.filesystem.lineparser; + +import org.moparforia.shared.tracks.filesystem.TrackFileParser; + +import java.util.HashMap; +import java.util.Map; + +public class ScoreInfoLineParser implements TrackFileParser.LineParser { + @Override + public Map apply(String s) { + Map map = new HashMap<>(); + String[] scoreInfo = s.split(","); + map.put("attempts", Integer.parseInt(scoreInfo[0])); + map.put("strokes", Integer.parseInt(scoreInfo[1])); + map.put("bestPar", Integer.parseInt(scoreInfo[2])); + map.put("numberOfBestPar", Integer.parseInt(scoreInfo[3])); + return map; + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/SimpleLineParser.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/SimpleLineParser.java new file mode 100644 index 00000000..80cf025e --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/lineparser/SimpleLineParser.java @@ -0,0 +1,24 @@ +package org.moparforia.shared.tracks.filesystem.lineparser; + +import org.moparforia.shared.tracks.filesystem.TrackFileParser; + +import java.util.Collections; +import java.util.Map; + + +/** + * Line parser that returns entire contents of the line + */ +public class SimpleLineParser implements TrackFileParser.LineParser { + + private final String parameter_name; + + public SimpleLineParser(String parameter_name) { + this.parameter_name = parameter_name; + } + + @Override + public Map apply(String line) { + return Collections.singletonMap(parameter_name, line); + } +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/stats/StatsManager.java b/shared/src/main/java/org/moparforia/shared/tracks/stats/StatsManager.java new file mode 100644 index 00000000..db88b20d --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/stats/StatsManager.java @@ -0,0 +1,32 @@ +package org.moparforia.shared.tracks.stats; + +import org.moparforia.shared.tracks.Track; + +public interface StatsManager { + + /** + * @param track Track + * @return Statistics object for said track + */ + TrackStats getStats(Track track); + + /** + * Rates track + * + * @param rating Rating from 1 to 10 + */ + void rate(Track track, int rating); + + /** + * Add score to the player for that tracks + * + * @param player Name of the player that scored par + * @param par Par + */ + void addScore(Track track, String player, int par); + + /** + * @return If the class support also setting score or is just meant for their retrieval + */ + boolean isReadOnly(); +} diff --git a/shared/src/main/java/org/moparforia/shared/tracks/stats/TrackStats.java b/shared/src/main/java/org/moparforia/shared/tracks/stats/TrackStats.java new file mode 100644 index 00000000..04d17654 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/tracks/stats/TrackStats.java @@ -0,0 +1,66 @@ +package org.moparforia.shared.tracks.stats; + +import org.moparforia.shared.tracks.Track; + +import java.time.LocalDate; + +/** + * Interface that represent all the statistics for specific track, class is interface so it supports lazy loading + */ +public interface TrackStats { + + /** + * @return Track that these stats are for + */ + Track getTrack(); + + /** + * @return Total number of attempts across all the games + */ + int getTotalAttempts(); + + /** + * @return Total number of strobes across all the games + */ + int getTotalStrokes(); + + /** + * @return Get best par achieved on this track + */ + int getBestPar(); + + /** + * @return Percentage of best par among all the completions + */ + double getPercentageOfBestPar(); + + /** + * @return Name of the player who achieved best score first + */ + String getBestPlayer(); + + /** + * @return Date of the first best par achieved + */ + LocalDate getBestParTime(); + + + /** + * Returns ratings of this track. + * Index is representing the actual rating and the value is number of ratings of that value + * @return Array of all the ratings of size 10 + */ + int[] getRatings(); + + /** + * @return Average rating of this track + */ + double getAverageRating(); + + /** + * @return Total number of ratings fo this track + */ + int getNumberOfRatings(); + + +} diff --git a/shared/src/main/java/org/moparforia/shared/utils/CollectorUtils.java b/shared/src/main/java/org/moparforia/shared/utils/CollectorUtils.java new file mode 100644 index 00000000..443daba4 --- /dev/null +++ b/shared/src/main/java/org/moparforia/shared/utils/CollectorUtils.java @@ -0,0 +1,17 @@ +package org.moparforia.shared.utils; + +import java.util.Collections; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CollectorUtils { + + public static Collector> toShuffledStream() { + return Collectors.collectingAndThen(Collectors.toList(), collected -> { + Collections.shuffle(collected); + return collected.stream(); + }); + } + +} diff --git a/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemExtension.java b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemExtension.java new file mode 100644 index 00000000..e13da80f --- /dev/null +++ b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemExtension.java @@ -0,0 +1,78 @@ +package org.moparforia.shared.tracks.filesystem; + +import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.softsmithy.lib.nio.file.CopyFileVisitor; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +public class FileSystemExtension implements BeforeEachCallback, AfterEachCallback { + private static final String[] DIRS = { + "/tracks/modern", + "/tracks/traditional", + "/tracks/short", + "/tracks/long", + "/tracks/basic", + "/tracks/hio", + "/tracks/sets", + }; + + private FileSystem fileSystem; + + FileSystem getFileSystem() { + return this.fileSystem; + } + + void copyFile(String src) throws IOException, URISyntaxException { + URL resource = getClass().getClassLoader().getResource(src); + Path srcPath = Paths.get(resource.toURI()); + Path targetPath = fileSystem.getPath(src); + CopyFileVisitor.copy(srcPath, targetPath); + } + + /** + * Copies directory from resource folder into InMemory file system + * @param dir Path to the dir + */ + void copyDir(String dir) throws IOException, URISyntaxException { + URL resource = getClass().getClassLoader().getResource(dir); + Path base = Paths.get(getClass().getClassLoader().getResource("").toURI()); + List files = Files.walk(Paths.get(resource.toURI())) + .filter(Files::isRegularFile) + .collect(Collectors.toList()); + for (Path file : files) { + Path relative_path = fileSystem.getPath(base.relativize(file).toString()); + CopyFileVisitor.copy(base.resolve(file), relative_path); + } + } + + void copyAll() throws IOException, URISyntaxException { + copyDir("tracks/"); + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + if (this.fileSystem != null) { + this.fileSystem.close(); + } + } + + @Override + public void beforeEach(ExtensionContext extensionContext) throws Exception { + this.fileSystem = MemoryFileSystemBuilder.newEmpty().build("test"); + for (String DIR : DIRS) { + Path path = fileSystem.getPath(DIR); + Files.createDirectories(path); + } + } +} diff --git a/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManagerTest.java b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManagerTest.java new file mode 100644 index 00000000..fad2fdec --- /dev/null +++ b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemStatsManagerTest.java @@ -0,0 +1,62 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.moparforia.shared.tracks.Track; +import org.moparforia.shared.tracks.TrackCategory; +import org.moparforia.shared.tracks.stats.TrackStats; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.FileSystem; + +import static java.lang.Double.NaN; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FileSystemStatsManagerTest { + private final double PRECISION = 0.001d; + @RegisterExtension + final FileSystemExtension extension = new FileSystemExtension(); + + FileSystemStatsManager statsManager; + + Track single = new Track("4 da Crew", "Aither", "Data", TrackCategory.MODERN); + Track empty_stats = new Track("SprtTrack", "Sprt", "Data", TrackCategory.MODERN); + + @BeforeEach + void beforeEach() { + FileSystem fileSystem = this.extension.getFileSystem(); + statsManager = new FileSystemStatsManager(fileSystem); + } + + @Test + void testSimpleLoad() throws IOException, URISyntaxException { + extension.copyDir("tracks/modern"); + + statsManager.load(); + + TrackStats stats = statsManager.getStats(single); + assertEquals("Sprt", stats.getBestPlayer()); + assertEquals(537, stats.getTotalAttempts()); + assertEquals(11734, stats.getTotalStrokes()); + assertEquals(4, stats.getBestPar()); + assertEquals(0.039 , stats.getPercentageOfBestPar(), PRECISION); + assertEquals(7.752, stats.getAverageRating(), PRECISION); + } + + @Test + void testEmptyStats() throws IOException, URISyntaxException { + extension.copyDir("tracks/modern"); + + statsManager.load(); + TrackStats stats = statsManager.getStats(empty_stats); + assertEquals("", stats.getBestPlayer()); + assertEquals(0, stats.getTotalAttempts()); + assertEquals(0, stats.getTotalStrokes()); + assertEquals(-1, stats.getBestPar()); + assertEquals(NaN , stats.getPercentageOfBestPar(), PRECISION); + assertEquals(NaN, stats.getAverageRating(), PRECISION); + + } +} \ No newline at end of file diff --git a/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManagerTest.java b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManagerTest.java new file mode 100644 index 00000000..7e633dd4 --- /dev/null +++ b/shared/src/test/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManagerTest.java @@ -0,0 +1,113 @@ +package org.moparforia.shared.tracks.filesystem; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.moparforia.shared.tracks.*; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.FileSystem; + +import static org.junit.jupiter.api.Assertions.*; + +class FileSystemTrackManagerTest { + @RegisterExtension + final FileSystemExtension extension = new FileSystemExtension(); + + TrackManager manager; + + @BeforeEach + void beforeEach() { + FileSystem fileSystem = this.extension.getFileSystem(); + manager = new FileSystemTrackManager(fileSystem); + } + + @Test + void testSimpleTrackLoad() throws TrackLoadException, IOException, URISyntaxException { + extension.copyDir("tracks/modern/"); + + manager.load(); + assertEquals(6, manager.getTracks().size()); + assertEquals(0, manager.getTrackSets().size()); + + assertEquals(6, manager.findAllByCategory(TrackCategory.MODERN).size()); + assertEquals(6, manager.findAllByCategory(TrackCategory.ALL).size()); + assertEquals(0, manager.findAllByCategory(TrackCategory.BASIC).size()); + + assert manager.isLoaded(); + + Track track = manager.findTrackByName("4 da Crew"); + assertNotNull(track); + assertEquals("Data", track.getMap()); + assertEquals("Aither", track.getAuthor()); + assertEquals("4 da Crew", track.getName()); + assertEquals("Aither", track.getAuthor()); + } + + /** + * Loads modern tracks + * Loads Tracksets + * + * oakpark.trackset should be ignored because it didnt contain any loaded tracks + * birchwood.trackset should be have only 2 songs + */ + @Test + void testSimpleSetLoad() throws IOException, URISyntaxException, TrackLoadException { + extension.copyDir("tracks/modern/"); + extension.copyDir("tracks/sets/"); + + manager.load(); + assertEquals(1, manager.getTrackSets().size()); + TrackSet birchwood = manager.getTrackSet("Birchwood"); + + assertEquals(2, birchwood.getTracks().size()); + assertEquals("Birchwood", birchwood.getName()); + assertEquals(TrackSetDifficulty.EASY, birchwood.getDifficulty()); + + } + + @Test + void testLoad() throws IOException, URISyntaxException, TrackLoadException { + extension.copyAll(); + + manager.load(); + assertEquals(18, manager.getTracks().size()); + assertEquals(2, manager.getTrackSets().size()); + + assertEquals(6, manager.findAllByCategory(TrackCategory.MODERN).size()); + assertEquals(18, manager.findAllByCategory(TrackCategory.ALL).size()); + assertEquals(2, manager.findAllByCategory(TrackCategory.SHORT).size()); + assertEquals(3, manager.findAllByCategory(TrackCategory.TRADITIONAL).size()); + assertEquals(2 ,manager.findAllByCategory(TrackCategory.HIO).size()); + assertEquals(3, manager.findAllByCategory(TrackCategory.BASIC).size()); + + assert manager.isLoaded(); + } + + @Test + void testRandomTracksIncorrectLimit() { + assertThrows(IllegalArgumentException.class, () -> manager.getRandomTracks(0, TrackCategory.ALL)); + assertThrows(IllegalArgumentException.class, () -> manager.getRandomTracks(-1, TrackCategory.ALL)); + } + + @Test + void testRandomTracks() throws IOException, URISyntaxException, TrackLoadException { + extension.copyAll(); + + manager.load(); + assertEquals(3, manager.getRandomTracks(3, TrackCategory.MODERN).size()); + assertEquals(6, manager.getRandomTracks(50, TrackCategory.MODERN).size()); + } + + /** + * This means that if randomTracks is called on a category that doesn't have any tracks it will return empty list + */ + @Test + void testRandomTracksEmpty() throws IOException, URISyntaxException, TrackLoadException { + extension.copyDir("tracks/modern"); + + manager.load(); + assertEquals(0, manager.getRandomTracks(50, TrackCategory.BASIC).size()); + } +} \ No newline at end of file diff --git a/shared/src/test/resources/tracks/basic/Aither-4_da_Crew.track b/shared/src/test/resources/tracks/basic/Aither-4_da_Crew.track new file mode 100644 index 00000000..d59d3ace --- /dev/null +++ b/shared/src/test/resources/tracks/basic/Aither-4_da_Crew.track @@ -0,0 +1,9 @@ +V 1 +A Aither +N 4 da Crew +T BAQQ47DBJMQBAMMBAKA14DB3A15DBAKA4DB3A4DBAGA4DBJQIFEE14DE15DE4DE4DE4DBAIA3E14DE15DE4DE4DE4D4E14DE15DE4DE4DE4DEEBIMQBAQQ5DBNUQBAUA4DBPUQBAQQDBJAQE6DBMAQEDDBIAQBAQQ7DBNAQE3DE4DEEBAQQBIQIBAIA12DBJQIFBAIA6DBAQQGDDBAQQBIQAHDH4DH4DE4D3EBAIA14DEE6DEEDDEIDDE4DE4DE4D4E14DEE6DEEDDEEDDE4DE4DE4D4E8DBMIQE4DEE6DEEDDEEDDE4DE4DE4D4E8DBAQQE4DEE6DEEDDEEDDE4DE3DBPAQBAQQ3DBNGQ4E8DEE4DEE6DEEDDEEDDE4DE4DH4D4E8DEE4DEE6DEEDDEEDDE4DE4DE4D4E8DEE4DEE6DEEDDEEDDE4DE4DE4D4E8DEE4DEE6DEEDDEBLQAEDE4DE4DE4D4E8DEE4DEE6DEEDDE8DBNAQE3DE4D4E8DEEBCIQEDDEE6DEEDDEBIQAHDH4DH4DE4D4E8DEE4DEE6DEEDDEB3ACJAEE4DE4DE4D4E8DEE4DEE6DEEDDEECAAEE4DE4DE4D3EBLQBBABBDDCNBGDDBKQBEBABB4DEE6DEBLWIEBKWIEBLQAFDE4DE4DE4DBKWIEE9DBKAQB3A4DEE6DEBAWADDE8DCQA4DBAQQ3DBNWQBAWAEEBIQAB3A13DEG6DEBIWAB3A20DBJWAEEB3ACBAE12DEECIAEBBAMECMAEEG22D3E14DEE6DEBLQAE20DBKQAEEBAMM14DEG6DBLMQF22DBKMQ +S ftft14 +I 537,11734,4,21 +B Grange,1280012972607 +L advanced,1369922144542 +R 8,2,0,3,4,2,8,6,1,4,55 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/basic/Aither-5th_Street.track b/shared/src/test/resources/tracks/basic/Aither-5th_Street.track new file mode 100644 index 00000000..bda68dd5 --- /dev/null +++ b/shared/src/test/resources/tracks/basic/Aither-5th_Street.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N 5th Street +T BYMQBAMM15DBbMQBZMQBaQMBAQQDDBYQMBZMQBAMMDDBbMQGBbQMBAQQ17DBAMMBaMQEDBEMABSAMB3A4DBAGA9DB3A13DBAKA8DB3A3DEBbMQFDB3A7DE9DE13DE8DE3DEBYQMEBEMAE7DE9DE7DBMAQE4DBLAQBAQQ6DBKAQE3DEBZQMEB3A8DE9DE7DBAQQE17DEBAQQBEMAE8DBLAQBAQQ7DBKAQE7DEE3DBEABBA3BFABEDDBEABBA3BFABE4DEEBRAME9DBHAMBJQMEBIQAB3A12DBOAQE3DBA3BDBCFEDDBA3BDBCFE4DEEB3A10DBTAMBAMMEB3A18DBHABFBGABBEABBA3BFABBHABFBGABE4D3E10D4E21DBA3BDBCFI7D3E11DBHAMEE15DBYAPEDBYAPEDBHABFBGABE7D3E11DBTAMEE3DBPAQBAQQ8DBJAQEDBaAPBYAPFBEAQBAQQ6DBFAQE3D3E12DEE10DBJQABCQAEDE3DBAPADBGQPBEQAI9D3E12DEE11DBLAQFEEDDBEAQEBGQPBEQPB3A10D3E12DEE12DIEEDDBAQQBGQPBEQPIE10D3E12DEE13DEEDDEBEQAB3A12D3E11DBEAQBGAQE5DBIAQBALA6DEEDDEG13D3E10DBEAQBGAQI5DBEACBAQQE6DEEDDEE13D3E9DBEAQBGAQICOAEDBQACEBEACBACAEE6DEECPA3E13D3E8DBEAQBGAQIDBQACBEACBACABQCBGDBECBEE6DEEDBEAQBGAQE13D3E7DBEAQBAQQ11DE6DEEBEAQBGAQB3A14D3E27DEBEAQBGAQI15DEEBFABE26DEBGAQB3A15DBEAQEEBA3BQABE23DCBAEEGCAAE13DBEAQBAQQBSMQEE3DBFABE21DBKQAEE14DBEAQBAQQBAMMDE4DBZQMBYMQBAMMBaMQBbQMBAQQ35DBRMQED +I 1469,9040,2,118 +B Karvanoppa,1279962093653 +L Karvanoppa,1370297436571 +R 3,0,1,1,2,3,5,4,4,3,52 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/basic/Aither-____Not_Tragedies.track b/shared/src/test/resources/tracks/basic/Aither-____Not_Tragedies.track new file mode 100644 index 00000000..e318797d --- /dev/null +++ b/shared/src/test/resources/tracks/basic/Aither-____Not_Tragedies.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N ... Not Tragedies +T BANA24DBAQQBXQSDDBAQQ18DBANAEDBQNABXNQBAQQ7DBAIADDBAQQBAEA8DEB3ADDEG16D3EBTNACMAB3A7DEEDDEE8DBWAQEDDEE14DCNA4EBWQNB3A8DEEDDEE8DB3A3DEE16D3EBAQQE8DEEDDEE8DE3DEE3DBWQAEDBBAUBWAQE3DBWQABAIADD5E3DBWQAE3DEEDDEE8DE3DEE3DBAQQBBAUBCAUFBAQQE3DBAQQGDD5E3DBAQQE3DEEDDEE8DBWQAEDDEE3DEGDFEE3DEHDD5E3DEE3DEEDDEE8DBAQQEDDEE3DEBAEADDEE3DEGDD5E3DEEDCBA3EDDEE3DBDEQE3DEEDDEE3DEGDDEE3DEHDD5E3DEE3DEEDDEE8DEEDDEE3DEHDDEE3DEGBBAQG5E3DEBAWA3DEEDDEE8DEEDDEE3DEGDDEE3DEHDD5E9DEDDEE7DBEEAEEDDEE3DEHDDEE3DEGDD5E9DEDDEE5DBEEAB3ADEEDDEE3DEGDDEE3DEHDD4EBRAQE8DECPI3E5DB3ADDEEDDEE3DEHDDEE3DEGDD3EBWQNBRANE8DEDDEE4DBEEAEDDEEDDEE3DEGDDEE3DEHDD3EDBHNABQANBQAQE6DEDDEEDDBEEAB3A4DEEDDBWQAE3DEHDDEE3DBWAQGDD3EDDBXQNBAQQ7DEDDEEDDB3A5DCWAE7DEGDDEE7D3E10DEEDDEEDBEEAE3DCAAECWOE7DEHDDEE7D3E10DEEDDEBEEAB3A7DHE7DEGDDEE7D3EBAQQ10DEDDE19DHDDE5DCDADD4EB3A9DEDDB3A31D3EDECOAE7DEDDE31D3EHE9DEDDE31D4E9DBXQNBANACTNGBXQNBAQQ31DEE48D +I 647,11824,4,2 +B Challenge,1282655862335 +L Vegan Fox,1314355650348 +R 5,2,2,0,0,8,5,11,4,6,41 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/hio/Aither-Blunt_Force_Trauma.track b/shared/src/test/resources/tracks/hio/Aither-Blunt_Force_Trauma.track new file mode 100644 index 00000000..6f2cd215 --- /dev/null +++ b/shared/src/test/resources/tracks/hio/Aither-Blunt_Force_Trauma.track @@ -0,0 +1,7 @@ +V 1 +A Aither +N Blunt Force Trauma +T BAQQ16DBSQMG30DEBAMMDEG11DBJQMFBIQMBAMM12DBHMQE15DEB3ADBSAQG4DBAIA7DEBAMMDBIMGBAGA11DBAVADB3A12D3E7DE7DEEDBAGA12DEDE12D3E7DE7DEEDE12DEDE12D3E7DE7DEEDE12DEDE12D3E6DBFAQE7DEEDB3A5DBAQQDB3A4DBAQQ8DCTPDDBAQQ3DEE6DBAQQE7DEEDE5DEDE4DEDBAIA12D3E6DEE7DEEDEDDCMAEDEDE4DEDE12DEBTQOBAOA6DEE7DEEDBLMAE4DEDE4DEDE12D3E6DEE7DEE7DBZQMBaQMBLMAE3DEDE12DEBAQQB3A6DEE7DEBLQME5DBKQMBYQMBbQMBIMAE3DEDE6DBXAQ3DED3E6DEE7DBHAQF8DBKAQB3A4DEDE12D3E6DEE7DB3A15DEDE12D3E6DEE7DCTAE14DEDE12D3EDDBTAQBAQQ3DE7DEE14DEDEDBXAQ3DE6D3E6DEE7DB3A15DEDE12D3E6DEE7DBFAQE14DEDE12D3E6DEE7DBAQQ17DE7DBXAQDDEDEE3DBRAQEDDBFQABFIQE6DECBAHBWVAG4DBWQAG3DBWQAGDDE12DEEH7DBRQABRIQE5DEB3ADEE4DEE3DEEDDE7DCNIE3DEECAAE5DBGQABGIQH6DEEDBWQAE9DEEDDE12DEEH6DBAQQBAIA7DEE4DBWQAE3DIE5DE12D3E5DBKQAEE7DEE4DEE3DEE5DE3DBXAQ3DE4DEE7DBKMQBAMM7DEG4DBWQMBAQQ10DBAMM12DE +I 97,1861,6,1 +B Hirdy,1370025533956 +R 2,0,0,0,0,0,1,2,0,0,4 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/hio/Aither-BoomBiddyByeBye.track b/shared/src/test/resources/tracks/hio/Aither-BoomBiddyByeBye.track new file mode 100644 index 00000000..64b30e39 --- /dev/null +++ b/shared/src/test/resources/tracks/hio/Aither-BoomBiddyByeBye.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N BoomBiddyByeBye +T BAQQ5DBQQLDBAQQ4DBAMM13DBAQQG5DBAQQ14DEB3A3DBGLABALABELAB3A3DEBFIABAIA12DEBSIMBHIME3DEB3A3DBEABBABBDBEBAB3ADBFBABA3BHBA3ECOAEBGLABALABELAB3A4DEGDBFIAE7DBTIQBAQQ4DBRIQBAIABSIM3EDBEABBABBDBEBAB3A4DFF3EDBGLABALABELAI5DE4DB3ABFIAE4DBTIAB3A4DBRIAEDBFMIEEBEABBA3BEBAI7D4EBGLABALABELAI10DEEDDBFIAEDDEE4DEEDDEEBA3BEBAI8D3EBGLABALABELAI11DEE4DBFIAEBTIQBAQQ4DBRIQEDDEBEABEI9DBFBAEBTQLBALABELAI12DEE6DBFIAIDEG5DEBA3BEBAE10DEEBELAB3A13DEE8DBFIAEE5DEEB3A11DEBAQQB3A6DBQAQE6DEE9DEE5D3E11D3E6DBAQQE6DBSAQE9DEGBFIAE3D3E7DBQAQEDD3E6DEE17DEEDDBFIAED3E6DBGEABAQQECPA4E6DEE17DEE4DBFIAEBEBAE4DBEAQBAEADEEDD3E5DBbQABXQABYQAE5DBSAQE9DEE5DBSAQG5DBAQQEDE4DEEDBTAQBAQQDDBWAQBDASBWQAI5DBSQAG3DBAIA5DEE12DEEDEHDD3E5DBaQABXAQBZQBBABB5DFHDDEG5DEE12DEEDEECPA4E6DIGDBFBAEDCBB3ECAA3E5DEE12DEEDEEDD3E6DEE3DBFBAFDEEDDEBTQABDAW3DBRQAE14DEDEEDD3E6DEE4DF3E23DEEDBGAQEDD3E6DEE5D3E23DEBEEAB3A4D3E6DEE5DBFBAEE18DBEAQBFAQEDDBSAQG5DEBEQNE6DEE6DEE12DBEAQBFAQE3DBHAQBGAQE9DEBANAE6DBSAQE6DEE12DBHAQBGAQE15DEEBRANE13DEE30DEEDBQANE12DEE30DEE3DBGQNBAQQ43D,Ads:A1821 +I 751,9553,3,2 +B phena b,1324505741398 +L _junnu_moi,1366466904264 +R 3,0,2,1,4,5,9,3,5,5,51 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/long/Aither-Another_one_bites_the_mud.track b/shared/src/test/resources/tracks/long/Aither-Another_one_bites_the_mud.track new file mode 100644 index 00000000..3bfdec7d --- /dev/null +++ b/shared/src/test/resources/tracks/long/Aither-Another_one_bites_the_mud.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Another one bites the mud +T BACADDBGQCBAQQ6DBSQAG12DBQQCG8DBJEQCMEBIEQBAQQ6DBQQCGDBACAEBAQQDDBGAQB3A4DBJQAFBIQAB3A7DBHACBACA6DBGACB3A3DBJQAFBAEAGBIQAB3A4DBHACBACADEEBGQCEBAFADDBHFAEDDCPAFEG11DBHACEDBGACB3A6D3EB3A7DBRCABFQCBHQCBAQQBEQFE3DFE3DBXQAE22D4E7DEIBAQQEB3ABFFAE3DE3DCDPE8DBEACBACABFACE10D4EDDBFAQE4DBHAC3EDDBFFAEDBHFAEDDBXAQE6DBEACBACA4DBFACE8D4ECBAEBAQQE4DBGIA3E3DE3DBHFABTAQBAQQ9DBSQCG7DBFAQE3DEEBOXQEDDEE3DBGIABAIA3E3DBFFAE3DHEBIQIBIIKBAKA20DBRQKEBAXABLXKBAKABKQKEEDBGIABAIADD3E4DFEDDBHFAEBAIABIKQH15DBGAQH3DHCOEBIXQBAQQDDBKAQEBGIABAIADDBEIAEEBFAIE5DBFFAEDEEGBIQAB3A19DEHGBIQAB3A3DBAIADBEIAB3ADEEBAIAFE5DED3EB3ABGHABAIABHJAE16D3EB3A3DBGIAEDB3ADD3EDDBFAIE3DBFFA5EBAGACGABAKAE16DBAVA3EDDBGIABAIADBEIAEDD3E3DFE3DFEEBAXAEBHAFBAEABGALEBQAQE14D4EBGIABAIADDBEIAB3A3DEEBHAIE3DE3DBKQA4E4DBAQQE14DBAQQ3EBAIADDBEIAB3A4DEEB3ADBHAIEDBFAIBIAQBAQQDDBKIQBKKIIE4DEE12DCNA4EBGIAEBEIAB3A5DBGHA3EDDFEDBAQQBIQIBIIKBAKADBKQKEE4DEBLQAE12DBKQA3EBAIADI6DBAHA3E3DEDEGBIKQH3DE4DBLAQF14DBKGQ3EBEIAE5DBGHA4E3DEDEEGBIQAB3ABJQABTQGBAGA20DBKEGBKQEEBEIAB3A5DBGHABAHAD3E3DBHAIEEBSAIEB3ACAAFHG4DBHAQHDDBQQCGDDBQQCG9DBRAQE3DBGHABAHADDBEHA3E4DFEB3AEEDDEE6DBHACBACA5DBGACB3A7DBXQAG3DBGHABAHADDBEHAB3AEEBFACE4DBHAQEBGAQEDDEE8DBHACEBGACB3A10DCDPEDDBGHABAHADBGAHB3ADDEBTQCBACAE10DEE22DBXAQEBGHABAHADDBEHAB3ADDBEAQEHEBFACBQACE8DEE10DBEACIDBFACE7DBAQQBGHABAHADDBEHAB3A3DBAQQBEQCEDBHQCIBFACE6DBKQAEBLQAE5DBGCABACA7DBFACE4DBKQAEBLQHEBEHAB3A3DBEAQBAQQDBACABACABFQCFBSQCG8DBQQEF9DBSQCG11DBQQEF7DBEQCBACAD +S tttt14 +I 233,3705,5,1 +B advanced,1367309863750 +R 4,1,1,0,0,4,1,0,0,2,24 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/long/Aither-Anticandy.track b/shared/src/test/resources/tracks/long/Aither-Anticandy.track new file mode 100644 index 00000000..8ba6e38f --- /dev/null +++ b/shared/src/test/resources/tracks/long/Aither-Anticandy.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Anticandy +T BAMM26DBAQQ21DEB3ADBBAFG22DEBAGA16DB3ADD3EBCALF23DEE5DBBGLE9DEDD3E25DEE6DBCGFE8DEDD3E5DBAQQ15DE3DEE3DBBGJE11DEDD3E16DBBAQGDCBAEE3DEE16DEDD3E20DEBCALE3DE16DEDD3E18DBCAHEEG4DE16DEDD3E20DEE4DE16DEDD3E3DBWQABAQQ5DBAMMDCTMG6DE13DBFAQB3ADBEAQBAQQ8DEE3DEBWAQHDDCBAEH14DEBAMM7DBEMAEDBFMABAMM7D3E3D3E3DEEDDBBAIE10DEE6DBEMAB3A3DFE6D3E3D3E3DEE14DEBEMAB3A17DBFMA3E9DE4DBRAQBBAFDBTAQBAQQDE4DEG19D3E9DEG8DEE4DEE8DBEAQBFAQE8D3E9DEE8DEE4DEE7DBTAQBGAQBHAQBRAQE7DEBAQQE3DBWQABWAQE3DEE8DEE4DEE19D3E3D3E3DEE8DEE4DEE19D3E3D3E3DEE8DEE4DEE19DEEBAMM9DBGAQE8DEE4DE7DE5DBAQQ7DEH19DEE6DBAKA3DH9DBABBDDHD3E15DBCAHEDDEE6DE3DE9DED3BFEDEECAAE15DBCAFEDEEDBCALE3DE3DE9DEDDEBBAIEEH19DEEBBAHF4DE3DE9DEDDEDEE21DBAMM4DBAQQ21D +I 789,14549,6,11 +B IceWave,1280334968466 +L Abracadabra,1357037806123 +R 6,2,1,1,5,7,9,4,12,7,42 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/Aither-AC_DC.track b/shared/src/test/resources/tracks/modern/Aither-AC_DC.track new file mode 100644 index 00000000..aff3d0a4 --- /dev/null +++ b/shared/src/test/resources/tracks/modern/Aither-AC_DC.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N AC/DC +T BKQABLQAB3ADBFAQBHAQBAQQ21DBGAQBGNABANADDBENABEAQBHAQBAQQ12DBJQABIQAEDBAQQFB3A21DBGNABANADDBENABEAQBAQQBFAQB3A11DEB3ADDBEAQEDFE8DCIAEDDBEAQHDDBGAQEDBGNABANADDBENABEAQBAQQDDFEDDCPAE6DEEDBEAQBGAQBHAQEDFE10DBEAQBAQQDDBGAQHDBGNABANADDBENABEAQBAQQ4DFE9DEEBEAQBAQQ5DFEDDCLAE4DBEAQBAQQDDBGAQB3ADBGNABANADDBENAB3ADEDBFQAEDDFE8DEBEAQBAQQI3DIEDFE3DBEAQBAQQDBEAQGDDBGAQB3ADBGNABANA5DBENAEDB3AFEDDFE7DEBAQQDE4DEDDFEDBEAQBAQQ5DBGAQB3ADBGNABANA5DBENAHEDEDBRQAEDDBRAQE6DEEDE4DE3DEBEAQBAQQDBGAQEGB3A7DIEDBENAB3ADEDEBGQAHDDBGAQH7DEEDBGAQE3DE3DBEAQGDBGAQB3AFGBEAQE5DIHDBENAB3ADDEDBGQAGDDBGAQB3A8DEEBGAQH4DE6DBFAQEDBEAQIE4DBGNABANADBENAB3A3DE4DBGAQB3A9DEBGAQB3A5DBHAQEDDBHAQEDDFEBAQQDE3DBGNABANA3DFEDBEAQE3DBGAQB3A10DBGNQBEAQE6DFEDB3AFEDDFEDEDDBGNABANA3DHHDDBAQQ3DBGAQB3A5DBEAQBAQQ3DBGAQBANABAQQE7DFEEDFE4DE4DBGNAEBENAB3A3DEDDBGAQB3A5DBEAQBAQQ3DBGAQH3E8DFEDDFE3DE3DBGNAHBENAB3A4DEDBGAQB3A5DBEAQBAQQ3DBGAQB3AD3ECAAE11DFEDDBFAQEDBGNABANABENAI11DBEAQBAQQ5DBGAQB3ADD3E14DFEDDFBGNABANABENAI11DBEAQBAQQ3DBGAQB3A3DCJA4E15DFEDDBFNQBENAI11DBEAQBAQQDBGAQEGB3A6D3E16DFEDDB3A11DBEAQBAQQDBGAQB3AFG5DBKQABLQA3E7DBKQABLQAE6DBGNABHNQEDE10DBEAQBAQQDBGAQCBAE7DBJQABIQA3E7DBJQABIQAE5DBGNABANABENAB3A11DBHAQBAQQDDBFAQB3ADBFAQE7D3E14DBGNABANABENAI13DFEDDFEBAQQFE6D3E10DCOAEDBGNABANABENAI12DCKAEDFEDDFEDFE5D3E12DBGNABANABENACKAE16DFE5DFE4D3E12DBANABENAI19DFE7DBFAQEDEE35DBFAQFE7DFBFNAE +I 1852,16235,2,100 +B Jeppe-82,1223134918614 +L !-Sallena,1369414751953 +R 18,4,0,5,8,15,14,10,9,6,81 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/Aither-Absinth_II.track b/shared/src/test/resources/tracks/modern/Aither-Absinth_II.track new file mode 100644 index 00000000..a4226629 --- /dev/null +++ b/shared/src/test/resources/tracks/modern/Aither-Absinth_II.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Absinth II +T BGQBBXBQ22DBSQBG3DBAMM3DBXBQ5DBSQBG7DBHQBBWQBBIQBBA3BEBQBGAQB3A17DBJQABAQQBIQACBAB3ADEDDBKAMB3A4DBJQABAQQBIQDBADA5DBJQDBWBQEBA3BEBQBGAQB3A18DCAAEB3ADDBKMAEDBIMAB3A6DEBADABCDQE5DEEBEBQBGAQB3A20DEEBIAMBAMMDDBKAMB3A7DEEBBDQE5DEEBGAQB3A20DBKQAEEBAMMDBIMAI9DBODQE7DEEB3A3DBIAQBAQQ3DBJAQE7DBIAQBAQQ3DBTQAEEDB3A10DBRDAE7D3EBKEABLEAEBAQQBIQMBAMMDBJQMFE7DBAQQBIQAHCNABJQAFBKMAEDBLMAE9DEE7D3EBAEADEEBAMMBIMADB3AEE7DEG3DEBAMMBIMAI11DEE7D4EDEEBKAMCMAB3ADEE7DEE3DEEB3A12DEE7D4EDEEG3DEBLQAE6DEE3DEBKAME12DBMDQE7D4ED3E3DBLAQFDDBJAQE3DEECWAEDEG13DBAQQEBBDQE5D4ED3E4DBAOADBJQOFE3DEBAMM3DEE13DEECBDE5D4EDEEBLQAE3DEDDEE3DEG3DEE13DEE7D4EDEBLAQF3DBJAQEDDEE3DEE3DEE13DEBLQDE5DBKQD4EDE4DBJQAFEBMOA3E3DEE3DEBJAPE12DBLAQF7DBTQB3EDE5DEEB3A3E3DEE3DEBAPAE18DBLAMBAMMDD3EDE5DEEBOOA3E3DEE3DEEBLPAE5DBLBABKBAE10DBJMAED3EDE5DEEDDEE3DEE3DEEDBJAPBLPAEDDBEAQBHQBBGQBBFAQE10DF3EBJEABIEAE5DEEDDEE3DEE3DEBLQPE3DBJAPBEAQBEQBBFQBGGFE10D3EDDBBAQE4DBOAQEDDBOAQE3DEE3DBLAQF5DBEQBBABB3DFBAQQ5DBNAQE3DBWBQEBFAQEDDBCAQE12DEE10DBJBABIBABSABDBJBABIBAH10DEBAMMBHMQFE15DEBFAQE26DEEDFFE14DEBHAQFE25DEEDDFFE12DBKQAEBLQAFFE23DBKQAEE3DBXQB14DBQQBG27DBEQB +I 915,12765,4,4 +B IceWave,1282316783014 +L Asspolis,1365605441980 +R 7,0,0,1,1,4,3,6,6,5,38 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/Aither-Big_Blind.track b/shared/src/test/resources/tracks/modern/Aither-Big_Blind.track new file mode 100644 index 00000000..13afc27c --- /dev/null +++ b/shared/src/test/resources/tracks/modern/Aither-Big_Blind.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Big Blind +T BAQQ21DBFAQB3ADDBEAQBAQQ20DBFAQE22DFEBEAQBAQQ8DBZQNCTNDBaQNE9DEBZQNB3ADDBAKA11DB3A3DBHAQEDFGDBGAQB3A17DBHAQEDECTNECOAEE11DE4DFE3DB3A19DEDEBYQNEDDE11DE5DFEDDE19DEDE16DBAEADDBFAQEDDFEDEDDBAQQ13DBAIADDEDE16DEDDBAQQFEDDFBGAQEDDE13DEDDEDEDB3A12DEDEDDEDFE6DEDBXAP9DEDEDDEDEDE12DEDEDDEDDFE5DEDB3A3DBbQABFAQB3A3DEDEDDEDEDE12DEDEDDE3DFE4DEDE3DBAQQDE3DEDEDDEDEDEDDBAQQ6DEDDEBZQNEDDBaQNEBHAQEDFE3DEDE3DEDE3DEBZQNEDDBaQNEEDEDDE6DEDDECTNEDDCTNEB3AFEDFECGAEEDE3DEDE3DECTNEDDCTNEEDEDDEDB3ADDEDEDD3EDD3EDFEDFFDEDE3DEDE3D3EDD3EDEDDEDECAAEEDEDD3EDD3ECBAFFEDFEEDE3DBHAQBZQAE3D3EDD3EDEDDEDEDDBaQABGAQEDDEBYQNEDDBbQNEE3DFEDFEDE9DEBYQNEDDBbQNEEDEDDEDE7DEDEDDBAQQDEDDBCAQFFE3DE3DBbQABFAQE3DEDEDDBAQQDEDEDDEDE5DCPAEEDEDDEDEDDEEDFEDDE3DBAQQDE3DEDEDDEDEDEDDEDE7DEDEDDEDEBCAQE4DFEDE3DEDE3DEDEDDEDEDEDDE11DEDDED3E5DFEE3DEDE3DEDEDDEDEDEDDE11DEDDEDBFAQF7DFE3DEDE3DBHAQBZQIEDDEDEDE17DBHAQEDFE11DEDE8DEDEDE18DFEDFE10DEDE8DEDEDBFAQE18DFEDFE9DEDE8DEDE48DBHAQE47D +I 1207,14720,5,14 +B Grange,1291899645252 +L Hervoton herpes,1359681468430 +R 2,2,2,4,1,10,8,6,3,6,87 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/Aither-Blockster.track b/shared/src/test/resources/tracks/modern/Aither-Blockster.track new file mode 100644 index 00000000..dde2171d --- /dev/null +++ b/shared/src/test/resources/tracks/modern/Aither-Blockster.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Blockster +T BAMMDDBXMQ12DBSQMBFMQBAMM4DBEMQBQMQBFMQBAMM5DBGQMBSQMBHQMBQMQBAMM6DBQMQBGQMBSQMBHQMBAMMDEDBGQMBGAQB3A8DBAKADDB3ADFBWQMBADA8DBWMQEBGQMBGAQB3A12DBHAQFEEBGQMBGAQB3A9DEDDEDBTQMEE3DCLDE3DEBGQMBGAQB3A14DFFEBGAQB3A10DEDDECNABWMQEEDDBGQDCDDBHQDEDDEBRQMB3ADBHGIBAIA10DBEIKEDBTQMEB3A11DEDDED3EDDBEQDGBFQDEDDEBWQMEDBAGAFE8DBEIKBAKAEDBWMQEE3DBZAQBXAQ6DBXKQDDBXAQD3E8D3EDEDFE6DBEIKBAKADED3E3DBWQABXMQ11DBaMQEE8D3EDEDDFE4DBEIKBAKADDEDEBWQME16DHEBQDA8D3EDE3DBAMM4DBAKA3DED3E16DEEB3A8D3EDEDDBGEGBAEA4DBHEKEDDED3E16D3ECDAE4DCDA4EDEDBGEGBAEA6DFEDED3E16D3E8D3EDEBGEGBAEA3DCMEE3DFEEDEEBXAQ11DBaAQE3D3E8D3EDBGEGBAEA10DFEDEBZMQBXMQ11DBWAQE3D3E3DCDAE3D3E16DEHB3A16D3E8D3E16D3E16D3E8DEEBAMM16D3E16D3ECDAE4DCDA3EBAEABAIA15D3E16D3E8D4E15DEBAMMECWAEDBZAQBXAQ11DEEBSDA8D4E15DEE4DBWQMBXMQ11DBaMQEBADA8D4E15DBAMMEH16DHEE8D3EB3A15DEBWQME14DCKA4EDDBHQDEBGQDEDD4E15DEBRQME16DBTQMEEDDBFQDCDDBEQDEDD4ECWAE11DCAABEAQEBFQMBFAQE14DBEAQBEQMEE3DCBDG3DEBRQMEE13DBEAQBGMQEBAMMFFE12DBEAQBEQMBAMMEE8DEBHMQEBAKA12DBEKQBGMQBAMMDEDFBQQMBEQMBSMQBAMM6DBSMQBFQMBQQMBEQMBAMM5DBHMQBSMQBGMQBAMM4DFBQQMBXQM12DBAMMDD +I 2410,45279,5,3 +B Jeppe-82,1233569680826 +L Jeppe-82,1257132839491 +R 37,7,1,9,5,23,12,18,17,15,82 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/empty_stats.track b/shared/src/test/resources/tracks/modern/empty_stats.track new file mode 100644 index 00000000..e3e99eb0 --- /dev/null +++ b/shared/src/test/resources/tracks/modern/empty_stats.track @@ -0,0 +1,4 @@ +V 1 +A Sprt +N SprtTrack +T Data \ No newline at end of file diff --git a/shared/src/test/resources/tracks/modern/single.track b/shared/src/test/resources/tracks/modern/single.track new file mode 100644 index 00000000..bf5c1487 --- /dev/null +++ b/shared/src/test/resources/tracks/modern/single.track @@ -0,0 +1,9 @@ +V 1 +A Aither +N 4 da Crew +T Data +S ftft14 +I 537,11734,4,21 +B Sprt,1280012972607 +L advanced,1369922144542 +R 8,2,0,3,4,2,8,6,1,4,55 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/sets/birchwood.trackset b/shared/src/test/resources/tracks/sets/birchwood.trackset new file mode 100644 index 00000000..f1167de3 --- /dev/null +++ b/shared/src/test/resources/tracks/sets/birchwood.trackset @@ -0,0 +1,6 @@ +Birchwood +EASY +Absinth II +5th Street +AC/DC +Basement Reflex \ No newline at end of file diff --git a/shared/src/test/resources/tracks/sets/oakpark.trackset b/shared/src/test/resources/tracks/sets/oakpark.trackset new file mode 100644 index 00000000..22fe9f27 --- /dev/null +++ b/shared/src/test/resources/tracks/sets/oakpark.trackset @@ -0,0 +1,3 @@ +Oak Park +EASY +Alchemea \ No newline at end of file diff --git a/shared/src/test/resources/tracks/short/Aither-Alchemea.track b/shared/src/test/resources/tracks/short/Aither-Alchemea.track new file mode 100644 index 00000000..70ae67ce --- /dev/null +++ b/shared/src/test/resources/tracks/short/Aither-Alchemea.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Alchemea +T BAQQ4DBQQAG15DBGMQBAMM25DEB3ADBFQABEQAB3ABFQAEDBEQABSAQB3ADBFQABGAQB3ADBFBABABBDBHBQEBEMAB3A23DBFMA3E5DFBEQAB3A8DEDDEB3A22DBIAPBJAPF3E16DEDDEE22DBLAPBKAP4E16DEDDEE3DBAQQ10DBJAQE8DBKKA3E16DEDDEE3DBRQABRAQCIABTAKBAKA17DBEMQEBAIA6DBMIQG8DEDDEE3DH22DEE6DBAQQE8DEDDEE25DBFQMEE6DEE8DEDDEE23DCDAEBAMMEE6DEE8DEDDEE25D3E6DEE8DBFBIEDBHBQF7DBGAQBEAQGEBEAQBAQQ3DBNAQE7DEEB3A6DEG10DBSABG26D3E6DEE38D3E5DCAABHAQBFAQE36DBGMAEE7DBFAQFI9DBFMQBAMM26DBEMQBGMQH6DFG7DBAKADDFBEMAH4DBAIA12DBAQQ8DBAMMECBAE4DEE7DEDDEB3A5DE12DEB3A6D3E6DEE6DBIAQBAEADDEE5DE12DEEDDCJAEDDEEBAEA6DEE6DBAQQEDDEE5DE12DEE6D3E6DEE6DEEDDEE5DE12DBOAQE6D3E3DCDAEDBKAQE6DEEDDEE5DE12DB3A7D3ECDAE4DB3A7DEEDDBKAQE4DBMAQE12DE7D3E6DE7DEEDDB3A5DBAQQE12DBMAQE6DEEBHMEE5DE7DEEDDE5DEE4DCDADDE4DBAQQE6DEE6DBIMQBAQQ17DBGMQBAMM11DBEMQE8D +I 1154,19593,6,15 +B FIN King Pelle,1280433774011 +L kenkäpossu,1360074117234 +R 4,0,1,3,2,11,7,5,5,11,64 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/short/Aither-Basement_Reflex.track b/shared/src/test/resources/tracks/short/Aither-Basement_Reflex.track new file mode 100644 index 00000000..610bc39c --- /dev/null +++ b/shared/src/test/resources/tracks/short/Aither-Basement_Reflex.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Basement Reflex +T BIMQBAQQ22DBONQG22DBJMQBAQQBIQAB3A20DBNNACTNBPNAB3A20DBJQAFEB3A22DEG22D3E16DBBAQEDDCBAHEHCBAEDDBBAQE16D3E22DEG22D3E21DHEHE21D3E4DBIAQBAQQ16DBMNQG16DBJAQE4D3E4DBAHA16DBJQHBMQHBIQHBAHA16DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE36DE4D3E4DE16DBKSHBOSHBLSHE16DE4D3E4DBLAHE5DBPHSBASA20DBNHSE5DBKAHE4D3E21DBJQABMSQBIQAB3A21D3E22DBAQQG22DEEBLMAE20DCAAEE21DBKMAEEBAMM9DBJAME11DEE11DBIAMBAMM9DEEBLQME9DBLMAE9DBKQAEBLQAE9DBKMABAMM9DBKQMEBLMQF46DBKMQ +I 55714,217981,1,3203 +B Jeppe-82,1222692521164 +L P epsi,1370258671464 +R 74,21,35,45,69,118,135,94,64,48,492 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/traditional/Aither-Audiorealism.track b/shared/src/test/resources/tracks/traditional/Aither-Audiorealism.track new file mode 100644 index 00000000..6ccf8c55 --- /dev/null +++ b/shared/src/test/resources/tracks/traditional/Aither-Audiorealism.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Audiorealism +T BAMMDBIMQBAQQ17DBJMQBAMM26DEDBAGA8DB3A8DBJQAFE26DEDE8DE9DEGDDBLAQBAQQ15DBKAQB3A3DBJMQEEDE8DE9DEEDDCDAG20DBAQQEEDE8DE9DEEDDEEDDCPAE16D3EDE8DBIAQE8DEEDDEE20D3EDE7DBKQGBKBQBLQACKAE6DEEDDBIAQBAQQ13DBJMQBAMMBJAME3D3EDE6DBLGQBJBQBABABLBQBJAQE6DEEDDBAQQBIQIBAIA11DBJQIFEDE3DEBJMQEDE7DBJQGBIBQBIQACAAE6DEEDDEBLAIE12DEEDE3DBJQMFEDE8DBKAQB3A8DEEDDECBAB3ADDBNIAE7DBKAIEEDE3DBAMMEEDE8DB3A9DEEDDE4DBNIQE3DBPIAB3ADDBKQAEEDE3D3EDE8DE9DEEDDEBIQIBAIA7DBPIQBAQQ4DEDE3D3EDE8DE9DEEDDEBAIA3DBPIAB3ABNIAE5DBJQIEEDE3D3EDE8DE8DBKQAEEDDEE3DBPIQBAQQBNIQE6DEEDE3D3EDBLMQBAQQ17DBKMQEDDEE13DEEDE3D3E21DEDDEE13DEEDE3D3E20DBKAMEDDEE4DBPIAB3A3DBNIAEDDEEDE3D3EDBIMAB3A21DEE4DBPIQBAQQ3DBNIQEDDEEDE3D3EDB3ACLAE20DEBIIAB3A11DBJIAEEDE3DBKQMEEDE22DEBLQAE5DCNAE4DBKQAEEDE3DBAQQBKMQEDEDDBTAQBAQQ14DBRAQEDDE14DBKMQEBKAME3DEBAMMEDBAGA18DH3DEBIQAHDDBAKA9DI6D3EDE18DE3DECOAECMAEE9DE5DBEAQBEQMEEDE18DEDDBKQAEBLQAEDDE9DE4DBEAQBEQMBAMMDEDBLMQBAQQ41DBEQMBAMMDD +I 2301,36975,5,62 +B Jeppe-82,1224249922827 +L Grange,1365519199618 +R 32,2,2,7,5,15,15,22,11,18,147 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/traditional/Aither-Avoiding_ponds.track b/shared/src/test/resources/tracks/traditional/Aither-Avoiding_ponds.track new file mode 100644 index 00000000..4e553c67 --- /dev/null +++ b/shared/src/test/resources/tracks/traditional/Aither-Avoiding_ponds.track @@ -0,0 +1,9 @@ +V 1 +A Aither +N Avoiding ponds +T BAQQ6DBKMQBAMMDBAQQ10DBAMM4DBKQMBAQQ3DBLQMBAMM3DBAQQ6DBLQMBAMM4DE4DBIQMBAMMDDBKQME10DEDBIMQBAQQ8DBJMQEDE8DBJMQEDDE4DBAMMBIMQIDDBGAQB3A9DEDBAQQBGAQB3A4DBHAQEDDEDB3ADDBHAQE5DEDDE3DBKMQEIDDBGAQB3A10DEDEB3ACBAE4DFEDEDE4DBHAQE3DEDDEDBIQMBAMMDBKQMEDBGAQB3A11DEDBGAQE7DFEEDE5DFEDDEDDEDBAMMBIMQI3DB3A12DEDB3A9DFBLAMBKAME6DEDDEBMMQEEBKMQEI3DBGAQE12DBLAMBKAME13DBAHABAIADBAJAEDEDDEGBOQMBIQMBAMMDE3DB3ACAAE9DBEAQBAQQFDBBAME12DBAGABANACUNBAKAEDEDDEEDBIMQBJMQEE3DE5DBEAQBAQQE3DBAQQDEBCAMF4DBEAQBFAQE6DEEDEEDEDDEEDBAQQDEEDDBGAQE5DBAQQBGAQE3DEDE6DBHAQBAQQFE5DBAFABAEADBALAEDEDDEEDEDEEDDB3A12DEDE7DFBGAQE11DBHAQEDEEDEDEEDDE12DEDE22DEDEEDEDEEDBGAQE11DBEAQEDE22DEDBOQMEDEDEEDB3A11DBEAQBAQQDBGAQE22DE4DEDEEDE11DBAQQDBGAQB3A4DBEAQBFAQE11DBEAQBAQQDEDEBCQMEDDEDBOQMEDEDDBAHABAIADBAJAE4DBHAQEB3ADDBEAQBAQQ3DE11DBAQQDBGAQEDE4DEDDBCQMEEDDBAGABAMMDBAKAE5DFE3DBHAQEDDE11DBHAQEB3ADDE4DEDBBQMFDEDDECUM3E4DBFAQF6DBHAQBGAQE16DE4DE4DEDDBAFABAEADBALAE4DBAQQFE24DE4DE4DE11DEDE24DE4DE4DE11DEDE24DE4DE4DBFAQE10DEBGAQE23DBEAQE4DE5DE22DBEAQBAQQDDBFAQE7DBEAQBAQQ5DE6DIE17DBEAQBAQQ6DFE3DBEAQBAQQ8DE48D +S fftt14 +I 513,4559,1,9 +B Minigolfputter,1367757824953 +L Mirak 1,1369920555751 +R 2,1,1,0,0,1,0,2,1,1,10 \ No newline at end of file diff --git a/shared/src/test/resources/tracks/traditional/Aither-Bananas_for_Banshee.track b/shared/src/test/resources/tracks/traditional/Aither-Bananas_for_Banshee.track new file mode 100644 index 00000000..926cb0c2 --- /dev/null +++ b/shared/src/test/resources/tracks/traditional/Aither-Bananas_for_Banshee.track @@ -0,0 +1,8 @@ +V 1 +A Aither +N Bananas for Banshee +T BZMQBXMQ46DBaMQBWQMBAQQ3DBIQMBAMMDBJQMBAQQ21DBGAQDB3ADBHAQDBAQQ10DBWMQEEBIQAB3A12DBJQAEBIQAB3A26DBJTA4EB3A14DEGCLAE26D5E14DEE28D5E14DEE28D5E4DBEAQBFAQE7DEE3DBIAQBAQQ6DBFNQBANABFANBSNADBGNABANABENQBAQQDDBJAQE4D5E3DBEAQBGMQBFQMFE6DEE3DBAQQBIQBBA3BRABH3DBHAQFF3DBENQBGAQHDBJQAFE4D4ECAAEDBEAQBGMQBAMMDFFE5DEE3DEBA3BGABB3A5DFFEDBENQBGAQB3A3DEE4D4EHDBEAQBGAQBSAMBQMADBSAMBFQAFE4DEE3DEEBFABE6DFFBENQBGAQB3A4DEE4D5EBEAQBGAQI5DBFQBFE3DBSAQE3DEEDBRABE6DFBGAQB3A5DEE4D4EBEAQBGAQI5DBEABBABBFFE7DEEB3A16DEE4D4EBGAQB3A7DBSABCBBFFE5DBKQAEBEBAE16DEE4D3EBGMQB3A8DBEABBA3BEBQBAQQ7DBKAQI5DBQAQE10DEE4D3EBAMME9DBSABG14DBEAQBGAQE10DEE4D5E24DBEAQBGAQI11DEE4D5E23DBEAQBGAQI12DEE4D5E22DBEAQBGAQI13DEEDCOAED5E8DBQAQE11DBEAQBGAQI14DEBLQAEDDBKQA5E7DBEAQBGAQE10DBEAQBEQNBANAE14DBLAQF5D3EBAKA6DBEKQBGAQBFKABAKA4DBGAKBEAKBAKADDBEKQBEQNBANABTNKBAKA10DBGAKG4DBIKAHDBJTA5E5DBEKQBGAQIBEAKEDDBGAKBEAKF3DBEKQBEQNBANABENKBAKA8DBGAKHDBEAKE4DB3ADCPAF3EBLQME4DBEKQBGAQCKABFKABAKADDBGAKBEAKH3DBEKQBEQNBANA3DBSNKBHNKE4DBGAKBEAKH7DBLKAEDBKTA3EBAQQ46DEBYMQBXQM46DBbMQ +I 728,8755,4,45 +B Joonas,1280110304310 +L advanced,1370202090153 +R 6,4,3,2,3,10,7,5,0,7,37 \ No newline at end of file diff --git a/tracks/sets/birchwood.trackset b/tracks/sets/birchwood.trackset index 1717e475..8a141b64 100644 --- a/tracks/sets/birchwood.trackset +++ b/tracks/sets/birchwood.trackset @@ -1,11 +1,11 @@ Birchwood EASY -Leonardo-Leobas_1 -Tiikoni-Removable_Wall -Leonardo-Simple_Triple -Ennaji-Watertank_run -Leonardo-Garapalou -Leonardo-Two_Bridges -Tiikoni-Wormhole -Leonardo-Trip_to_Basement -Leonardo-Virtuoso_Bridges +Leobas 1 +Removable Wall +Simple Triple +Watertank run +Garapalou +Two Bridges +Wormhole +Trip to Basement +Virtuoso Bridges \ No newline at end of file diff --git a/tracks/sets/oakpark.trackset b/tracks/sets/oakpark.trackset index 43951881..9eb25e10 100644 --- a/tracks/sets/oakpark.trackset +++ b/tracks/sets/oakpark.trackset @@ -1,20 +1,20 @@ Oak Park EASY -Tiikoni-Barrier_III -Leonardo-Basic_Z_2 -Tiikoni-Oval_I -Leonardo-Amdazou -Tiikoni-Lower_V -Hoeg-Miniaturica -Leonardo-Monday_Hogback -Aither-Four_Rooms -Tiikoni-Speedy -Leonardo-Rood -Leonardo-Basic_Z_1 -Leonardo-Zab_2 -Tiikoni-Sandwall -Leonardo-Mud_Cisterns -Tiikoni-Flume -Leonardo-The_lake_and_the_river -Leonardo-Mi_Bo -Darwin-Darwin_s_road_II +Barrier III +Basic Z-2 +Oval I +Amdazou +Lower V +Miniaturica +Monday Hogback +Four Rooms +Speedy +Rood +Basic Z-1 +Zab 2 +Sandwall +Mud Cisterns +Flume +The lake and the river +Mi-Bo +Darwin's road II \ No newline at end of file diff --git a/tracks/sets/onebyone.trackset b/tracks/sets/onebyone.trackset index 9946873c..faccb412 100644 --- a/tracks/sets/onebyone.trackset +++ b/tracks/sets/onebyone.trackset @@ -1,20 +1,20 @@ One by One MEDIUM -Leonardo-1_stroke__4_bounces -Dante-Room_Worm -SuperGenuis-Too_easy_too -Tiikoni-Downhill -ConTrick-Tea_for_irish -Zwan-Wohwonk -Dante-Drop_it -Leonardo-Stopper -Dante-Ice_Bounce -Darwin-Narrow_bridges -Dante-ArmChair -Leonardo-Go_go_go -SuperGenuis-Worm -Dante-Keep_on_track -Tiikoni-Leaps -Zwan-Rebound_goal -Enygma-There_and_back -Dante-Traditional_bounce +1 stroke, 4 bounces +Room Worm +Too easy too +Downhill +Tea for irish +Wohwonk +Drop it +Stopper +Ice Bounce +Narrow bridges +ArmChair +Go go go +Worm +Keep on track +Leaps +Rebound goal +There and back +Traditional bounce \ No newline at end of file diff --git a/tracks/sets/scaryset.trackset b/tracks/sets/scaryset.trackset index be2376fa..f36880d0 100644 --- a/tracks/sets/scaryset.trackset +++ b/tracks/sets/scaryset.trackset @@ -1,11 +1,11 @@ Scary Set HARD -Leonardo-Dream_of_Six_Strokes -Tiikoni-Acid_Way -Leonardo-KGB_s_wish -Tiikoni-Minimum_Possibility -Leonardo-Risky_Business -Darwin-Ruins_of_the_tempel -Leonardo-Abstemiously_Dangerous -Tiikoni-Leaking_Spiral -Leonardo-Tube_of_Death +Dream of Six Strokes +Acid Way +KGB's wish +Minimum Possibility +Risky Business +Ruins of the tempel +Abstemiously Dangerous +Leaking Spiral +Tube of Death diff --git a/tracks/sets/sprucecorpse.trackset b/tracks/sets/sprucecorpse.trackset index 1b8d0ecb..b1d948c2 100644 --- a/tracks/sets/sprucecorpse.trackset +++ b/tracks/sets/sprucecorpse.trackset @@ -1,11 +1,11 @@ Spruce Corpse MEDIUM -Darwin-Three_hills -Leonardo-Updo -Leonardo-Kim_Dim -Leonardo-Well_stairs -Tiikoni-Continents -Leonardo-Drobri -Dante-Waterway -Leonardo-Six_bends -Leonardo-Gurus_do_it_better +Three hills +Updo +Kim-Dim +Well stairs +Continents +Drobri +Waterway +Six bends +Gurus do it better diff --git a/tracks/sets/thefirst.trackset b/tracks/sets/thefirst.trackset index 5bda8613..1a35b783 100644 --- a/tracks/sets/thefirst.trackset +++ b/tracks/sets/thefirst.trackset @@ -1,20 +1,20 @@ The First MEDIUM -Tiikoni-Curve_I -Leonardo-Barb_II -Tiikoni-Oval_III -Tiikoni-Bridgebuilder -Leonardo-Sand_Stripe -Tiikoni-Hopper -Leonardo-Real_Pro_s_7_Strokes -Ennaji-8_rooms -Leonardo-Resemble_of_T_B_ -Tiikoni-Barrier_I -Tiikoni-Magnetic_Aid -Ennaji-Icy_cavern -Tiikoni-Over_and_Up -Tiikoni-Returns -Leonardo-Triple_Crossing -Tiikoni-Two_Ways -Leonardo-Try_it -Tiikoni-Uphill_I +Curve I +Barb II +Oval III +Bridgebuilder +Sand Stripe +Hopper +Real Pro's 7 Strokes +8 rooms +Resemble of T.B. +Barrier I +Magnetic Aid +Icy cavern +Over and Up +Returns +Triple Crossing +Two Ways +Try it +Uphill I diff --git a/tracks/sets/tormentfields.trackset b/tracks/sets/tormentfields.trackset index 79c732e5..c6e04276 100644 --- a/tracks/sets/tormentfields.trackset +++ b/tracks/sets/tormentfields.trackset @@ -1,20 +1,20 @@ Torment Fields HARD -Leonardo-Revocations -Dante-Bridges -Leonardo-Jump_to_the_elevator -Leonardo-Dream_of_Four_Strokes -Leonardo-Walls___Waters -Zwan-Hillocky -Tiikoni-Mean -Leonardo-Jacke_s_Dream -Hoeg-Raffle_Imposition -Zwan-No_man_s_land -Leonardo-Dui_Hui -Dante-Swiftly_repeating_myself -Leonardo-Advance_d_ -Tiikoni-Pipe -Zwan-Tribulation -Leonardo-Skills_and_Snares -Zwan-Acid_Floor -Zwan-Wararumbel +Revocations +Bridges +Jump to the elevator +Dream of Four Strokes +Walls Waters +Hillocky +Mean +Jacke s Dream +Raffle Imposition +No man s land +Dui Hui +Swiftly repeating myself +Advance d +Pipe +Tribulation +Skills and Snares +Acid Floor +Wararumbel