From d23c1acb7e416b67d40982e6e50968e1c23cf799 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 10 Nov 2023 22:55:56 -0500 Subject: Fix room matching and secret index parsing bug --- .../skyblocker/skyblock/dungeon/secrets/Room.java | 114 +++++++++++++-------- .../skyblocker/dungeons/secretlocations.json | 4 +- 2 files changed, 71 insertions(+), 47 deletions(-) (limited to 'src/main') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index ecfcf496..c9b32be9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -41,6 +41,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Room { + private static final Pattern SECRET_INDEX = Pattern.compile("^(\\d+)"); private static final Pattern SECRETS = Pattern.compile("ยง7(\\d{1,2})/(\\d{1,2}) Secrets"); @NotNull private final Type type; @@ -70,11 +71,12 @@ public class Room { private int doubleCheckBlocks; /** * Represents the matching state of the room with the following possible values: - *
  • {@link TriState#DEFAULT} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}. - *
  • {@link TriState#FALSE} means that the room has been checked and there is no match. - *
  • {@link TriState#TRUE} means that the room has been checked and there is a match. + *
  • {@link MatchState#MATCHING} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}.
  • + *
  • {@link MatchState#DOUBLE_CHECKING} means that the room has a unique match and is being double checked.
  • + *
  • {@link MatchState#MATCHED} means that the room has a unique match ans has been double checked.
  • + *
  • {@link MatchState#FAILED} means that the room has been checked and there is no match.
  • */ - private TriState matched = TriState.DEFAULT; + private MatchState matchState = MatchState.MATCHING; private Table secretWaypoints; private String name; private Direction direction; @@ -96,7 +98,7 @@ public class Room { } public boolean isMatched() { - return matched == TriState.TRUE; + return matchState == MatchState.DOUBLE_CHECKING || matchState == MatchState.MATCHED; } /** @@ -108,7 +110,7 @@ public class Room { @Override public String toString() { - return "Room{type=" + type + ", shape=" + shape + ", matched=" + matched + ", segments=" + Arrays.toString(segments.toArray()) + "}"; + return "Room{type=" + type + ", shape=" + shape + ", matchState=" + matchState + ", segments=" + Arrays.toString(segments.toArray()) + "}"; } @NotNull @@ -208,6 +210,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * * @param pos the position of the secret waypoint relative to this room * @return the removed secret waypoint or {@code null} if there was no secret waypoint at the given position */ @@ -223,6 +226,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from this instance of the room. + * * @param secretIndex the index of the secret waypoint * @param relativePos the position of the secret waypoint relative to this room */ @@ -237,7 +241,7 @@ public class Room { * This method returns immediately if any of the following conditions are met: * * Then this method tries to match this room through: @@ -251,7 +255,7 @@ public class Room { @SuppressWarnings("JavadocReference") protected void update() { // Logical AND has higher precedence than logical OR - if (!type.needsScanning() || matched != TriState.DEFAULT || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { + if (!type.needsScanning() || matchState != MatchState.MATCHING && matchState != MatchState.DOUBLE_CHECKING || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { return; } MinecraftClient client = MinecraftClient.getInstance(); @@ -266,6 +270,9 @@ public class Room { break; } } + }).exceptionally(e -> { + DungeonSecrets.LOGGER.error("[Skyblocker Dungeon Secrets] Encountered an unknown error while matching room {}", this, e); + return null; }); } @@ -297,16 +304,24 @@ public class Room { * *
  • If there are no matching rooms left:
  • * *
  • If there are exactly one room matching:
  • * *
  • Return {@code false}
  • * @@ -320,40 +335,39 @@ public class Room { if (id == 0) { return false; } - for (MutableTriple> directionRooms : possibleRooms) { + possibleRooms.removeIf(directionRooms -> { int block = posIdToInt(DungeonMapUtils.actualToRelative(directionRooms.getLeft(), directionRooms.getMiddle(), pos), id); - List possibleDirectionRooms = new ArrayList<>(); - for (String room : directionRooms.getRight()) { - if (Arrays.binarySearch(roomsData.get(room), block) >= 0) { - possibleDirectionRooms.add(room); - } - } - directionRooms.setRight(possibleDirectionRooms); - } + directionRooms.getRight().removeIf(room -> Arrays.binarySearch(roomsData.get(room), block) < 0); + return directionRooms.getRight().isEmpty(); + }); int matchingRoomsSize = possibleRooms.stream().map(Triple::getRight).mapToInt(Collection::size).sum(); if (matchingRoomsSize == 0) { // If no rooms match, reset the fields and scan again after 50 ticks. - matched = TriState.FALSE; - DungeonSecrets.LOGGER.warn("[Skyblocker] No dungeon room matches after checking {} block(s)", checkedBlocks.size()); - Scheduler.INSTANCE.schedule(() -> matched = TriState.DEFAULT, 50); + DungeonSecrets.LOGGER.warn("[Skyblocker Dungeon Secrets] No dungeon room matched after checking {} block(s) including double checking {} block(s)", checkedBlocks.size(), doubleCheckBlocks + 1); + Scheduler.INSTANCE.schedule(() -> matchState = MatchState.MATCHING, 50); reset(); return true; - } else if (matchingRoomsSize == 1 && ++doubleCheckBlocks >= 10) { - // If one room matches, load the secrets for that room and discard the no longer needed fields. - for (Triple> directionRooms : possibleRooms) { - if (directionRooms.getRight().size() == 1) { - name = directionRooms.getRight().get(0); - direction = directionRooms.getLeft(); - physicalCornerPos = directionRooms.getMiddle(); - roomMatched(); - discard(); - return true; - } + } else if (matchingRoomsSize == 1) { + if (matchState == MatchState.MATCHING) { + // If one room matches, load the secrets for that room and set state to double-checking. + assert possibleRooms.size() == 1; + Triple> directionRoom = possibleRooms.get(0); + assert directionRoom.getRight().size() == 1; + name = directionRoom.getRight().get(0); + direction = directionRoom.getLeft(); + physicalCornerPos = directionRoom.getMiddle(); + roomMatched(); + return false; + } else if (matchState == MatchState.DOUBLE_CHECKING && ++doubleCheckBlocks >= 10) { + // If double-checked, set state to matched and discard the no longer needed fields. + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s) including double checking {} block(s)", name, checkedBlocks.size(), doubleCheckBlocks); + discard(); + return true; } - return false; // This should never happen, we just checked that there is one possible room, and the return true in the loop should activate + return false; } else { - DungeonSecrets.LOGGER.debug("[Skyblocker] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); + DungeonSecrets.LOGGER.debug("[Skyblocker Dungeon Secrets] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); return false; } } @@ -371,7 +385,7 @@ public class Room { /** * Loads the secret waypoints for the room from {@link DungeonSecrets#waypointsJson} once it has been matched - * and sets {@link #matched} to {@link TriState#TRUE}. + * and sets {@link #matchState} to {@link MatchState#DOUBLE_CHECKING}. * * @param directionRooms the direction, position, and name of the room */ @@ -381,25 +395,30 @@ public class Room { for (JsonElement waypointElement : DungeonSecrets.getRoomWaypoints(name)) { JsonObject waypoint = waypointElement.getAsJsonObject(); String secretName = waypoint.get("secretName").getAsString(); - int secretIndex = Integer.parseInt(secretName.substring(0, Character.isDigit(secretName.charAt(1)) ? 2 : 1)); + Matcher secretIndexMatcher = SECRET_INDEX.matcher(secretName); + int secretIndex = secretIndexMatcher.find() ? Integer.parseInt(secretIndexMatcher.group(1)) : 0; BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); - matched = TriState.TRUE; - - DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); + matchState = MatchState.DOUBLE_CHECKING; + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s), starting double checking", name, checkedBlocks.size()); } /** * Resets fields for another round of matching after room matching fails. */ private void reset() { + matchState = MatchState.FAILED; IntSortedSet segmentsX = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::x).toArray())); IntSortedSet segmentsY = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::y).toArray())); possibleRooms = getPossibleRooms(segmentsX, segmentsY); checkedBlocks = new HashSet<>(); doubleCheckBlocks = 0; + secretWaypoints = null; + name = null; + direction = null; + physicalCornerPos = null; } /** @@ -407,6 +426,7 @@ public class Room { * These fields are no longer needed and are discarded to save memory. */ private void discard() { + matchState = MatchState.MATCHED; roomsData = null; possibleRooms = null; checkedBlocks = null; @@ -473,7 +493,7 @@ public class Room { BlockState state = world.getBlockState(hitResult.getBlockPos()); if (state.isOf(Blocks.CHEST) || state.isOf(Blocks.PLAYER_HEAD) || state.isOf(Blocks.PLAYER_WALL_HEAD)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::needsInteraction).findAny() - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); } else if (state.isOf(Blocks.LEVER)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::isLever).forEach(SecretWaypoint::setFound); } @@ -491,7 +511,7 @@ public class Room { return; } secretWaypoints.values().stream().filter(SecretWaypoint::needsItemPickup).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(collector))).filter(SecretWaypoint.getRangePredicate(collector)) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -502,7 +522,7 @@ public class Room { */ protected void onBatRemoved(AmbientEntity bat) { secretWaypoints.values().stream().filter(SecretWaypoint::isBat).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(bat))) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -575,4 +595,8 @@ public class Room { public enum Direction { NW, NE, SW, SE } + + public enum MatchState { + MATCHING, DOUBLE_CHECKING, MATCHED, FAILED + } } diff --git a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json index a0a97c67..02e19632 100644 --- a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json +++ b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json @@ -2173,7 +2173,7 @@ }, { "secretName":"3 - Lever 2", - "category":"Lever", + "category":"lever", "x":31, "y":53, "z":24 @@ -2375,7 +2375,7 @@ }, { "secretName":"2 - Item", - "category":"Item", + "category":"item", "x":27, "y":56, "z":19 -- cgit From 2abfcece13208818ae86dd83f44a257daba23506 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:01:30 -0500 Subject: Fix room matching --- .../skyblock/dungeon/secrets/DungeonSecrets.java | 4 ++-- .../skyblocker/skyblock/dungeon/secrets/Room.java | 25 ++++++++++++---------- .../skyblock/dungeon/secrets/SecretWaypoint.java | 2 +- .../skyblocker/dungeons/secretlocations.json | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/main') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index eda08cf6..ee517eb8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -255,7 +255,7 @@ public class DungeonSecrets { dungeonFutures.add(CompletableFuture.runAsync(() -> { try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach((room, waypointsJson) -> - addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseThrow()) + addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseGet(ArrayList::new)) ); LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { @@ -273,7 +273,7 @@ public class DungeonSecrets { try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { JsonObject customWaypointsJson = new JsonObject(); customWaypoints.rowMap().forEach((room, waypoints) -> - customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow()) + customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseGet(JsonArray::new)) ); SkyblockerMod.GSON.toJson(customWaypointsJson, writer); LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index c9b32be9..9b95f146 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -110,7 +110,7 @@ public class Room { @Override public String toString() { - return "Room{type=" + type + ", shape=" + shape + ", matchState=" + matchState + ", segments=" + Arrays.toString(segments.toArray()) + "}"; + return "Room{type=%s, segments=%s, shape=%s, matchState=%s, name=%s, direction=%s, physicalCornerPos=%s}".formatted(type, Arrays.toString(segments.toArray()), shape, matchState, name, direction, physicalCornerPos); } @NotNull @@ -271,7 +271,7 @@ public class Room { } } }).exceptionally(e -> { - DungeonSecrets.LOGGER.error("[Skyblocker Dungeon Secrets] Encountered an unknown error while matching room {}", this, e); + DungeonSecrets.LOGGER.error("[Skyblocker Dungeon Secrets] Encountered an unknown exception while matching room {}", this, e); return null; }); } @@ -335,28 +335,32 @@ public class Room { if (id == 0) { return false; } - possibleRooms.removeIf(directionRooms -> { + for (MutableTriple> directionRooms : possibleRooms) { int block = posIdToInt(DungeonMapUtils.actualToRelative(directionRooms.getLeft(), directionRooms.getMiddle(), pos), id); - directionRooms.getRight().removeIf(room -> Arrays.binarySearch(roomsData.get(room), block) < 0); - return directionRooms.getRight().isEmpty(); - }); + List possibleDirectionRooms = new ArrayList<>(); + for (String room : directionRooms.getRight()) { + if (Arrays.binarySearch(roomsData.get(room), block) >= 0) { + possibleDirectionRooms.add(room); + } + } + directionRooms.setRight(possibleDirectionRooms); + } int matchingRoomsSize = possibleRooms.stream().map(Triple::getRight).mapToInt(Collection::size).sum(); if (matchingRoomsSize == 0) { // If no rooms match, reset the fields and scan again after 50 ticks. - DungeonSecrets.LOGGER.warn("[Skyblocker Dungeon Secrets] No dungeon room matched after checking {} block(s) including double checking {} block(s)", checkedBlocks.size(), doubleCheckBlocks + 1); + DungeonSecrets.LOGGER.warn("[Skyblocker Dungeon Secrets] No dungeon room matched after checking {} block(s) including double checking {} block(s)", checkedBlocks.size(), doubleCheckBlocks); Scheduler.INSTANCE.schedule(() -> matchState = MatchState.MATCHING, 50); reset(); return true; } else if (matchingRoomsSize == 1) { if (matchState == MatchState.MATCHING) { // If one room matches, load the secrets for that room and set state to double-checking. - assert possibleRooms.size() == 1; - Triple> directionRoom = possibleRooms.get(0); - assert directionRoom.getRight().size() == 1; + Triple> directionRoom = possibleRooms.stream().filter(directionRooms -> directionRooms.getRight().size() == 1).findAny().orElseThrow(); name = directionRoom.getRight().get(0); direction = directionRoom.getLeft(); physicalCornerPos = directionRoom.getMiddle(); + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s), starting double checking", name, checkedBlocks.size()); roomMatched(); return false; } else if (matchState == MatchState.DOUBLE_CHECKING && ++doubleCheckBlocks >= 10) { @@ -402,7 +406,6 @@ public class Room { } DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); matchState = MatchState.DOUBLE_CHECKING; - DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s), starting double checking", name, checkedBlocks.size()); } /** diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 0c2d1b34..fdfa88c3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -136,7 +136,7 @@ public class SecretWaypoint extends Waypoint { } private static Category get(JsonObject waypointJson) { - return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElseThrow(); + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElse(Category.DEFAULT); } boolean needsInteraction() { diff --git a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json index 02e19632..0f22f597 100644 --- a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json +++ b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json @@ -3936,7 +3936,7 @@ }, { "secretName":"4/5/6 - Entrance 3", - "category":"", + "category":"entrance", "x":31, "y":142, "z":39 -- cgit From 35d02596389b2516d62fbd1298b5b90e69b57fa5 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sun, 12 Nov 2023 17:42:00 -0500 Subject: Add secret waypoint tests --- .../skyblock/dungeon/secrets/SecretWaypoint.java | 13 ++-- .../dungeon/secrets/SecretWaypointTest.java | 79 ++++++++++++++++++++++ 2 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java (limited to 'src/main') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index fdfa88c3..43f624f6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -20,6 +20,8 @@ import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.function.Predicate; @@ -27,6 +29,7 @@ import java.util.function.Supplier; import java.util.function.ToDoubleFunction; public class SecretWaypoint extends Waypoint { + protected static final Logger LOGGER = LoggerFactory.getLogger(SecretWaypoint.class); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.INT.fieldOf("secretIndex").forGetter(secretWaypoint -> secretWaypoint.secretIndex), Category.CODEC.fieldOf("category").forGetter(secretWaypoint -> secretWaypoint.category), @@ -35,8 +38,8 @@ public class SecretWaypoint extends Waypoint { ).apply(instance, SecretWaypoint::new)); public static final Codec> LIST_CODEC = CODEC.listOf(); static final List SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); - private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; - private static final Supplier TYPE_SUPPLIER = () -> CONFIG.waypointType; + private static final Supplier CONFIG = () -> SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; + private static final Supplier TYPE_SUPPLIER = () -> CONFIG.get().waypointType; final int secretIndex; final Category category; final Text name; @@ -95,7 +98,7 @@ public class SecretWaypoint extends Waypoint { //TODO In the future, shrink the box for wither essence and items so its more realistic super.render(context); - if (CONFIG.showSecretText) { + if (CONFIG.get().showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); RenderHelper.renderText(context, name, posUp, true); double distance = context.camera().getPos().distanceTo(centerPos); @@ -135,8 +138,8 @@ public class SecretWaypoint extends Waypoint { } } - private static Category get(JsonObject waypointJson) { - return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElse(Category.DEFAULT); + static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(LOGGER::error).orElse(Category.DEFAULT); } boolean needsInteraction() { diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java new file mode 100644 index 00000000..0870e744 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java @@ -0,0 +1,79 @@ +package de.hysky.skyblocker.skyblock.dungeon.secrets; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import net.minecraft.util.math.BlockPos; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class SecretWaypointTest { + private final Gson gson = new Gson(); + + @Test + void testCodecSerialize() { + SecretWaypoint waypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN); + JsonElement json = SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).result().orElseThrow(); + String expectedJson = "{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]}"; + + Assertions.assertEquals(expectedJson, json.toString()); + } + + @Test + void testCodecDeserialize() { + String json = "{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]}"; + SecretWaypoint waypoint = SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + SecretWaypoint expectedWaypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN); + + equal(expectedWaypoint, waypoint); + } + + @Test + void testListCodecSerialize() { + List waypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(-1, 0, 1))); + JsonElement json = SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, waypoints).result().orElseThrow(); + String expectedJson = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":{\"text\":\"name\"},\"pos\":[-1,0,1]}]"; + + Assertions.assertEquals(expectedJson, json.toString()); + } + + @Test + void testListCodecDeserialize() { + String json = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":{\"text\":\"name\"},\"pos\":[-1,0,1]}]"; + List waypoints = SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + List expectedWaypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(-1, 0, 1))); + + Assertions.assertEquals(expectedWaypoints.size(), waypoints.size()); + for (int i = 0; i < expectedWaypoints.size(); i++) { + SecretWaypoint expectedWaypoint = expectedWaypoints.get(i); + SecretWaypoint waypoint = waypoints.get(i); + equal(expectedWaypoint, waypoint); + } + } + + @Test + void testGetCategory() { + JsonObject waypointJson = new JsonObject(); + waypointJson.addProperty("category", "chest"); + SecretWaypoint.Category category = SecretWaypoint.Category.get(waypointJson); + Assertions.assertEquals(SecretWaypoint.Category.CHEST, category); + } + + @Test + void testGetCategoryDefault() { + JsonObject waypointJson = new JsonObject(); + waypointJson.addProperty("category", ""); + SecretWaypoint.Category category = SecretWaypoint.Category.get(waypointJson); + Assertions.assertEquals(SecretWaypoint.Category.DEFAULT, category); + } + + private static void equal(SecretWaypoint expectedWaypoint, SecretWaypoint waypoint) { + Assertions.assertEquals(expectedWaypoint.secretIndex, waypoint.secretIndex); + Assertions.assertEquals(expectedWaypoint.category, waypoint.category); + Assertions.assertEquals(expectedWaypoint.name, waypoint.name); + Assertions.assertEquals(expectedWaypoint.pos, waypoint.pos); + } +} -- cgit