From eec2fd28a90c69f1c8d705d7e8e8d5384e74f887 Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 5 Sep 2025 21:01:54 +0200 Subject: [PATCH 1/5] Update BigArrayList dependency - Implement new iterable BigArrayList in various places - Fix formatting in build.gradle --- build.gradle | 32 +++++++------------ settings.gradle | 2 +- .../tasfile/PlaybackSerialiserTest.java | 24 +++----------- .../tasfile/SerialiserFlavorBaseTest.java | 19 ++--------- 4 files changed, 21 insertions(+), 56 deletions(-) diff --git a/build.gradle b/build.gradle index 52d14f78..44320c0e 100644 --- a/build.gradle +++ b/build.gradle @@ -31,16 +31,14 @@ loom { // dependency repositories repositories { mavenCentral() + maven { url = "https://maven.minecrafttas.com/main" } maven { url = 'https://raw.githubusercontent.com/BleachDev/cursed-mappings/main/' } maven { url = "https://jitpack.io" } - maven { url = "https://maven.mgnet.work/main" } maven { url = 'https://repo.spongepowered.org/maven' } } // dependency configurations configurations { - // non-transitive download mod dependency - downloadMod.transitive = false // embed dependency included in build implementation.extendsFrom(embed) } @@ -48,25 +46,19 @@ configurations { // dependencies dependencies { // tasmod dependencies - embed group: 'com.dselent', name: 'bigarraylist', version: '1.1' - //compileOnly group: 'com.minecrafttas', name: 'killtherng', version: '2.0' - //downloadMod group: 'com.minecrafttas', name: 'killtherng-full', version: '2.0' // for downloadKTRNG task + embed "com.dselent:bigarraylist:1.5" + embed "com.github.KaptainWutax:SeedUtils:b6a383113c" // loom dependencies minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.legacyfabric:yarn:${project.minecraft_version}+build.mcp" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // testing dependencies testImplementation 'org.junit.jupiter:junit-jupiter:5.13.3' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } -// task for downloading KillTheRng -//task downloadKTRNG(type: Copy) { - //group 'tasmod' - //description 'Download KillTheRNG to the run/mods/ folder of the project' - //from configurations.downloadMod - //into 'run/mods/' -//} compileJava { options.release = 8 @@ -104,11 +96,11 @@ tasks.named('test', Test) { } spotless { - encoding 'UTF-8' - lineEndings 'UNIX' - java { - importOrderFile('formatter/TASmodImportorder.txt') - eclipse().configFile('formatter/TASmodFormatter.xml') - } - enforceCheck false + encoding 'UTF-8' + lineEndings 'UNIX' + java { + importOrderFile('formatter/TASmodImportorder.txt') + eclipse().configFile('formatter/TASmodFormatter.xml') + } + enforceCheck false } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 7b7f82d9..4e1e9491 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ pluginManagement { // add repositories for plugins repositories { - maven { url = 'https://maven.mgnet.work/main' } + maven { url = "https://maven.minecrafttas.com/main" } maven { url = 'https://maven.fabricmc.net/' } maven { url = 'https://repo.legacyfabric.net/repository/legacyfabric/' } mavenCentral() diff --git a/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java b/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java index 50a3eeda..3dfd9162 100644 --- a/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java +++ b/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java @@ -7,7 +7,6 @@ import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; -import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -200,7 +199,7 @@ void testSerialiser() { try { BigArrayList actual = PlaybackSerialiser.loadFromFile(file, testFlavor); - assertBigArrayList(expected, actual); + assertIterableEquals(expected, actual); assertEquals("testing", testMetadata.actual); } catch (PlaybackLoadException | IOException e) { fail(e); @@ -267,7 +266,7 @@ void testDeserialiser() throws PlaybackLoadException, IOException { expected.add(new InputContainer(new VirtualKeyboard(), mouse3, cameraAngle3)); - assertBigArrayList(expected, actual); + assertIterableEquals(expected, actual); assertEquals("Wat", testMetadata.actual); @@ -278,7 +277,7 @@ void testDeserialiser() throws PlaybackLoadException, IOException { fclist.add(fccontainer); fclist.add(new SortedFileCommandContainer()); fclist.add(new SortedFileCommandContainer()); - assertBigArrayList(fclist, testFileCommand.getInlineStorage()); + assertIterableEquals(fclist, testFileCommand.getInlineStorage()); BigArrayList fclistEnd = new BigArrayList<>(); SortedFileCommandContainer fccontainerEnd = new SortedFileCommandContainer(); @@ -290,7 +289,7 @@ void testDeserialiser() throws PlaybackLoadException, IOException { fclistEnd.add(fccontainerEnd); fclistEnd.add(new SortedFileCommandContainer()); fclistEnd.add(new SortedFileCommandContainer()); - assertBigArrayList(fclistEnd, testFileCommand.getEndlineStorage()); + assertIterableEquals(fclistEnd, testFileCommand.getEndlineStorage()); } @Test @@ -353,7 +352,7 @@ void testDeserialiserNoExtensions() throws PlaybackLoadException, IOException { expected.add(new InputContainer(new VirtualKeyboard(), mouse3, cameraAngle3)); - assertBigArrayList(expected, actual); + assertIterableEquals(expected, actual); assertEquals("e", testMetadata.actual); @@ -389,18 +388,5 @@ void testFlavorIsNull() { }); assertEquals("Flavor name NotAFlavor doesn't exist.", t.getMessage()); - - } - - private void assertBigArrayList(BigArrayList expected, BigArrayList actual) { - assertIterableEquals(convertBigArrayListToArrayList(expected), convertBigArrayListToArrayList(actual)); - } - - private ArrayList convertBigArrayListToArrayList(BigArrayList list) { - ArrayList out = new ArrayList<>(); - for (long i = 0; i < list.size(); i++) { - out.add(list.get(i)); - } - return out; } } diff --git a/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java b/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java index 6481476f..29276d55 100644 --- a/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java +++ b/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java @@ -6,7 +6,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; @@ -231,7 +230,7 @@ void testSerialiseContainer() { expected.add("\t3|||4.0;4.0"); // C o m p a r e - assertBigArrayList(expected, actual); + assertIterableEquals(expected, actual); } /** @@ -714,7 +713,7 @@ void testDeserialiseContainer() { expected.add(new InputContainer(keyboard, mouse, cameraAngle)); - assertBigArrayList(expected, actual); + assertIterableEquals(expected, actual); } /** @@ -733,7 +732,7 @@ void testSplitInputs() { List actualComment = new ArrayList<>(); UnsortedFileCommandContainer actualFileCommand = new UnsortedFileCommandContainer(); - splitInputs(tick, actualKeyboard, actualMouse, actualCameraAngle, actualComment, actualFileCommand); + splitTickLines(tick, actualKeyboard, actualMouse, actualCameraAngle, actualComment, actualFileCommand); List expectedKeyboard = new ArrayList<>(); List expectedMouse = new ArrayList<>(); @@ -1078,18 +1077,6 @@ void testYawUnclamping() { assertEquals(-190f, unclampYaw(170f, -170f)); } - private void assertBigArrayList(BigArrayList expected, BigArrayList actual) { - assertIterableEquals(convertBigArrayListToArrayList(expected), convertBigArrayListToArrayList(actual)); - } - - private ArrayList convertBigArrayListToArrayList(BigArrayList list) { - ArrayList out = new ArrayList<>(); - for (long i = 0; i < list.size(); i++) { - out.add(list.get(i)); - } - return out; - } - @Override public SerialiserFlavorBase clone() { return new SerialiserFlavorBaseTest(); From aa0547350a42b9cc6e8a5170c8ffac26934fe182 Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 5 Sep 2025 21:01:54 +0200 Subject: [PATCH 2/5] [PlaybackSerialiser] More documentation - Added more iterable BigArrayLists --- .../filecommands/PlaybackFileCommand.java | 160 +++++++++++++++++- .../playback/tasfile/PlaybackSerialiser.java | 35 +++- .../tasfile/flavor/SerialiserFlavorBase.java | 71 ++++++-- 3 files changed, 244 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java index 510473e7..428a16d0 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java @@ -11,19 +11,37 @@ import com.minecrafttas.mctcommon.file.AbstractDataFile; import com.minecrafttas.mctcommon.registry.Registerable; import com.minecrafttas.tasmod.TASmodClient; +import com.minecrafttas.tasmod.commands.CommandFileCommand; +import com.minecrafttas.tasmod.playback.PlaybackControllerClient; import com.minecrafttas.tasmod.playback.PlaybackControllerClient.InputContainer; +import com.minecrafttas.tasmod.playback.tasfile.PlaybackSerialiser; import com.minecrafttas.tasmod.playback.tasfile.flavor.SerialiserFlavorBase; public class PlaybackFileCommand { + /** + * The name of the fileCommand + */ private String name; + /** + * The arguments of the fileCommand + */ private String[] args; + /** + * Creates a new FileCommand with no arguments + * @param name The {@link #name} + */ public PlaybackFileCommand(String name) { this(name, (String[]) null); } + /** + * Creates a new FileCommand + * @param name The {@link #name} + * @param args The {@link #args}r + */ public PlaybackFileCommand(String name, String... args) { if (args == null) { args = new String[] {}; @@ -32,10 +50,16 @@ public PlaybackFileCommand(String name, String... args) { this.args = args; } + /** + * @return {@link #name} + */ public String getName() { return name; } + /** + * @return {@link #args} + */ public String[] getArgs() { return args; } @@ -94,6 +118,12 @@ public PlaybackFileCommandExtension(String tempFolderName) { this(TASmodClient.tasfiledirectory.resolve("temp").resolve(tempFolderName)); } + /** + *

Creates a FileCommandExtension and creates a temp folder with
+ * at the specified path for the {@link BigArrayList} files + * + * @param tempFolderName The name of the temp folder + */ public PlaybackFileCommandExtension(Path tempDirectory) { if (tempDirectory == null) { tempDir = null; @@ -112,16 +142,56 @@ public PlaybackFileCommandExtension(Path tempDirectory) { endlineFileCommandStorage = new BigArrayList<>(tempDir.toString()); } + /** + * Whether this extension is enabled.
+ * Can be changed e.g. via the {@link CommandFileCommand} command + */ protected boolean enabled = false; + /** + *

The names of all file commands that should be handled by this extension + *

Imagine having the following file commands in the playback file: + *

+		 * // $desyncMonitor(13, 0, 1, 1, 1, 1); $hud(true);
+		 * 
+ * And you want to support the hud file command with an extension,
+ * then you must return a string array with the name: + *
+		 * public String[] getFileCommandNames() {
+		 * 	return new String[]{"hud"};
+		 * }
+		 * 
+ * Now, methods like {@link #onDeserialiseEndlineComment(long, InputContainer, SortedFileCommandContainer) onDeserialiseEndlineComment} + * will only have a {@link SortedFileCommandContainer}
+ * with the "hud" {@link FileCommandsInTickList} as a parameter. "desyncMonitor" will be ignored. + *

+ * To also include "desyncMonitor" in the {@link SortedFileCommandContainer}, simply add that name to the array: + *

+		 * public String[] getFileCommandNames() {
+		 * 	return new String[]{"hud", "desyncMonitor"};
+		 * }
+		 * 
+ * + * @return A string array of file command names + */ public abstract String[] getFileCommandNames(); + /** + * Fired when using the {@link CommandFileCommand} and setting this extension to enabled + */ public void onEnable() { }; + /** + * Fired when using the {@link CommandFileCommand} and setting this extension to disabled + */ public void onDisable() { }; + /** + * Fired when {@link PlaybackControllerClient#clear()} is called
+ * Make sure to call super.onClear() as it clears the {@link BigArrayLists} in this extension! + */ public void onClear() { try { inlineFileCommandStorage.clearMemory(); @@ -133,12 +203,32 @@ public void onClear() { endlineFileCommandStorage = new BigArrayList<>(); }; + /** + * Fired when the {@link PlaybackControllerClient} is recording inputs
+ * Usually used to generate new FileCommands during recording. + * @param tick The current tick in the recording + * @param inputContainer The current inputs in the recording + */ public void onRecord(long tick, InputContainer inputContainer) { }; + /** + * Fired when the {@link PlaybackControllerClient} is playing back inputs.
+ * Usually used to generate new FileCommands during playback. + * @param tick The current tick in the playback + * @param inputContainer The current inputs in the playback + */ public void onPlayback(long tick, InputContainer inputContainer) { }; + /** + * Fired when the {@link PlaybackSerialiser} writes the inputs to a file.
+ * This is used to store your inlineFileCommands into an comment. + * + * @param tick The current tick that is serialised + * @param inputContainer The current inputs that are being serialised + * @return A {@link SortedFileCommandContainer} with your filecommands for one container that you want serialised + */ public SortedFileCommandContainer onSerialiseInlineComment(long tick, InputContainer inputContainer) { SortedFileCommandContainer out = new SortedFileCommandContainer(); if (tick >= inlineFileCommandStorage.size()) @@ -155,6 +245,14 @@ public SortedFileCommandContainer onSerialiseInlineComment(long tick, InputConta return out; } + /** + * Fired when the {@link PlaybackSerialiser} writes the inputs to a file.
+ * This is used to store your endlineFileCommands into an comment. + * + * @param tick The current tick that is serialised + * @param inputContainer The current inputs that are being serialised + * @return A {@link SortedFileCommandContainer} with your filecommands for one container that you want serialised + */ public SortedFileCommandContainer onSerialiseEndlineComment(long tick, InputContainer inputContainer) { SortedFileCommandContainer out = new SortedFileCommandContainer(); if (tick >= endlineFileCommandStorage.size()) @@ -171,24 +269,47 @@ public SortedFileCommandContainer onSerialiseEndlineComment(long tick, InputCont return out; } - public void onDeserialiseInlineComment(long tick, InputContainer container, SortedFileCommandContainer fileCommandContainer) { + /** + * Fired when the {@link PlaybackSerialiser} reads the inputs from a file.
+ * This is used to load your inlineFileCommands from a comment into {@link #inlineFileCommandStorage} to be used in {@link #onPlayback(long, InputContainer)}. + * + * @param tick The current tick that is deserialised + * @param inputContainer The current inputs that are being deserialised + * @param fileCommandContainer The {@link SortedFileCommandContainer} that was deserialised + */ + public void onDeserialiseInlineComment(long tick, InputContainer inputContainer, SortedFileCommandContainer fileCommandContainer) { if (fileCommandContainer == null) return; inlineFileCommandStorage.add(fileCommandContainer); } - public void onDeserialiseEndlineComment(long tick, InputContainer container, SortedFileCommandContainer fileCommandContainer) { + /** + * Fired when the {@link PlaybackSerialiser} reads the inputs from a file.
+ * This is used to load your endlineFileCommands from a comment into {@link #endlineFileCommandStorage} to be used in {@link #onPlayback(long, InputContainer)}. + * + * @param tick The current tick that is deserialised + * @param inputContainer The current inputs that are being deserialised + * @param fileCommandContainer The {@link SortedFileCommandContainer} that was deserialised + */ + public void onDeserialiseEndlineComment(long tick, InputContainer inputContainer, SortedFileCommandContainer fileCommandContainer) { if (fileCommandContainer == null) return; endlineFileCommandStorage.add(fileCommandContainer); } + /** + * @return {@link #enabled} + */ public boolean isEnabled() { return enabled; } + /** + * Set {@link #enabled} and run {@link #onEnable()} and {@link #onDisable()} + * @param enabled Sets {@link #enabled} + */ public void setEnabled(boolean enabled) { if (enabled) onEnable(); @@ -239,8 +360,8 @@ public static class FileCommandsInCommentList extends ArrayListThis would translate into an ArrayList like *
 	 * [
-	 * 	[$desyncMonitor(13, 0, 1, 1, 1, 1);, $hud(true);]	<- One {@link FileCommandsInCommentList}
-	 * 	[$desyncMonitor(16, 3, 1, 1, 1, 1);, $hud(false);]
+	 * 	[$desyncMonitor(13, 0, 1, 1, 1, 1);, $hud(true);],	<- One {@link FileCommandsInCommentList}
+	 * 	[$desyncMonitor(16, 3, 1, 1, 1, 1);, $hud(false);],
 	 * 	[$label(Test);, $hud(false);]
 	 * ]
 	 * 
@@ -259,6 +380,28 @@ public SortedFileCommandContainer sort() { /* * Fill the HashMap in SortedFileCommandContainer with empty FileCommandsInCommentList * for each different FileCommand name found in this UnsortedFileCommandContainer. + * + * We have to do this, since absent FileCommands are set to null. + * + * Example: + * // $desyncMonitor(13, 0, 1, 1, 1, 1); $hud(true); + * // $desyncMonitor(16, 3, 1, 1, 1, 1); $hud(false); + * // $label(Test); $hud(false); + * + * In line 1, the "label" FC is missing + * In line 2, once again, "label is missing + * In line 3, desyncMonitor is missing. + * + * If it's missing, we need to set that spot to null. + * + * So first we create empty Hashmaps for each: + * { + * "desyncMonitor": [], + * "hud": [], + * "label": [] + * } + * + * Then iterate through all filecommands and set null where a FileCommand is absent */ for (FileCommandsInCommentList unsortedFileCommandsList : this) { if (unsortedFileCommandsList != null) { @@ -268,7 +411,7 @@ public SortedFileCommandContainer sort() { } } - /** + /* * Add the FileCommands to the previously created FileCommandsInCommentLists */ for (FileCommandsInCommentList unsortedFileCommandsList : this) { @@ -285,7 +428,7 @@ public SortedFileCommandContainer sort() { boolean valuePresent = false; if (unsortedFileCommandsList != null) { - /** + /* * Iterates through all filecommands in a comment * and adds it to the sorted list if found */ @@ -296,7 +439,7 @@ public SortedFileCommandContainer sort() { } } } - /** + /* * If the value is not found, * add null to indicate that the * file command is missing from this comment @@ -336,9 +479,10 @@ public static class FileCommandsInTickList extends ArrayListA LinkedHashMap for storing {@link FileCommandsInCommentList} sorted by the name of the FileCommand name. + *

A LinkedHashMap for storing {@link FileCommandsInTickList} sorted by the name of the FileCommand name. *

The key represents the FileCommand name, while the elements are the {@link FileCommandsInTickList} *

This stands in contrast to the {@link UnsortedFileCommandContainer}, which can be obtained by calling {@link SortedFileCommandContainer#unsort() unsort()} + *

Used in {@link PlaybackFileCommandExtension PlaybackFileCommandExtensions} as this format makes it easier to distribute the file commands to their respective class extensions *

Example
*
 	 * // $desyncMonitor(13, 0, 1, 1, 1, 1); $hud(true);
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
index 06e838d3..1b5ba234 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
@@ -16,6 +16,7 @@
 import com.minecrafttas.tasmod.playback.tasfile.exception.PlaybackSaveException;
 import com.minecrafttas.tasmod.playback.tasfile.flavor.SerialiserFlavorBase;
 import com.minecrafttas.tasmod.registries.TASmodAPIRegistry;
+import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
 import com.minecrafttas.tasmod.util.FileThread;
 
 /**
@@ -25,6 +26,10 @@
  */
 public class PlaybackSerialiser {
 
+	/**
+	 * The default flavor name used for saving TASfiles when no flavor is specified,
+ * used in {@link #saveToFile(Path, BigArrayList, String, long)} + */ private static String defaultFlavor = "beta1"; /** @@ -112,8 +117,8 @@ public static void saveToFile(Path path, BigArrayList container, } BigArrayList tickLines = flavor.serialise(container, stopIndex); - for (long i = 0; i < tickLines.size(); i++) { - writerThread.addLine(tickLines.get(i)); + for (String tickLine : tickLines) { + writerThread.addLine(tickLine); } writerThread.close(); @@ -132,6 +137,19 @@ public static BigArrayList loadFromFile(Path file) throws Playba return loadFromFile(file, true); } + /** + * Loads a BigArrayList of {@link InputContainer InputContainers} from a file.
+ * Tries to determine the {@link SerialiserFlavorBase flavor} by reading the header of the TASfile + * + *

Has a parameter to stop processing extension data, usually used when + * {@link SavestateHandlerClient#loadstate(String) loading savestates} to prevent loadstates from overwriting data + * + * @param file The file to load from + * @param processExtensions Sets {@link SerialiserFlavorBase#processExtensions} + * @return The loaded BigArrayList of {@link InputContainer InputContainers} + * @throws PlaybackLoadException If the file contains errors + * @throws IOException If the file could not be read + */ public static BigArrayList loadFromFile(Path file, boolean processExtensions) throws PlaybackLoadException, IOException { if (file == null) { throw new PlaybackLoadException("Load from file failed. No file specified"); @@ -160,6 +178,19 @@ public static BigArrayList loadFromFile(Path file, String flavor return loadFromFile(file, flavorName, true); } + /** + * Loads a BigArrayList of {@link InputContainer InputContainers} from a file, with a specific flavor + * + *

Has a parameter to stop processing extension data, usually used when + * {@link SavestateHandlerClient#loadstate(String) loading savestates} to prevent loadstates from overwriting data + * + * @param file The file to load from + * @param flavorName The name of the {@link SerialiserFlavorBase flavor} to use. If the detected flavor in the TASfile mismatches, a {@link PlaybackLoadException} is thrown + * @param processExtensions Sets {@link SerialiserFlavorBase#processExtensions} + * @return The loaded BigArrayList of {@link InputContainer InputContainers} + * @throws PlaybackLoadException If the file contains errors + * @throws IOException If the file could not be read + */ public static BigArrayList loadFromFile(Path file, String flavorName, boolean processExtensions) throws PlaybackLoadException, IOException { // If the flavor is null or empty, try to determine the flavor by reading the header diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java index 937af70d..02491f98 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java @@ -1014,7 +1014,7 @@ protected void deserialiseEnabledFileCommandNames(List headerLines) { * ├── {@link #deserialiseMultipleInlineComments(List, UnsortedFileCommandContainer)} * │ └── {@link #deserialiseInlineComment(String, FileCommandsInCommentList)} * │ └── {@link #deserialiseFileCommandsInline(String, FileCommandsInCommentList)} - * ├── {@link #splitInputs(List, List, List, List, List, List)} + * ├── {@link #splitTickLines(List, List, List, List, List, List)} * │ └── {@link #deserialiseEndlineComment(String, FileCommandsInCommentList)} * │ └── {@link #deserialiseFileCommandsEndline(String, FileCommandsInCommentList)} * ├── {@link #deserialiseKeyboard(List)} @@ -1092,8 +1092,9 @@ protected enum ExtractPhases { /** *

* Extracts all the lines corresponding to one tick+subticks a.k.a one - * "container" from the incoming lines.
- * The extracted ticks are easier to process than using a huge list.
+ * {@link InputContainer "InputcContainer"} from the incoming lines.
+ * The extracted containers are easier to process than using a huge list.
+ * Furthermore, this method ensures the correct formatting of the lines. *

* A container has multiple parts to it, that are split into * {@link ExtractPhases}
@@ -1147,6 +1148,7 @@ protected enum ExtractPhases { * @param lines The line list * @param startPos The start position of this tick * @return The updated index for the next tick + * @throws PlaybackLoadException When the order of phases is wrong */ protected long extractContainer(List extracted, BigArrayList lines, long startPos) { ExtractPhases phase = ExtractPhases.NONE; @@ -1206,37 +1208,67 @@ protected long extractContainer(List extracted, BigArrayList lin return startPos + counter - 1; } + /** + * Main deserialising method of a single {@link InputContainer} + * + * In each step, incoming lines are broken down to it's components: + * + *

    + *
  1. Lines are split in inline comments and ticks
  2. + *
  3. Inline comments are processed
  4. + *
  5. Tick lines are split into keyboard, mouse, cameraAngle, endlineComments, endlineFileCommands
  6. + *
  7. All components from the previous step get deserialised into actual objects
  8. + *
  9. Optional if {@link #processExtensions} is true: Update FileCommands
  10. + *
+ * + * @param out The list of {@link InputContainers}, passed in by reference + * @param containerLines The lines to deserialise + */ protected void deserialiseContainer(BigArrayList out, List containerLines) { - + // Split lines into comments and ticks List inlineComments = new ArrayList<>(); List tickLines = new ArrayList<>(); splitContainer(containerLines, inlineComments, tickLines); + // Process inline comments UnsortedFileCommandContainer inlineFileCommands = new UnsortedFileCommandContainer(); deserialiseMultipleInlineComments(inlineComments, inlineFileCommands); + // Split ticks into components List keyboardStrings = new ArrayList<>(); List mouseStrings = new ArrayList<>(); List cameraAngleStrings = new ArrayList<>(); List endlineComments = new ArrayList<>(); UnsortedFileCommandContainer endlineFileCommands = new UnsortedFileCommandContainer(); + splitTickLines(tickLines, keyboardStrings, mouseStrings, cameraAngleStrings, endlineComments, endlineFileCommands); - splitInputs(tickLines, keyboardStrings, mouseStrings, cameraAngleStrings, endlineComments, endlineFileCommands); - + /* + * The previous step splits everything into multiple lists. + * However, the process makes it so every list has the same number of elements. + * While this is true for keyboard, mouse and camera, + * endlineComments will have empty lines. + * + * Ideally we want to remove all empty lines, + * however comments do allow empty lines between ticks. + * Therefore we remove empty lines, but starting from the back of the list + */ pruneListEndNull(endlineComments); + // Deserialise each component VirtualKeyboard keyboard = deserialiseKeyboard(keyboardStrings); VirtualMouse mouse = deserialiseMouse(mouseStrings); VirtualCameraAngle cameraAngle = deserialiseCameraAngle(cameraAngleStrings); - CommentContainer comments = new CommentContainer(inlineComments, endlineComments); + CommentContainer comments = new CommentContainer(inlineComments, endlineComments); // Comments don't need deserialisation InputContainer deserialisedContainer = new InputContainer(keyboard, mouse, cameraAngle, comments); + // Update FileCommands if (processExtensions) { TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.handleOnDeserialiseInline(currentTick, deserialisedContainer, inlineFileCommands); TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.handleOnDeserialiseEndline(currentTick, deserialisedContainer, endlineFileCommands); } + // Set the previous input container, used for relative coordinates previousInputContainer = deserialisedContainer; out.add(deserialisedContainer); @@ -1245,11 +1277,18 @@ protected void deserialiseContainer(BigArrayList out, List + * // This is an inline comment + * 57|W,LCONTROL;w|;0,887,626|17.85;-202.74799 // This is an endline comment, but that is still part of a tick and processed later + *
+ * + * @param lines The lines to process + * @param inlineComments The list to add the inline comments + * @param ticks The list to add the ticks to */ protected void splitContainer(List lines, List inlineComments, List ticks) { for (String line : lines) { - if (contains(singleComment(), line)) { + if (contains(inlineComment(), line)) { inlineComments.add(line); } else { ticks.add(line); @@ -1257,6 +1296,11 @@ protected void splitContainer(List lines, List inlineComments, L } } + /** + * + * @param inlineComments + * @param inlineFileCommands + */ protected void deserialiseMultipleInlineComments(List inlineComments, UnsortedFileCommandContainer inlineFileCommands) { for (int i = 0; i < inlineComments.size(); i++) { FileCommandsInCommentList deserialisedFileCommands = new FileCommandsInCommentList(); @@ -1546,7 +1590,7 @@ protected Float deserialiseRelativeFloat(String name, String floatstring, Float return out; } - protected void splitInputs(List lines, List serialisedKeyboard, List serialisedMouse, List serialisedCameraAngle, List commentsAtEnd, UnsortedFileCommandContainer endlineFileCommands) { + protected void splitTickLines(List lines, List serialisedKeyboard, List serialisedMouse, List serialisedCameraAngle, List commentsAtEnd, UnsortedFileCommandContainer endlineFileCommands) { String previousCamera = null; if (previousInputContainer != null) { @@ -1718,12 +1762,15 @@ protected > void pruneListEndEmptySubtickable(List l } /** - * @return The regex used for detecting comment lines + * @return The regex used for detecting inline comments */ - protected String singleComment() { + protected String inlineComment() { return "^//"; } + /** + * @return The regex used for detecting endline comments + */ protected String endlineComment() { return "(//.+)"; } From a1709fca24b97c02ea5a203a5f2fe3be39fb4347 Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 5 Sep 2025 21:20:18 +0200 Subject: [PATCH 3/5] Change all ' to " in gradle files --- build.gradle | 32 ++++++++++++++++---------------- settings.gradle | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/build.gradle b/build.gradle index 44320c0e..6b2e3e15 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ plugins { // loom plugin - id 'fabric-loom' version "${loom_version}" + id "fabric-loom" version "${loom_version}" // legacy looming (loom plugin improvements) - id 'legacy-looming' version "${loom_version}" - id 'com.palantir.git-version' version '3.1.0' - id 'com.diffplug.spotless' version '7.0.3' + id "legacy-looming" version "${loom_version}" + id "com.palantir.git-version" version "3.1.0" + id "com.diffplug.spotless" version "7.0.3" } @@ -23,18 +23,18 @@ java { loom { // set access widener - accessWidenerPath = file('src/main/resources/tasmod.accesswidener') + accessWidenerPath = file("src/main/resources/tasmod.accesswidener") // add log4jconfig - log4jConfigs.from(file('src/main/resources/log4j.xml')) + log4jConfigs.from(file("src/main/resources/log4j.xml")) } // dependency repositories repositories { mavenCentral() maven { url = "https://maven.minecrafttas.com/main" } - maven { url = 'https://raw.githubusercontent.com/BleachDev/cursed-mappings/main/' } + maven { url = "https://raw.githubusercontent.com/BleachDev/cursed-mappings/main/" } maven { url = "https://jitpack.io" } - maven { url = 'https://repo.spongepowered.org/maven' } + maven { url = "https://repo.spongepowered.org/maven" } } // dependency configurations @@ -55,8 +55,8 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // testing dependencies - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.3' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testImplementation "org.junit.jupiter:junit-jupiter:5.13.3" + testRuntimeOnly "org.junit.platform:junit-platform-launcher" } @@ -70,7 +70,7 @@ processResources { inputs.property "mcversion", project.minecraft_version filesMatching("fabric.mod.json") { - expand 'mod_url': project.mod_url, 'name': project.mod_name, 'mod_version': project.version, 'mod_description': project.mod_description, 'mod_sources': project.mod_sources, 'mod_email': project.mod_email + expand "mod_url": project.mod_url, "name": project.mod_name, "mod_version": project.version, "mod_description": project.mod_description, "mod_sources": project.mod_sources, "mod_email": project.mod_email } } @@ -87,7 +87,7 @@ jar { } // configure testing -tasks.named('test', Test) { +tasks.named("test", Test) { useJUnitPlatform() testLogging { @@ -96,11 +96,11 @@ tasks.named('test', Test) { } spotless { - encoding 'UTF-8' - lineEndings 'UNIX' + encoding "UTF-8" + lineEndings "UNIX" java { - importOrderFile('formatter/TASmodImportorder.txt') - eclipse().configFile('formatter/TASmodFormatter.xml') + importOrderFile("formatter/TASmodImportorder.txt") + eclipse().configFile("formatter/TASmodFormatter.xml") } enforceCheck false } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4e1e9491..cdc97026 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,8 +3,8 @@ pluginManagement { // add repositories for plugins repositories { maven { url = "https://maven.minecrafttas.com/main" } - maven { url = 'https://maven.fabricmc.net/' } - maven { url = 'https://repo.legacyfabric.net/repository/legacyfabric/' } + maven { url = "https://maven.fabricmc.net/" } + maven { url = "https://repo.legacyfabric.net/repository/legacyfabric/" } mavenCentral() gradlePluginPortal() } From 241e63e25a09c1db55470e94cb9ab4a330b5b780 Mon Sep 17 00:00:00 2001 From: Scribble Date: Sat, 6 Sep 2025 16:14:55 +0200 Subject: [PATCH 4/5] Finished documentation for SerialiserFlavorBase --- .../playback/tasfile/PlaybackSerialiser.java | 2 +- .../tasfile/flavor/SerialiserFlavorBase.java | 486 +++++++++++++----- .../tasfile/flavor/builtin/AlphaFlavor.java | 2 +- 3 files changed, 369 insertions(+), 121 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java index 1b5ba234..876be822 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java @@ -292,7 +292,7 @@ public static SerialiserFlavorBase readFlavor(Path file) throws PlaybackLoadExce List lines = new ArrayList<>(); String line = null; - // Reads the first 100 lines + // Reads the first 100 lines to search for the flavor for (int i = 0; i < 100; i++) { line = reader.readLine(); diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java index 02491f98..7d6f4e30 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java @@ -53,7 +53,7 @@ * but also a list of enabled extensions and the name of the flavor that was used to encode the file. * *
  • - * Content
    + * Container
    * Contains the actual inputs per tick, inputs in a subtick (a.k.a in a frame), comments and other extensions. *
  • * @@ -122,10 +122,10 @@ public abstract class SerialiserFlavorBase implements Registerable { ==============================================*/ /* - _ _ ____ __ ____ ____ ____ - ( )_( )( ___) /__\ ( _ \( ___)( _ \ - ) _ ( )__) /(__)\ )(_) ))__) ) / - (_) (_)(____)(__)(__)(____/(____)(_)\_) + _ _ ____ __ ____ ____ ____ + / )( \( __) / _\ ( \( __)( _ \ + ) __ ( ) _) / \ ) D ( ) _) ) / + \_)(_/(____)\_/\_/(____/(____)(__\_) */ @@ -134,6 +134,7 @@ public abstract class SerialiserFlavorBase implements Registerable { *
     	 * ##################### TASfile ####################
     	 * 
    + * * @return The very top of the header */ protected String headerStart() { @@ -146,6 +147,7 @@ protected String headerStart() { *
     	 * ##################################################
     	 * 
    + * * @return The end of the header */ protected String headerEnd() { @@ -186,6 +188,7 @@ protected String headerEnd() { * * ################################################## // {@link #headerEnd()} * + * * @return List of lines containing the header */ public List serialiseHeader() { @@ -219,6 +222,7 @@ protected void serialiseFlavorName(List out) { *
     	 * FileCommand-Extensions: tasmod_label@v1, tasmod_desyncMonitor@v1
     	 * 
    + * * @param out The serialised lines, passed by reference */ protected void serialiseEnabledFileCommandNames(List out) { @@ -248,6 +252,7 @@ protected void serialiseEnabledFileCommandNames(List out) { * pitch:29.25007 * yaw:-88.80094 * + * * @param out */ protected void serialiseMetadata(List out) { @@ -285,6 +290,7 @@ protected void serialiseMetadataName(List out, String name) { * Playing Time:00:00.0 * Rerecords:0 * + * * @param out * @param data */ @@ -295,10 +301,10 @@ protected void serialiseMetadataValues(List out, LinkedHashMap out, LinkedHashMap + * * @param inputs The inputs to serialise * @param toTick The tick where to stop, used for partial serialisation by savestates. -1 to serialise all * @return The list of lines @@ -379,6 +386,7 @@ protected void serialiseContainer(BigArrayList out, InputContainer conta * A;a * S,D;sd * + * * @param keyboard The keyboard to serialise * @return A list of serialised keyboardSubticks */ @@ -406,6 +414,7 @@ protected List serialiseKeyboard(VirtualKeyboard keyboard) { *
     	 * 	W,S;ws
     	 * 
    + * * @param keyboardSubtick The subtick to serialise * @return The serialised subtick */ @@ -413,6 +422,23 @@ protected String serialiseKeyboardSubtick(VirtualKeyboard keyboardSubtick) { return String.format("%s;%s", String.join(",", keyboardSubtick.getCurrentPresses()), charListToString(keyboardSubtick.getCharList())); } + /** + *

    Utility method for converting a char list to a string + *

    Replaces line break characters with \\n + * + * @param charList The list to use + * @return The created string + */ + protected String charListToString(List charList) { + String charString = ""; + if (!charList.isEmpty()) { + charString = charList.stream().map(Object::toString).collect(Collectors.joining()); + charString = StringUtils.replace(charString, "\r", "\\n"); + charString = StringUtils.replace(charString, "\n", "\\n"); + } + return charString; + } + /** *

    Serialises a {@link VirtualMouse} *

    A {@link VirtualMouse} is most often comprised of multiple subticks,
    @@ -423,6 +449,7 @@ protected String serialiseKeyboardSubtick(VirtualKeyboard keyboardSubtick) { * RC;-15,15,21 * RC,MC;30,14,20 * + * * @param mouse The mouse to serialise * @return A list of serialised mouse subticks */ @@ -446,6 +473,7 @@ protected List serialiseMouse(VirtualMouse mouse) { *

     	 * 	LC;0,15,21
     	 * 
    + * * @param mouseSubtick The mouse subtick to serialise * @return The serialised mouse subtick */ @@ -463,6 +491,7 @@ protected String serialiseMouseSubtick(VirtualMouse mouseSubtick) { * 34;25 * 140;-130 * + * * @param cameraAngle Camera angle to serialise * @return The serialised list of camera angles */ @@ -505,6 +534,7 @@ protected String serialiseCameraAngleSubtick(VirtualCameraAngle cameraAngleSubti * // Inline comment * 12|W;w||0;0 * + * * @param inlineComments The list of inline comments to serialise * @param fileCommandsInline The list of file commands to serialise * @return List of comments including file commands @@ -565,6 +595,7 @@ protected List serialiseInlineComments(List inlineComments, Unso *
     	 * // Inline comment
     	 * 
    + * * @param comment Content in the comment * @return The inline comment */ @@ -578,6 +609,7 @@ protected String serialiseInlineComment(String comment) { *
     	 *	12|W;w||0;0	// Endline comment
     	 * 
    + * * @param endlineComments The list of endline comments to serialise * @param fileCommandsEndline The list of file commands to serialise * @return The serialised comments @@ -638,6 +670,7 @@ protected List serialiseEndlineComments(List endlineComments, Un *
     	 * // Endline comment
     	 * 
    + * * @param comment Content in the comment * @return The endline comment */ @@ -654,6 +687,7 @@ protected String serialiseEndlineComment(String comment) { *
     	 * 	// $fileCommandName1(argument1); $fileCommandName2(argument1, argument2);
     	 * 
    + * * @param fileCommands The file commands to serialise * @return A string of serialised file commands or null if fileCommands is null */ @@ -678,6 +712,7 @@ protected String serialiseFileCommandsInline(FileCommandsInCommentList fileComma *
     	 * 	12|W;w||0;0	// $fileCommandName1(argument1); $fileCommandName2(argument1, argument2);
     	 * 
    + * * @param fileCommands The file commands to serialise * @return A string of serialised file commands or null if fileCommands is null */ @@ -694,6 +729,7 @@ protected String serialiseFileCommandsEndline(FileCommandsInCommentList fileComm * * *

    Has to check if {@link #processExtensions} is false + * * @param fileCommand The {@link PlaybackFileCommand} to serialise * @return The serialised file command, empty if {@link #processExtensions} is false */ @@ -713,6 +749,7 @@ protected String serialiseFileCommand(PlaybackFileCommand fileCommand) { * 1|W,S;s|;0,0,0|34.47822;82.56482 // $endlineFileCommand(arg) * 2|;||37.02822;79.86482 * + * * @param out The list of lines that will be written to file, passed in by reference * @param serialisedKeyboard The serialised keyboard from {@link #serialiseKeyboard(VirtualKeyboard)} * @param serialisedMouse The serialised mouse from {@link #serialiseMouse(VirtualMouse)} @@ -804,6 +841,7 @@ protected String mergeInput(long currentTick, String keyboard, String mouse, Str * 256|W;w|;0,0,0|31.778223;85.11482 // Parent * 1|W,S;s|;0,0,0|34.47822;82.56482 // Subtick * + * * @param currentSubtick The current subtick in this sequence * @param keyboard The serialised keyboard * @param mouse The serialised mouse @@ -817,6 +855,7 @@ protected String mergeSubtickInput(int currentSubtick, String keyboard, String m /** * If a string is null, return an empty string + * * @param string String to check * @return The string or empty if null */ @@ -871,16 +910,17 @@ protected String joinNotEmpty(String delimiter, String... args) { */ /* - _ _ ____ __ ____ ____ ____ - ( )_( )( ___) /__\ ( _ \( ___)( _ \ - ) _ ( )__) /(__)\ )(_) ))__) ) / - (_) (_)(____)(__)(__)(____/(____)(_)\_) + _ _ ____ __ ____ ____ ____ + / )( \( __) / _\ ( \( __)( _ \ + ) __ ( ) _) / \ ) D ( ) _) ) / + \_)(_/(____)\_/\_/(____/(____)(__\_) */ /** *

    Checks if the name of this flavor is present in the header of the TASfile. *

    Used to determine the flavor of the file if the flavor is not given + * * @param headerLines The lines from the header to check * @return True, if the flavor name is present in the header */ @@ -899,6 +939,7 @@ public boolean checkFlavorName(List headerLines) { *

    Extracts the header from the TASfile *

    Optimization to seperate the header from the actual inputs.
    * Only reads a maximum of 1000 and until it finds {@link #headerEnd()} + * * @param lines The total lines to check * @return The list of lines containing the header * @throws PlaybackLoadException If the end of the header is not found after 1000 lines @@ -927,6 +968,7 @@ public List extractHeader(BigArrayList lines) { * ├── {@link #deserialiseMetadata(List)} * └── {@link #deserialiseEnabledFileCommandNames(List)} * + * * @param headerLines The header lines to deserialise * @see #serialiseHeader() */ @@ -937,6 +979,7 @@ public void deserialiseHeader(List headerLines) { /** *

    Deserialises the TASfile metadata + * * @param headerLines * @see #serialiseMetadata(List) */ @@ -978,6 +1021,7 @@ protected void deserialiseMetadata(List headerLines) { /** *

    Deserialises file command extension names and enables them + * * @param headerLines The header lines to search * @see #serialiseEnabledFileCommandNames(List) * @throws PlaybackLoadException If the "FileCommand-Extensions" keyword is not found in the header @@ -1004,6 +1048,14 @@ protected void deserialiseEnabledFileCommandNames(List headerLines) { throw new PlaybackLoadException("FileCommand-Extensions value was not found in the header"); } + /* + ___ __ __ _ ____ __ __ __ _ ____ ____ + / __)/ \ ( ( \(_ _)/ _\ ( )( ( \( __)( _ \ + ( (__( O )/ / )( / \ )( / / ) _) ) / + \___)\__/ \_)__) (__)\_/\_/(__)\_)__)(____)(__\_) + + */ + /** *

    Deserialises the input part of the TASfile * @@ -1021,6 +1073,7 @@ protected void deserialiseEnabledFileCommandNames(List headerLines) { * ├── {@link #deserialiseMouse(List)} * └── {@link #deserialiseCameraAngle(List)} * + * * @param lines The serialised lines of the TASfile * @param startPos The position when the header ends and the inputs start * @return A list of {@link InputContainer InputContainers} @@ -1044,6 +1097,13 @@ public BigArrayList deserialise(BigArrayList lines, long return out; } + /** + *

    Extract phases for a tick container. + *

    A container has a certain order.
    + * This enum contains phases that are updated when extracting and verifying a container in {@link SerialiserFlavorBase#extractContainer(List, BigArrayList, long)} + * + * @author Scribble + */ protected enum ExtractPhases { /** * Inline comment phase. @@ -1274,6 +1334,13 @@ protected void deserialiseContainer(BigArrayList out, List lines, List inlineComments, L } /** + * Deserialises a list of inline comments into comments and inline file commands * - * @param inlineComments - * @param inlineFileCommands + * @param inlineComments The comments to deserialise. Will contain comments without filecommands + * @param inlineFileCommands The {@link UnsortedFileCommandContainer} passed in by reference */ protected void deserialiseMultipleInlineComments(List inlineComments, UnsortedFileCommandContainer inlineFileCommands) { for (int i = 0; i < inlineComments.size(); i++) { @@ -1315,6 +1383,20 @@ protected void deserialiseMultipleInlineComments(List inlineComments, Un } } + /** + * Processes an inline comment + * + * It + *

      + *
    1. Extracts any inlineFileCommands
    2. + *
    3. Removes the leading // from the comment
    4. + *
    5. Trims the whitespaces
    6. + *
    + * + * @param comment The inline comment to process + * @param deserialisedFileCommands The {@link FileCommandsInCommentList}. Passed in by reference + * @return The processed comment. Null if comment is empty + */ protected String deserialiseInlineComment(String comment, FileCommandsInCommentList deserialisedFileCommands) { comment = deserialiseFileCommandsInline(comment, deserialisedFileCommands); comment = extract("^// ?(.+)", comment, 1); @@ -1327,6 +1409,27 @@ protected String deserialiseInlineComment(String comment, FileCommandsInCommentL return comment; } + /** + * @return The regex used for detecting endline comments + */ + protected String endlineComment() { + return "(//.+)"; + } + + /** + * Processes an endline comment + * + * It + *
      + *
    1. Extracts any endlineFileCommands
    2. + *
    3. Removes the leading // from the comment
    4. + *
    5. Trims the whitespaces
    6. + *
    + * + * @param comment The endline comment to process + * @param deserialisedFileCommands The {@link FileCommandsInCommentList}. Passed in by reference + * @return The processed comment. Null if comment is empty + */ protected String deserialiseEndlineComment(String comment, FileCommandsInCommentList deserialisedFileCommands) { comment = deserialiseFileCommandsEndline(comment, deserialisedFileCommands); comment = extract("^// ?(.+)", comment, 1); @@ -1339,6 +1442,13 @@ protected String deserialiseEndlineComment(String comment, FileCommandsInComment return comment; } + /** + * Extracts and deserialises one or more inlineFileCommands + * + * @param comment The comment to process + * @param deserialisedFileCommands The {@link FileCommandsInCommentList}. Passed in by reference + * @return The comment minus the fileCommands + */ protected String deserialiseFileCommandsInline(String comment, FileCommandsInCommentList deserialisedFileCommands) { Matcher matcher = extract("\\$(.+?)\\((.*?)\\);", comment); @@ -1357,6 +1467,13 @@ protected String deserialiseFileCommandsInline(String comment, FileCommandsInCom return comment; } + /** + * Extracts and deserialises one or more endlineFileCommands + * + * @param comment The comment to process + * @param deserialisedFileCommands The {@link FileCommandsInCommentList}. Passed in by reference + * @return The comment minus the fileCommands + */ protected String deserialiseFileCommandsEndline(String comment, FileCommandsInCommentList deserialisedFileCommands) { Matcher matcher = extract("\\$(.+?)\\((.*?)\\);", comment); @@ -1375,12 +1492,77 @@ protected String deserialiseFileCommandsEndline(String comment, FileCommandsInCo return comment; } + /** + * @return The regex used in {@link #splitTickLines(List, List, List, List, List, UnsortedFileCommandContainer)} + */ + protected String splitTickLineRegex() { + return "^\\t?\\d+\\|(.*?)\\|(.*?)\\|(\\S*)\\s?"; + } + + /** + * Splits tick lines into it's components + * + * @param lines The lines to split + * @param serialisedKeyboard The empty keyboard list to add to, passed in by reference + * @param serialisedMouse The empty mouse list to add to, passed in by reference + * @param serialisedCameraAngle The empty camera angle list to add to, passed in by reference + * @param commentsAtEnd The empty comments list to add to, passed in by reference + * @param endlineFileCommands The empty file commands list to add to, passed in by reference + */ + protected void splitTickLines(List lines, List serialisedKeyboard, List serialisedMouse, List serialisedCameraAngle, List commentsAtEnd, UnsortedFileCommandContainer endlineFileCommands) { + + String previousCamera = null; + if (previousInputContainer != null) { + VirtualCameraAngle camera = previousInputContainer.getCameraAngle(); + previousCamera = String.format("%s;%s", camera.getYaw(), camera.getPitch()); + } + + for (String line : lines) { + Matcher tickMatcher = extract(splitTickLineRegex(), line); + + if (tickMatcher.find()) { + if (!tickMatcher.group(1).isEmpty()) { + serialisedKeyboard.add(tickMatcher.group(1)); + } + if (!tickMatcher.group(2).isEmpty()) { + serialisedMouse.add(tickMatcher.group(2)); + } + + if (!tickMatcher.group(3).isEmpty()) { + serialisedCameraAngle.add(tickMatcher.group(3)); + previousCamera = tickMatcher.group(3); + } else { + if (previousCamera != null) + serialisedCameraAngle.add(previousCamera); + } + + FileCommandsInCommentList deserialisedFileCommands = new FileCommandsInCommentList(); + + String endlineComment = line.substring(tickMatcher.group(0).length()); + commentsAtEnd.add(deserialiseEndlineComment(endlineComment, deserialisedFileCommands)); + + if (deserialisedFileCommands.isEmpty()) + deserialisedFileCommands = null; + + endlineFileCommands.add(deserialisedFileCommands); + } + } + } + + /** + * Deserialises a list of keyboard strings in a tick + * + * @param keyboardStrings The list to process + * @return The {@link VirtualKeyboard} of this tick + * @throws PlaybackLoadException When the user made an error in the file + */ protected VirtualKeyboard deserialiseKeyboard(List keyboardStrings) { VirtualKeyboard out = new VirtualKeyboard(); currentSubtick = 0; for (String line : keyboardStrings) { Matcher matcher = extract("(.*?);(.*)", line); + if (matcher.find()) { String[] keys = matcher.group(1).split(","); char[] chars = matcher.group(2).toCharArray(); @@ -1395,6 +1577,13 @@ protected VirtualKeyboard deserialiseKeyboard(List keyboardStrings) { return out; } + /** + * Deserialises a list of mouse strings in a tick + * + * @param mouseStrings The list to process + * @return The {@link VirtualMouse} of this tick + * @throws PlaybackLoadException When the user made an error in the file + */ protected VirtualMouse deserialiseMouse(List mouseStrings) { VirtualMouse out = new VirtualMouse(); @@ -1433,6 +1622,13 @@ protected VirtualMouse deserialiseMouse(List mouseStrings) { return out; } + /** + * Deserialises a list of cameraAngle strings in a tick + * + * @param cameraAngleStrings The list to process + * @return The {@link VirtualCameraAngle} of this tick + * @throws PlaybackLoadException When the user made an error in the file + */ protected VirtualCameraAngle deserialiseCameraAngle(List cameraAngleStrings) { VirtualCameraAngle out = new VirtualCameraAngle(null, null, false); @@ -1470,6 +1666,13 @@ protected VirtualCameraAngle deserialiseCameraAngle(List cameraAngleStri return out; } + /** + * Deserialises keypresses in one subtick + * + * @param keyString The list of keyStrings in the current subtick + * @return A {@link Set} of integer keycodes + * @throws PlaybackLoadException When the user made an error in the file + */ protected Set deserialiseVirtualKeyboardKey(String[] keyString) { Set out = new HashSet<>(); @@ -1490,6 +1693,13 @@ protected Set deserialiseVirtualKeyboardKey(String[] keyString) { return out; } + /** + * Deserialises mousepresses in one subtick + * + * @param keyString The list of keyStrings in the current subtick + * @return A {@link Set} of integer keycodes + * @throws PlaybackLoadException When the user made an error in the file + */ protected Set deserialiseVirtualMouseKey(String[] keyString) { Set out = new HashSet<>(); @@ -1510,6 +1720,19 @@ protected Set deserialiseVirtualMouseKey(String[] keyString) { return out; } + /** + *

    Deserialises a singular VirtualKey. + * This could be either a keyboard or a mouse key + * + *

    All key names supported are listed in {@link VirtualKey}. + * + *

    Also can process literal integer keycode strings like 17. + * + * @param key The key string to check + * @param keyValidator An external validator to check. Used for mouse and keyboard as they have different keycode ranges + * @return The keycode of the string key or null if key is empty + * @throws PlaybackLoadException When a keycode can't be parsed + */ protected Integer deserialiseVirtualKey(String key, WrongKeyCheck keyValidator) { Integer vkey = null; @@ -1534,11 +1757,25 @@ else if (isNumeric(key)) { return vkey; } + /** + * Lambda for checking keycode ranges + * + * @see SerialiserFlavorBase#deserialiseVirtualKey(String, WrongKeyCheck) + * @author Scribble + */ @FunctionalInterface protected interface WrongKeyCheck { public void checkKey(int key) throws PlaybackLoadException; } + /** + * Wrapper around {@link Integer#parseInt(String)} + * + * @param name The name what is currently being parsed, used in error messages + * @param intstring The string to parse + * @return The parsed integer + * @throws PlaybackLoadException If a {@link NumberFormatException} is thrown during parsing + */ protected int parseInt(String name, String intstring) { try { return Integer.parseInt(intstring); @@ -1547,6 +1784,16 @@ protected int parseInt(String name, String intstring) { } } + /** + *

    Deserialises values in the form of "~10". + *

    These values will be compared and added to the value from the previous tick or subtick + * + * @param name The name what is currently being parsed, used in error messages + * @param intstring The string to parse + * @param previous The value from the previous tick + * @return The parsed and adjusted integer + * @throws PlaybackLoadException If a {@link NumberFormatException} is thrown during parsing + */ protected int deserialiseRelativeInt(String name, String intstring, Integer previous) { int out = 0; if (intstring.startsWith("~")) { @@ -1563,6 +1810,14 @@ protected int deserialiseRelativeInt(String name, String intstring, Integer prev return out; } + /** + * Wrapper around {@link Float#parseFloat(String)} + * + * @param name The name what is currently being parsed, used in error messages + * @param floatstring The string to parse + * @return The parsed float + * @throws PlaybackLoadException If a {@link NumberFormatException} is thrown during parsing + */ protected float parseFloat(String name, String floatstring) { try { return Float.parseFloat(floatstring); @@ -1571,6 +1826,16 @@ protected float parseFloat(String name, String floatstring) { } } + /** + *

    Deserialises values in the form of "~10.0". + *

    These values will be compared and added to the value from the previous tick or subtick + * + * @param name The name what is currently being parsed, used in error messages + * @param floatstring The string to parse + * @param previous The value from the previous tick + * @return The parsed and adjusted float + * @throws PlaybackLoadException If a {@link NumberFormatException} is thrown during parsing + */ protected Float deserialiseRelativeFloat(String name, String floatstring, Float previous) { if (floatstring == null) return null; @@ -1590,50 +1855,13 @@ protected Float deserialiseRelativeFloat(String name, String floatstring, Float return out; } - protected void splitTickLines(List lines, List serialisedKeyboard, List serialisedMouse, List serialisedCameraAngle, List commentsAtEnd, UnsortedFileCommandContainer endlineFileCommands) { - - String previousCamera = null; - if (previousInputContainer != null) { - VirtualCameraAngle camera = previousInputContainer.getCameraAngle(); - previousCamera = String.format("%s;%s", camera.getYaw(), camera.getPitch()); - } - - for (String line : lines) { - Matcher tickMatcher = extract(splitInputRegex(), line); - - if (tickMatcher.find()) { - if (!tickMatcher.group(1).isEmpty()) { - serialisedKeyboard.add(tickMatcher.group(1)); - } - if (!tickMatcher.group(2).isEmpty()) { - serialisedMouse.add(tickMatcher.group(2)); - } - - if (!tickMatcher.group(3).isEmpty()) { - serialisedCameraAngle.add(tickMatcher.group(3)); - previousCamera = tickMatcher.group(3); - } else { - if (previousCamera != null) - serialisedCameraAngle.add(previousCamera); - } - - FileCommandsInCommentList deserialisedFileCommands = new FileCommandsInCommentList(); - - String endlineComment = line.substring(tickMatcher.group(0).length()); - commentsAtEnd.add(deserialiseEndlineComment(endlineComment, deserialisedFileCommands)); - - if (deserialisedFileCommands.isEmpty()) - deserialisedFileCommands = null; - - endlineFileCommands.add(deserialisedFileCommands); - } - } - } - - protected String splitInputRegex() { - return "^\\t?\\d+\\|(.*?)\\|(.*?)\\|(\\S*)\\s?"; - } - + /** + * Utility method to extract something with regex + * + * @param regex The regex to use + * @param haystack The string to search + * @return The {@link Matcher} for this regex + */ protected Matcher extract(String regex, String haystack) { Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); Matcher matcher = pattern.matcher(haystack); @@ -1641,6 +1869,14 @@ protected Matcher extract(String regex, String haystack) { return matcher; } + /** + * Utility method to extract something with regex and a group + * + * @param regex The regex to use + * @param haystack The string to search + * @param group The group to extract + * @return The extracted string + */ protected String extract(String regex, String haystack, int group) { Matcher matcher = extract(regex, haystack); if (matcher.find()) { @@ -1649,32 +1885,45 @@ protected String extract(String regex, String haystack, int group) { return null; } + /** + * Utility method to check if a string contains a regex patterns + * + * @param regex The regex to use + * @param haystack The string to search + * @return True if the string contains the regex pattern + */ protected boolean contains(String regex, String haystack) { return extract(regex, haystack).find(); } + /** + * Utility method to check if the string is numeric + * + * @param string The string to search + * @return True if the string is numeric + */ protected boolean isNumeric(String string) { return Pattern.matches("-?\\d+", string); } - protected boolean isFloat(String string) { - return Pattern.matches("-?\\d+(?:\\.\\d+)?", string); - } - /** - * @return {@link #currentTick} + * Utility method to check if the string is a float + * + * @param string The string to search + * @return True if the string is a float */ - public long getCurrentTick() { - return currentTick; + protected boolean isFloat(String string) { + return Pattern.matches("-?\\d+(?:\\.\\d+)?", string); } /** - * @return {@link #currentSubtick} + * Utility method for creating a centered text + * + * @param text The text to center + * @param spacingChar The char which should be used for spacing + * @param headingWidth The total width + * @return The centered text */ - public Integer getCurrentSubtick() { - return currentSubtick; - } - public static String createCenteredHeading(String text, char spacingChar, int headingWidth) { if (text == null || text.isEmpty()) { @@ -1691,6 +1940,13 @@ public static String createCenteredHeading(String text, char spacingChar, int he return String.format("%s%s%s", paddingPre, text, paddingSuf); } + /** + * Utility method for repeating a char a certain amount + * + * @param spacingChar The char to use + * @param width The width to repeat the char + * @return The paddedString + */ private static String createPaddedString(char spacingChar, int width) { char[] spacingLine = new char[width]; for (int i = 0; i < spacingLine.length; i++) { @@ -1699,7 +1955,7 @@ private static String createPaddedString(char spacingChar, int width) { return new String(spacingLine); } - public static void addAll(BigArrayList list, BigArrayList toAdd) { + public static void addAll(BigArrayList list, BigArrayList toAdd) { //TODO Add this to BigArrayList itself for (int i = 0; i < toAdd.size(); i++) { T element = toAdd.get(i); list.add(element); @@ -1761,55 +2017,9 @@ protected > void pruneListEndEmptySubtickable(List l } } - /** - * @return The regex used for detecting inline comments - */ - protected String inlineComment() { - return "^//"; - } - - /** - * @return The regex used for detecting endline comments - */ - protected String endlineComment() { - return "(//.+)"; - } - - @Override - public abstract SerialiserFlavorBase clone(); - - @Override - public boolean equals(Object obj) { - if (obj instanceof SerialiserFlavorBase) { - SerialiserFlavorBase flavor = (SerialiserFlavorBase) obj; - return this.getExtensionName().equals(flavor.getExtensionName()); - } - return super.equals(obj); - } - - /** - * Set if extensions should be loaded. - * - * Setting this to false will stop {@link TASmodAPIRegistry#PLAYBACK_FILE_COMMAND} and {@link TASmodAPIRegistry#PLAYBACK_METADATA} from being processed - * - * @param processExtensions - */ - public void setProcessExtensions(boolean processExtensions) { - this.processExtensions = processExtensions; - } - - protected String charListToString(List charList) { - String charString = ""; - if (!charList.isEmpty()) { - charString = charList.stream().map(Object::toString).collect(Collectors.joining()); - charString = StringUtils.replace(charString, "\r", "\\n"); - charString = StringUtils.replace(charString, "\n", "\\n"); - } - return charString; - } - /** *

    Clamps the yaw to a value between -180 and 180 + * * @param yaw The yaw to clamp * @return The clamped yaw */ @@ -1828,6 +2038,7 @@ protected Float clampYaw(Float yaw) { *

    Unclamping the yaw from a clamped value *

    Makes it so 170 and a previous value of -170 will return -190,
    * removing the -180 180 clamp. Uses {@link #yawRotations} + * * @param yaw The yaw to unclamp * @param previous The previous yaw to compare against. * @return The unclamped yaw @@ -1846,8 +2057,45 @@ protected Float unclampYaw(Float yaw, Float previous) { return yaw + (360 * yawRotations); } + /** + * Set if extensions should be loaded. + * + * Setting this to false will stop {@link TASmodAPIRegistry#PLAYBACK_FILE_COMMAND} and {@link TASmodAPIRegistry#PLAYBACK_METADATA} from being processed + * + * @param processExtensions + */ + public void setProcessExtensions(boolean processExtensions) { + this.processExtensions = processExtensions; + } + + /** + * @return {@link #currentTick} + */ + public long getCurrentTick() { + return currentTick; + } + + /** + * @return {@link #currentSubtick} + */ + public Integer getCurrentSubtick() { + return currentSubtick; + } + @Override public String toString() { return getExtensionName(); } + + @Override + public abstract SerialiserFlavorBase clone(); + + @Override + public boolean equals(Object obj) { + if (obj instanceof SerialiserFlavorBase) { + SerialiserFlavorBase flavor = (SerialiserFlavorBase) obj; + return this.getExtensionName().equals(flavor.getExtensionName()); + } + return super.equals(obj); + } } diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/builtin/AlphaFlavor.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/builtin/AlphaFlavor.java index 48c313b6..a81d2057 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/builtin/AlphaFlavor.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/builtin/AlphaFlavor.java @@ -341,7 +341,7 @@ protected void deserialiseMetadata(List headerLines) { } @Override - protected String splitInputRegex() { + protected String splitTickLineRegex() { return "^\\d+\\|(.*?)\\|(.*?)\\|(\\S*)~&"; } From d115de0d7bcdf56a37793d16a8b75a97c7f3e1a5 Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 8 Sep 2025 09:05:23 +0200 Subject: [PATCH 5/5] Update to BigArrayList 1.6 --- build.gradle | 3 ++- .../playback/PlaybackControllerClient.java | 12 ++---------- .../filecommands/PlaybackFileCommand.java | 10 ++-------- .../DesyncMonitorFileCommandExtension.java | 8 +------- .../tasfile/flavor/SerialiserFlavorBase.java | 17 +---------------- 5 files changed, 8 insertions(+), 42 deletions(-) diff --git a/build.gradle b/build.gradle index 6b2e3e15..2ad1cb6c 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ loom { repositories { mavenCentral() maven { url = "https://maven.minecrafttas.com/main" } + //maven { url = "https://maven.minecrafttas.com/snapshots" } maven { url = "https://raw.githubusercontent.com/BleachDev/cursed-mappings/main/" } maven { url = "https://jitpack.io" } maven { url = "https://repo.spongepowered.org/maven" } @@ -46,7 +47,7 @@ configurations { // dependencies dependencies { // tasmod dependencies - embed "com.dselent:bigarraylist:1.5" + embed "com.dselent:bigarraylist:1.6" embed "com.github.KaptainWutax:SeedUtils:b6a383113c" // loom dependencies diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 07684e67..4c8a9e55 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -9,8 +9,6 @@ import static com.minecrafttas.tasmod.registries.TASmodPackets.PLAYBACK_SAVE; import static com.minecrafttas.tasmod.registries.TASmodPackets.PLAYBACK_STATE; -import java.io.File; -import java.io.IOException; import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.file.Path; @@ -51,7 +49,6 @@ import com.minecrafttas.tasmod.playback.tasfile.PlaybackSerialiser; import com.minecrafttas.tasmod.playback.tasfile.exception.PlaybackLoadException; import com.minecrafttas.tasmod.playback.tasfile.exception.PlaybackSaveException; -import com.minecrafttas.tasmod.playback.tasfile.flavor.SerialiserFlavorBase; import com.minecrafttas.tasmod.registries.TASmodConfig; import com.minecrafttas.tasmod.registries.TASmodPackets; import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; @@ -572,7 +569,7 @@ public void setInputs(BigArrayList inputs) { public void setInputs(BigArrayList inputs, long index) { clearInputList(); - SerialiserFlavorBase.addAll(this.inputs, inputs); + this.inputs.addAll(inputs); setIndex(index); } @@ -616,12 +613,7 @@ public void clear() { } private void clearInputList() { - try { - inputs.clearMemory(); - } catch (IOException e) { - e.printStackTrace(); - } - inputs = new BigArrayList(tasFileDirectory + File.separator + "temp"); + inputs.clear(); } public VirtualKeyboard getNextPlaybackKeyboard() { diff --git a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java index 428a16d0..b3d8d45e 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommand.java @@ -193,14 +193,8 @@ public void onDisable() { * Make sure to call super.onClear() as it clears the {@link BigArrayLists} in this extension! */ public void onClear() { - try { - inlineFileCommandStorage.clearMemory(); - endlineFileCommandStorage.clearMemory(); - } catch (IOException e) { - e.printStackTrace(); - } - inlineFileCommandStorage = new BigArrayList<>(); - endlineFileCommandStorage = new BigArrayList<>(); + inlineFileCommandStorage.clear(); + endlineFileCommandStorage.clear(); }; /** diff --git a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/builtin/DesyncMonitorFileCommandExtension.java b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/builtin/DesyncMonitorFileCommandExtension.java index aa78fc36..1a383e98 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/builtin/DesyncMonitorFileCommandExtension.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/builtin/DesyncMonitorFileCommandExtension.java @@ -1,6 +1,5 @@ package com.minecrafttas.tasmod.playback.filecommands.builtin; -import java.io.IOException; import java.io.Serializable; import java.nio.file.Path; import java.text.NumberFormat; @@ -356,12 +355,7 @@ private double parseDouble(String doublestring) throws ParseException { @Override public void onClear() { currentValues = null; - try { - monitorContainer.clearMemory(); - } catch (IOException e) { - e.printStackTrace(); - } - monitorContainer = new BigArrayList(); + monitorContainer.clear(); lastStatus = TextFormatting.GRAY + "Empty"; lastPos = ""; lastMotion = ""; diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java index 7d6f4e30..97253cdb 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java @@ -1,6 +1,5 @@ package com.minecrafttas.tasmod.playback.tasfile.flavor; -import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -765,7 +764,7 @@ protected void mergeInputs(BigArrayList out, List serialisedKeyb * // This is an inline comment * 1|||0;0 */ - addAll(out, serialisedInlineComments); + out.addAll(serialisedInlineComments); /* * Copy inputs with ticks and subticks into a queue, @@ -1955,20 +1954,6 @@ private static String createPaddedString(char spacingChar, int width) { return new String(spacingLine); } - public static void addAll(BigArrayList list, BigArrayList toAdd) { //TODO Add this to BigArrayList itself - for (int i = 0; i < toAdd.size(); i++) { - T element = toAdd.get(i); - list.add(element); - } - } - - public static void addAll(BigArrayList list, List toAdd) { - for (int i = 0; i < toAdd.size(); i++) { - T element = toAdd.get(i); - list.add(element); - } - } - /** * Empties the list starting from the back if the values are null *