Skip to content

Commit d2fdf9f

Browse files
committed
[PlaybackSerialiser] Added support for relative coord input (MinecraftTAS#184)
- Added more constructors for PlaybackLoadException - Added tests for coord input
1 parent 06b77fc commit d2fdf9f

File tree

3 files changed

+192
-29
lines changed

3 files changed

+192
-29
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,55 @@
11
package com.minecrafttas.tasmod.playback.tasfile.exception;
22

3+
import com.minecrafttas.tasmod.TASmod;
4+
35
public class PlaybackLoadException extends RuntimeException {
46

7+
public PlaybackLoadException(long tick, int subtick, String msg) {
8+
this(printTick(tick, subtick)+msg);
9+
}
10+
511
public PlaybackLoadException(String msg) {
612
super(msg);
713
}
814

15+
public PlaybackLoadException(long tick, int subtick, String msg, Object... args) {
16+
this(printTick(tick, subtick)+msg, args);
17+
}
18+
919
public PlaybackLoadException(String msg, Object... args) {
1020
super(String.format(msg, args));
1121
}
1222

23+
public PlaybackLoadException(long tick, int subtick, Throwable cause) {
24+
this(printTick(tick, subtick), cause);
25+
}
26+
1327
public PlaybackLoadException(Throwable cause) {
1428
super(cause);
1529
}
30+
31+
public PlaybackLoadException(long tick, int subtick, Throwable cause, String msg) {
32+
this(cause, printTick(tick, subtick)+msg);
33+
}
34+
35+
public PlaybackLoadException(Throwable cause, String msg) {
36+
super(msg, cause, false, false);
37+
}
38+
39+
public PlaybackLoadException(long tick, int subtick, Throwable cause, String msg, Object... args) {
40+
this(cause, printTick(tick, subtick)+msg, args);
41+
}
42+
43+
public PlaybackLoadException(Throwable cause, String msg, Object... args) {
44+
this(cause, String.format(msg, args));
45+
}
46+
47+
private static String printTick(long tick, int subtick) {
48+
return String.format("Tick %s, Subtick %s: ", tick, subtick);
49+
}
50+
51+
@Override
52+
public void printStackTrace() {
53+
TASmod.LOGGER.catching(this);;
54+
}
1655
}

src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public abstract class SerialiserFlavorBase {
3535
/**
3636
* Debug subtick field for error handling
3737
*/
38-
protected Integer currentSubtick = null;
38+
protected int currentSubtick = 0;
3939

4040
public abstract String flavorName();
4141

@@ -256,7 +256,7 @@ protected void mergeInputs(BigArrayList<String> out, List<String> serialisedKeyb
256256

257257
out.add(String.format("\t%s|%s|%s|%s", currentSubtick, kb, ms, ca));
258258
}
259-
currentSubtick = null;
259+
currentSubtick = 0;
260260
}
261261

262262
protected String getOrEmpty(String string) {
@@ -267,7 +267,7 @@ protected String getOrEmpty(String string) {
267267
* Joins strings together but ignores empty strings
268268
*
269269
* @param delimiter The delimiter of the joined string
270-
* @param args The strings to join
270+
* @param args The strings to join
271271
* @return Joined string
272272
*/
273273
protected String joinNotEmpty(String delimiter, Iterable<String> args) {
@@ -302,6 +302,8 @@ protected String joinNotEmpty(String delimiter, String... args) {
302302
*
303303
*/
304304

305+
private TickContainer previousTickContainer = null;
306+
305307
public boolean deserialiseFlavorName(List<String> headerLines) {
306308
for (String line : headerLines) {
307309
Matcher matcher = extract("^Flavor: " + flavorName(), line);
@@ -397,9 +399,11 @@ public BigArrayList<TickContainer> deserialise(BigArrayList<String> lines, long
397399
List<String> tick = new ArrayList<>();
398400
// Extract the tick and set the index
399401
i = extractContainer(tick, lines, i);
402+
currentTick = i;
400403
// Extract container
401404
deserialiseContainer(out, tick);
402405
}
406+
previousTickContainer = null;
403407
return out;
404408
}
405409

@@ -456,6 +460,8 @@ protected void deserialiseContainer(BigArrayList<TickContainer> out, List<String
456460
TASmodRegistry.PLAYBACK_FILE_COMMAND.handleOnDeserialiseInline(currentTick, deserialisedContainer, inlineFileCommands);
457461
TASmodRegistry.PLAYBACK_FILE_COMMAND.handleOnDeserialiseEndline(currentTick, deserialisedContainer, endlineFileCommands);
458462

463+
previousTickContainer = deserialisedContainer;
464+
459465
out.add(deserialisedContainer);
460466
}
461467

@@ -503,13 +509,14 @@ protected String deserialiseFileCommands(String comment, List<PlaybackFileComman
503509
deserialisedFileCommands.add(new PlaybackFileCommand(name, args));
504510
comment = matcher.replaceFirst("");
505511
}
506-
512+
507513
return comment;
508514
}
509515

510516
protected VirtualKeyboard deserialiseKeyboard(List<String> keyboardStrings) {
511517
VirtualKeyboard out = new VirtualKeyboard();
512518

519+
currentSubtick = 0;
513520
for (String line : keyboardStrings) {
514521
Matcher matcher = extract("(.*?);(.*)", line);
515522
if (matcher.find()) {
@@ -519,13 +526,18 @@ protected VirtualKeyboard deserialiseKeyboard(List<String> keyboardStrings) {
519526
int[] keycodes = deserialiseVirtualKey(keys, VirtualKey.ZERO);
520527
out.updateFromState(keycodes, chars);
521528
}
529+
currentSubtick++;
522530
}
523531
return out;
524532
}
525533

526534
protected VirtualMouse deserialiseMouse(List<String> mouseStrings) {
527535
VirtualMouse out = new VirtualMouse();
528536

537+
currentSubtick = 0;
538+
Integer previousCursorX = previousTickContainer == null? null : previousTickContainer.getMouse().getCursorX();
539+
Integer previousCursorY = previousTickContainer== null? null : previousTickContainer.getMouse().getCursorY();
540+
529541
for (String line : mouseStrings) {
530542
Matcher matcher = extract("(.*?);(.+)", line);
531543
if (matcher.find()) {
@@ -538,51 +550,43 @@ protected VirtualMouse deserialiseMouse(List<String> mouseStrings) {
538550
Integer cursorY;
539551

540552
if (functions.length == 3) {
541-
try {
542-
scrollwheel = Integer.parseInt(functions[0]);
543-
cursorX = Integer.parseInt(functions[1]);
544-
cursorY = Integer.parseInt(functions[2]);
545-
} catch (NumberFormatException e) {
546-
throw new PlaybackLoadException(e);
547-
}
553+
scrollwheel = parseInt("scrollwheel", functions[0]);
554+
cursorX = deserialiseRelativeInt("cursorX", functions[1], previousCursorX);
555+
cursorY = deserialiseRelativeInt("cursorY", functions[2], previousCursorY);
548556
} else {
549557
throw new PlaybackLoadException("Mouse functions do not have the correct length");
550558
}
551559

552560
out.updateFromState(keycodes, scrollwheel, cursorX, cursorY);
561+
562+
previousCursorX = cursorX;
563+
previousCursorY = cursorY;
553564
}
565+
currentSubtick++;
554566
}
555567
return out;
556568
}
557569

558570
protected VirtualCameraAngle deserialiseCameraAngle(List<String> cameraAngleStrings) {
559571
VirtualCameraAngle out = new VirtualCameraAngle();
560572

573+
currentSubtick = 0;
574+
Float previousPitch = previousTickContainer == null ? null : previousTickContainer.getCameraAngle().getPitch();
575+
Float previousYaw = previousTickContainer == null ? null : previousTickContainer.getCameraAngle().getYaw();
576+
561577
for (String line : cameraAngleStrings) {
562578
Matcher matcher = extract("(.+?);(.+)", line);
563579

564580
if (matcher.find()) {
565581
String cameraPitchString = matcher.group(1);
566582
String cameraYawString = matcher.group(2);
567583

568-
float cameraPitch;
569-
float cameraYaw;
570-
571-
if (isFloat(cameraPitchString))
572-
cameraPitch = Float.parseFloat(cameraPitchString);
573-
else
574-
throw new PlaybackLoadException("The camera pitch is not valid");
575-
576-
if (isFloat(cameraYawString))
577-
cameraYaw = Float.parseFloat(cameraYawString);
578-
else
579-
throw new PlaybackLoadException("The camera yaw is not valid");
584+
float cameraPitch = deserialiseRelativeFloat("camera pitch", cameraPitchString, previousPitch);
585+
float cameraYaw = deserialiseRelativeFloat("camera yaw", cameraYawString, previousYaw);
580586

581587
out.updateFromState(cameraPitch, cameraYaw);
582-
583-
} else {
584-
throw new PlaybackLoadException("The cameraAngle is not valid");
585588
}
589+
currentSubtick++;
586590
}
587591
return out;
588592
}
@@ -614,6 +618,54 @@ protected int[] deserialiseVirtualKey(String[] keyString, VirtualKey defaultKey)
614618
return out;
615619
}
616620

621+
protected int parseInt(String name, String intstring) {
622+
try {
623+
return Integer.parseInt(intstring);
624+
} catch (NumberFormatException e) {
625+
throw new PlaybackLoadException(currentTick, currentSubtick, e, "Can't parse integer in %s", name);
626+
}
627+
}
628+
629+
protected int deserialiseRelativeInt(String name, String intstring, Integer previous) {
630+
int out = 0;
631+
if(intstring.startsWith("~")) {
632+
intstring = intstring.replace("~", "");
633+
int relative = parseInt(name, intstring);
634+
if(previous != null) {
635+
out = previous + relative;
636+
} else {
637+
throw new PlaybackLoadException(currentTick, currentSubtick, "Can't process relative value ~%s in %s. Previous value for comparing is not available", intstring, name);
638+
}
639+
} else {
640+
out = parseInt(name, intstring);
641+
}
642+
return out;
643+
}
644+
645+
protected float parseFloat(String name, String floatstring) {
646+
try {
647+
return Float.parseFloat(floatstring);
648+
} catch (NumberFormatException e) {
649+
throw new PlaybackLoadException(currentTick, currentSubtick, e, "Can't parse float in %s", name);
650+
}
651+
}
652+
653+
protected float deserialiseRelativeFloat(String name, String floatstring, Float previous) {
654+
float out = 0;
655+
if(floatstring.startsWith("~")) {
656+
floatstring = floatstring.replace("~", "");
657+
float relative = parseFloat(name, floatstring);
658+
if(previous != null) {
659+
out = previous + relative;
660+
} else {
661+
throw new PlaybackLoadException(currentTick, currentSubtick, "Can't process relative value ~%s in %s. Previous value for comparing is not available", floatstring, name);
662+
}
663+
} else {
664+
out = parseFloat(name, floatstring);
665+
}
666+
return out;
667+
}
668+
617669
protected void splitInputs(List<String> lines, List<String> serialisedKeyboard, List<String> serialisedMouse, List<String> serialisedCameraAngle, List<String> commentsAtEnd, List<List<PlaybackFileCommand>> endlineFileCommands) {
618670

619671
for (String line : lines) {
@@ -635,10 +687,10 @@ protected void splitInputs(List<String> lines, List<String> serialisedKeyboard,
635687
List<PlaybackFileCommand> deserialisedFileCommands = new ArrayList<>();
636688
String endlineComment = line.substring(tickMatcher.group(0).length());
637689
commentsAtEnd.add(deserialiseEndlineComment(endlineComment, deserialisedFileCommands));
638-
639-
if(deserialisedFileCommands.isEmpty())
690+
691+
if (deserialisedFileCommands.isEmpty())
640692
deserialisedFileCommands = null;
641-
693+
642694
endlineFileCommands.add(deserialisedFileCommands);
643695
}
644696
}

src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,78 @@ void testIsFloat() {
627627
assertTrue(isFloat("-145.23"));
628628
assertTrue(isFloat(Long.toString(Integer.MAX_VALUE + 1L)));
629629
}
630+
631+
@Test
632+
void testParseInt() {
633+
int actual = parseInt("testParseInt", "12");
634+
assertEquals(12, actual);
635+
636+
this.currentTick = 13;
637+
this.currentSubtick = 1;
638+
Throwable t = assertThrows(PlaybackLoadException.class, ()->{
639+
parseInt("testParseInt", "12.1");
640+
});
641+
642+
assertEquals("Tick 13, Subtick 1: Can't parse integer in testParseInt", t.getMessage());
643+
assertEquals(NumberFormatException.class, t.getCause().getClass());
644+
assertEquals("For input string: \"12.1\"", t.getCause().getMessage());
645+
this.currentTick = 0;
646+
this.currentSubtick = 0;
647+
}
648+
649+
@Test
650+
void testParseFloat() {
651+
float actual = parseFloat("testParseFloat", "12.1");
652+
assertEquals(12.1f, actual);
653+
654+
this.currentTick = 15;
655+
this.currentSubtick = 6;
656+
Throwable t = assertThrows(PlaybackLoadException.class, ()->{
657+
parseFloat("testParseFloat", "12.123h");
658+
});
659+
660+
assertEquals("Tick 15, Subtick 6: Can't parse float in testParseFloat", t.getMessage());
661+
assertEquals(NumberFormatException.class, t.getCause().getClass());
662+
assertEquals("For input string: \"12.123h\"", t.getCause().getMessage());
663+
this.currentTick = 0;
664+
this.currentSubtick = 0;
665+
}
666+
667+
@Test
668+
void testDeserialiseRelativeInt() {
669+
int actual = deserialiseRelativeInt("testParseRelativeInt", "12", null);
670+
assertEquals(12, actual);
671+
672+
actual = deserialiseRelativeInt("test", "~2", 14);
673+
assertEquals(16, actual);
674+
675+
this.currentTick = 23;
676+
this.currentSubtick = 11;
677+
Throwable t = assertThrows(PlaybackLoadException.class, ()->{
678+
deserialiseRelativeInt("testParseRelativeInt", "~12", null);
679+
});
680+
assertEquals("Tick 23, Subtick 11: Can't process relative value ~12 in testParseRelativeInt. Previous value for comparing is not available", t.getMessage());
681+
this.currentTick = 0;
682+
this.currentSubtick = 0;
683+
}
684+
685+
@Test
686+
void testDeserialiseRelativeFloat() {
687+
float actual = deserialiseRelativeFloat("testParseRelativeFloat", "12.2", null);
688+
assertEquals(12.2f, actual);
689+
690+
actual = deserialiseRelativeFloat("test", "~2.4", 14.4f);
691+
assertEquals(16.8f, actual);
692+
693+
this.currentTick = 20;
694+
this.currentSubtick = 2;
695+
Throwable t = assertThrows(PlaybackLoadException.class, ()->{
696+
deserialiseRelativeFloat("testParseRelativeFloat", "~12.3", null);
697+
});
698+
assertEquals("Tick 20, Subtick 2: Can't process relative value ~12.3 in testParseRelativeFloat. Previous value for comparing is not available", t.getMessage());
699+
this.currentTick = 0;
700+
this.currentSubtick = 0;
701+
}
630702

631703
@Test
632704
void testStringPaddingEven() {

0 commit comments

Comments
 (0)