diff options
author | CraftyOldMiner <85420839+CraftyOldMiner@users.noreply.github.com> | 2022-04-07 05:17:47 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-07 12:17:47 +0200 |
commit | aa3357d71f7a80d3e1463df273915460ff343823 (patch) | |
tree | 75bad6008f5b3f0cd953bb1400c7a05dd36d35ad | |
parent | c60f9085f61c5f489bcf11da806ddc498fba1692 (diff) | |
download | NotEnoughUpdates-aa3357d71f7a80d3e1463df273915460ff343823.tar.gz NotEnoughUpdates-aa3357d71f7a80d3e1463df273915460ff343823.tar.bz2 NotEnoughUpdates-aa3357d71f7a80d3e1463df273915460ff343823.zip |
Wishing compass improved target identification, bug fixes (#108)
* Wishing compass improved target identification, bug fixes
- Use structure sizes to determine targets instead of adjacent zones. This should fix sporadic incorrect targets.
- Fix compass not working when used on the edge of a zone due to bounding box coordinates being off by one.
- Record all seen particles during compass use for troubleshooting intermittent failures.
* Fix description for waypoint names
* Fix typo
3 files changed, 429 insertions, 247 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java index 9a950e7f..977ef818 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java @@ -24,6 +24,7 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -63,6 +64,15 @@ public class CrystalWishingCompassSolver { TOPAZ, } + enum HollowsZone { + CRYSTAL_NUCLEUS, + JUNGLE, + MITHRIL_DEPOSITS, + GOBLIN_HOLDOUT, + PRECURSOR_REMNANTS, + MAGMA_FIELDS, + } + private static final CrystalWishingCompassSolver INSTANCE = new CrystalWishingCompassSolver(); public static CrystalWishingCompassSolver getInstance() { return INSTANCE; @@ -70,16 +80,32 @@ public class CrystalWishingCompassSolver { private static final Minecraft mc = Minecraft.getMinecraft(); private static boolean isSkytilsPresent = false; + private static final ArrayDeque<ParticleData> seenParticles = new ArrayDeque<>(); - // NOTE: There is a small set of breakable blocks above the nucleus at Y > 181. While this zone is reported - // as the Crystal Nucleus by Hypixel, for wishing compass purposes it is in the appropriate quadrant. + // There is a small set of breakable blocks above the nucleus at Y > 181. While this zone is reported + // as the Crystal Nucleus by Hypixel, for wishing compass purposes it is in the appropriate quadrant. private static final AxisAlignedBB NUCLEUS_BB = new AxisAlignedBB(462, 63, 461, 564, 181, 565); + // Bounding box around all breakable blocks in the crystal hollows, appears as bedrock in-game private static final AxisAlignedBB HOLLOWS_BB = new AxisAlignedBB(201, 30, 201, 824, 189, 824); - private static final AxisAlignedBB PRECURSOR_REMNANTS_BB = new AxisAlignedBB(513, 64, 513, 824, 189, 824); - private static final AxisAlignedBB MITHRIL_DEPOSITS_BB = new AxisAlignedBB(513, 64, 201, 824, 189, 512); - private static final AxisAlignedBB GOBLIN_HOLDOUT_BB = new AxisAlignedBB(201, 64, 513, 512, 189, 824); - private static final AxisAlignedBB JUNGLE_BB = new AxisAlignedBB(201, 64, 201, 512, 189, 512); - private static final AxisAlignedBB MAGMA_FIELDS_BB = new AxisAlignedBB(201, 30, 201, 824, 63, 824); + + // Zone bounding boxes + private static final AxisAlignedBB PRECURSOR_REMNANTS_BB = new AxisAlignedBB(512, 63, 512, 824, 189, 824); + private static final AxisAlignedBB MITHRIL_DEPOSITS_BB = new AxisAlignedBB(512, 63, 201, 824, 189, 513); + private static final AxisAlignedBB GOBLIN_HOLDOUT_BB = new AxisAlignedBB(201, 63, 512, 513, 189, 824); + private static final AxisAlignedBB JUNGLE_BB = new AxisAlignedBB(201, 63, 201, 513, 189, 513); + private static final AxisAlignedBB MAGMA_FIELDS_BB = new AxisAlignedBB(201, 30, 201, 824, 64, 824); + + // Structure bounding boxes (size + 2 in each dimension to make it an actual bounding box) + private static final AxisAlignedBB PRECURSOR_CITY_BB = new AxisAlignedBB(0, 0, 0, 107, 122, 107); + private static final AxisAlignedBB GOBLIN_KING_BB = new AxisAlignedBB(0, 0, 0, 59, 53, 56); + private static final AxisAlignedBB GOBLIN_QUEEN_BB = new AxisAlignedBB(0, 0, 0, 108, 114, 108); + private static final AxisAlignedBB JUNGLE_TEMPLE_BB = new AxisAlignedBB(0, 0, 0, 108, 120, 108); + private static final AxisAlignedBB ODAWA_BB = new AxisAlignedBB(0, 0, 0, 53, 46, 54); + private static final AxisAlignedBB MINES_OF_DIVAN_BB = new AxisAlignedBB(0, 0, 0, 108, 125, 108); + private static final AxisAlignedBB KHAZAD_DUM_BB = new AxisAlignedBB(0, 0, 0, 110, 46, 108); + + private static final Vec3Comparable JUNGLE_DOOR_OFFSET_FROM_CRYSTAL = new Vec3Comparable(-57, 36, -21); + private static final double MAX_DISTANCE_BETWEEN_PARTICLES = 0.6; private static final double MAX_DISTANCE_FROM_USE_TO_FIRST_PARTICLE = 9.0; @@ -118,6 +144,20 @@ public class CrystalWishingCompassSolver { return possibleTargets; } + public static HollowsZone getZoneForCoords(BlockPos blockPos) { + return getZoneForCoords(new Vec3Comparable(blockPos)); + } + + public static HollowsZone getZoneForCoords(Vec3Comparable coords) { + if (NUCLEUS_BB.isVecInside(coords)) return HollowsZone.CRYSTAL_NUCLEUS; + if (JUNGLE_BB.isVecInside(coords)) return HollowsZone.JUNGLE; + if (MITHRIL_DEPOSITS_BB.isVecInside(coords)) return HollowsZone.MITHRIL_DEPOSITS; + if (GOBLIN_HOLDOUT_BB.isVecInside(coords)) return HollowsZone.GOBLIN_HOLDOUT; + if (PRECURSOR_REMNANTS_BB.isVecInside(coords)) return HollowsZone.PRECURSOR_REMNANTS; + if (MAGMA_FIELDS_BB.isVecInside(coords)) return HollowsZone.MAGMA_FIELDS; + throw new IllegalArgumentException("Coordinates do not fall in known zone: " + coords.toString()); + } + private void resetForNewTarget() { NEUDebugLogger.log(NEUDebugFlag.WISHING,"Resetting for new target"); solverState = SolverState.NOT_STARTED; @@ -236,6 +276,7 @@ public class CrystalWishingCompassSolver { } firstCompass = new Compass(playerPos, currentTimeMillis.getAsLong()); + seenParticles.clear(); solverState = SolverState.PROCESSING_FIRST_USE; possibleTargets = calculatePossibleTargets(playerPos); return HandleCompassResult.SUCCESS; @@ -244,7 +285,10 @@ public class CrystalWishingCompassSolver { return HandleCompassResult.LOCATION_TOO_CLOSE; } - if (!possibleTargets.equals(calculatePossibleTargets(playerPos))) { + HollowsZone firstCompassZone = getZoneForCoords(firstCompass.whereUsed); + HollowsZone playerZone = getZoneForCoords(playerPos); + if (!possibleTargets.equals(calculatePossibleTargets(playerPos)) || + firstCompassZone != playerZone) { resetForNewTarget(); return HandleCompassResult.POSSIBLE_TARGETS_CHANGED; } @@ -291,6 +335,13 @@ public class CrystalWishingCompassSolver { return; } + // Capture particle troubleshooting info for two minutes starting when the first compass is used. + // This list is reset each time the first compass is used from a NOT_STARTED state. + if (firstCompass != null && !solverState.equals(SolverState.SOLVED) && + System.currentTimeMillis() < firstCompass.whenUsedMillis + 2*60*1000) { + seenParticles.add(new ParticleData(new Vec3Comparable(x, y, z), System.currentTimeMillis())); + } + try { SolverState originalSolverState = solverState; solveUsingParticle(x, y, z, currentTimeMillis.getAsLong()); @@ -399,13 +450,17 @@ public class CrystalWishingCompassSolver { return; } - solutionPossibleTargets = getSolutionTargets(possibleTargets, solution); + solutionPossibleTargets = getSolutionTargets( + getZoneForCoords(firstCompass.whereUsed), + foundCrystals.getAsCrystalEnumSet(), + possibleTargets, + solution); // Adjust the Jungle Temple solution coordinates if (solutionPossibleTargets.size() == 1 && solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE)) { originalSolution = solution; - solution = solution.addVector(-57, 36, -21); + solution = solution.add(JUNGLE_DOOR_OFFSET_FROM_CRYSTAL); } solverState = SolverState.SOLVED; @@ -441,14 +496,24 @@ public class CrystalWishingCompassSolver { return foundCrystals; } - // Returns candidates based on seen Y coordinates and quadrants that - // are not adjacent to the solution's quadrant. If the solution is - // the nucleus then a copy of the original possible targets is - // returned. + // Returns candidates based on: + // - Structure Y levels observed in various lobbies. It is assumed + // that structures other than Khazad Dum cannot have any portion + // in the Magma Fields. + // + // - Structure sizes & offsets into other zones that assume at least + // one block must be in the correct zone. + // + // - An assumption that any structure could be missing with a + // special exception for the Jungle Temple since it often conflicts + // with Bal and a lobby with a missing Jungle Temple has not been + // observed. This exception will remove Bal as a target if: + // - Target candidates include both Bal & the Jungle Temple. + // - The Amethyst crystal has not been acquired. + // - The zone that the compass was used in is the Jungle. // - // NOTE: Adjacent quadrant filtering could be improved based on - // structure sizes in the future to only allow a certain - // distance into the adjacent quadrant. + // - If the solution is the Crystal Nucleus then a copy of the + // passed in possible targets is returned. // // |----------|------------| // | Jungle | Mithril | @@ -458,160 +523,155 @@ public class CrystalWishingCompassSolver { // | Holdout | Deposits | // |----------|------------| static public EnumSet<CompassTarget> getSolutionTargets( + HollowsZone compassUsedZone, + EnumSet<Crystal> foundCrystals, EnumSet<CompassTarget> possibleTargets, Vec3Comparable solution) { EnumSet<CompassTarget> solutionPossibleTargets; solutionPossibleTargets = possibleTargets.clone(); - if (NUCLEUS_BB.isVecInside(solution)) { + HollowsZone solutionZone = getZoneForCoords(solution); + if (solutionZone == HollowsZone.CRYSTAL_NUCLEUS) { return solutionPossibleTargets; } solutionPossibleTargets.remove(CompassTarget.CRYSTAL_NUCLEUS); - // Eliminate non-adjacent zones first - if (MITHRIL_DEPOSITS_BB.isVecInside(solution)) { - solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING); - solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN); - } else if (PRECURSOR_REMNANTS_BB.isVecInside(solution)) { - solutionPossibleTargets.remove(CompassTarget.ODAWA); - solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE); - } else if (GOBLIN_HOLDOUT_BB.isVecInside(solution)) { - solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN); - } else if (JUNGLE_BB.isVecInside(solution)) { - solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY); + // Y coordinates are 43-71 from 13 samples + // Y=41/74 is the absolute min/max based on structure size if + // the center of the topaz crystal has to be in magma fields. + if (solutionPossibleTargets.contains(CompassTarget.BAL) && + solution.yCoord > 75) { + solutionPossibleTargets.remove(CompassTarget.BAL); } - // If there's only 1 possible target then don't remove based - // on Y coordinates since assumptions about Y coordinates could - // be wrong. - if (solutionPossibleTargets.size() > 1) { - // Y coordinates are 43-70 from 11 samples - if (solutionPossibleTargets.contains(CompassTarget.BAL) && - solution.yCoord > 72) { - solutionPossibleTargets.remove(CompassTarget.BAL); - } + // Y coordinates are 93-157 from 15 samples. + // Y=83/167 is the absolute min/max based on structure size + if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_KING) && + solution.yCoord < 82 || solution.yCoord > 168) { + solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING); + } - // Y coordinates are 93-157 from 10 samples, may be able to filter - // more based on the offset of the King within the structure - if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_KING) && - solution.yCoord < 64) { - solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING); - } + // Y coordinates are 129-139 from 10 samples + // Y=126/139 is the absolute min/max based on structure size + if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_QUEEN) && + (solution.yCoord < 125 || solution.yCoord > 140)) { + solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN); + } - // Y coordinates are 129-139 from 10 samples - if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_QUEEN) && - (solution.yCoord < 127 || solution.yCoord > 141)) { - solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN); - } + // Y coordinates are 72-80 from 10 samples + // Y=73/80 is the absolute min/max based on structure size + if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) && + (solution.yCoord < 72 || solution.yCoord > 81)) { + solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE); + } - // Y coordinates are 72-80 from 10 samples - if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) && - (solution.yCoord < 70 || solution.yCoord > 82)) { - solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE); - } + // Y coordinates are 87-155 from 7 samples + // Y=74/155 is the absolute min/max solution based on structure size + if (solutionPossibleTargets.contains(CompassTarget.ODAWA) && + (solution.yCoord < 73 || solution.yCoord > 155)) { + solutionPossibleTargets.remove(CompassTarget.ODAWA); + } - // Y coordinates are 110-128 from 3 samples, not enough data to use - if (solutionPossibleTargets.contains(CompassTarget.ODAWA) && - solution.yCoord < 64) { - solutionPossibleTargets.remove(CompassTarget.ODAWA); - } + // Y coordinates are 122-129 from 8 samples + // Y=122/129 is the absolute min/max based on structure size + if (solutionPossibleTargets.contains(CompassTarget.PRECURSOR_CITY) && + (solution.yCoord < 121 || solution.yCoord > 130)) { + solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY); + } - // Y coordinates are 122-129 from 8 samples - if (solutionPossibleTargets.contains(CompassTarget.PRECURSOR_CITY) && - (solution.yCoord < 119 || solution.yCoord > 132)) { - solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY); - } + // Y coordinates are 98-102 from 15 samples + // Y=98/100 is the absolute min/max based on structure size, + // but 102 has been seen - possibly with earlier code that rounded up + if (solutionPossibleTargets.contains(CompassTarget.MINES_OF_DIVAN) && + (solution.yCoord < 97 || solution.yCoord > 102)) { + solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN); + } - // Y coordinates are 98-102 from 15 samples - if (solutionPossibleTargets.contains(CompassTarget.MINES_OF_DIVAN) && - (solution.yCoord < 96 || solution.yCoord > 104)) { - solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN); - } + // Now filter by structure offset + if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_KING) && + (solution.xCoord > GOBLIN_HOLDOUT_BB.maxX + GOBLIN_KING_BB.maxX || + solution.zCoord < GOBLIN_HOLDOUT_BB.minZ - GOBLIN_KING_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING); } - return solutionPossibleTargets; - } + if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_QUEEN) && + (solution.xCoord > GOBLIN_HOLDOUT_BB.maxX + GOBLIN_QUEEN_BB.maxX || + solution.zCoord < GOBLIN_HOLDOUT_BB.minZ - GOBLIN_QUEEN_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN); + } - private EnumSet<CompassTarget> calculatePossibleTargets(BlockPos playerPos) { - boolean targetsBasedOnZoneWithoutCrystal = false; - EnumSet<CompassTarget> candidateTargets = EnumSet.allOf(CompassTarget.class); - EnumSet<Crystal> foundCrystals = this.foundCrystals.getAsCrystalEnumSet(); - Vec3Comparable playerPosVec = new Vec3Comparable(playerPos); - - // If the current zone's crystal hasn't been found then remove all non-nucleus candidates other - // than the ones in the current zone. The one exception is that the king is kept when in the jungle - // since the compass can point to the king if odawa is missing (which often happens). - // The nucleus is kept since it can be returned if the structure for the current zone is missing. - if (GOBLIN_HOLDOUT_BB.isVecInside(playerPosVec) && !foundCrystals.contains(Crystal.AMBER)) { - candidateTargets.clear(); - candidateTargets.add(CompassTarget.CRYSTAL_NUCLEUS); - candidateTargets.add(CompassTarget.GOBLIN_KING); - candidateTargets.add(CompassTarget.GOBLIN_QUEEN); - targetsBasedOnZoneWithoutCrystal = true; - } - - if (JUNGLE_BB.isVecInside(playerPosVec) && !foundCrystals.contains(Crystal.AMETHYST)) { - candidateTargets.clear(); - candidateTargets.add(CompassTarget.CRYSTAL_NUCLEUS); - candidateTargets.add(CompassTarget.ODAWA); - candidateTargets.add(CompassTarget.JUNGLE_TEMPLE); - if (!keyInInventory.getAsBoolean() && !kingsScentPresent.getAsBoolean()) { - // If Odawa is missing then the king may be returned - candidateTargets.add(CompassTarget.GOBLIN_KING); - } - targetsBasedOnZoneWithoutCrystal = true; + if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) && + (solution.xCoord > JUNGLE_BB.maxX + JUNGLE_TEMPLE_BB.maxX || + solution.zCoord > JUNGLE_BB.maxZ + JUNGLE_TEMPLE_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE); } - if (MITHRIL_DEPOSITS_BB.isVecInside(playerPosVec) && !foundCrystals.contains(Crystal.JADE)) { - candidateTargets.clear(); - candidateTargets.add(CompassTarget.CRYSTAL_NUCLEUS); - candidateTargets.add(CompassTarget.MINES_OF_DIVAN); - targetsBasedOnZoneWithoutCrystal = true; + if (solutionPossibleTargets.contains(CompassTarget.ODAWA) && + (solution.xCoord > JUNGLE_BB.maxX + ODAWA_BB.maxX || + solution.zCoord > JUNGLE_BB.maxZ + ODAWA_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.ODAWA); } - if (PRECURSOR_REMNANTS_BB.isVecInside(playerPosVec) && !foundCrystals.contains(Crystal.SAPPHIRE)) { - candidateTargets.clear(); - candidateTargets.add(CompassTarget.CRYSTAL_NUCLEUS); - candidateTargets.add(CompassTarget.PRECURSOR_CITY); - targetsBasedOnZoneWithoutCrystal = true; + if (solutionPossibleTargets.contains(CompassTarget.PRECURSOR_CITY) && + (solution.xCoord < PRECURSOR_REMNANTS_BB.minX - PRECURSOR_CITY_BB.maxX || + solution.zCoord < PRECURSOR_REMNANTS_BB.minZ - PRECURSOR_CITY_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY); } - if (MAGMA_FIELDS_BB.isVecInside(playerPosVec) && !foundCrystals.contains(Crystal.TOPAZ)) { - candidateTargets.clear(); - candidateTargets.add(CompassTarget.CRYSTAL_NUCLEUS); - candidateTargets.add(CompassTarget.BAL); - targetsBasedOnZoneWithoutCrystal = true; + if (solutionPossibleTargets.contains(CompassTarget.MINES_OF_DIVAN) && + (solution.xCoord < MITHRIL_DEPOSITS_BB.minX - MINES_OF_DIVAN_BB.maxX || + solution.zCoord > MITHRIL_DEPOSITS_BB.maxZ + MINES_OF_DIVAN_BB.maxZ)) { + solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN); } - if (!targetsBasedOnZoneWithoutCrystal) { - // Filter out crystal-based targets outside the current zone - if (foundCrystals.contains(Crystal.AMBER)) { - candidateTargets.remove(CompassTarget.GOBLIN_KING); - candidateTargets.remove(CompassTarget.GOBLIN_QUEEN); - } + // Special case the Jungle Temple + if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) && + solutionPossibleTargets.contains(CompassTarget.BAL) && + !foundCrystals.contains(Crystal.AMETHYST) && + compassUsedZone == HollowsZone.JUNGLE) { + solutionPossibleTargets.remove(CompassTarget.BAL); + } - if (foundCrystals.contains(Crystal.AMETHYST)) { - candidateTargets.remove(CompassTarget.ODAWA); - candidateTargets.remove(CompassTarget.JUNGLE_TEMPLE); - } + return solutionPossibleTargets; + } - if (foundCrystals.contains(Crystal.JADE)) { - candidateTargets.remove(CompassTarget.MINES_OF_DIVAN); - } + private EnumSet<CompassTarget> calculatePossibleTargets(BlockPos playerPos) { + EnumSet<CompassTarget> candidateTargets = EnumSet.of(CompassTarget.CRYSTAL_NUCLEUS); + EnumSet<Crystal> foundCrystals = this.foundCrystals.getAsCrystalEnumSet(); - if (foundCrystals.contains(Crystal.TOPAZ)) { - candidateTargets.remove(CompassTarget.BAL); + // Add targets based on missing crystals. + // NOTE: + // We used to assume that only the adjacent zone's targets could be returned. That turned + // out to be incorrect (e.g. a compass in the jungle pointed to the Precursor City when + // the king would have been a valid target). Now we assume that any structure could be + // missing (because Hypixel) and depend on the solution coordinates to filter the list. + for (Crystal crystal : Crystal.values()) { + if (foundCrystals.contains(crystal)) { + continue; } - if (foundCrystals.contains(Crystal.SAPPHIRE)) { - candidateTargets.remove(CompassTarget.PRECURSOR_CITY); + switch (crystal) { + case JADE: + candidateTargets.add(CompassTarget.MINES_OF_DIVAN); + break; + case AMBER: + candidateTargets.add( + kingsScentPresent.getAsBoolean() ? CompassTarget.GOBLIN_QUEEN : CompassTarget.GOBLIN_KING); + break; + case TOPAZ: + candidateTargets.add(CompassTarget.BAL); + break; + case AMETHYST: + candidateTargets.add( + keyInInventory.getAsBoolean() ? CompassTarget.JUNGLE_TEMPLE : CompassTarget.ODAWA); + break; + case SAPPHIRE: + candidateTargets.add(CompassTarget.PRECURSOR_CITY); + break; } } - candidateTargets.remove(kingsScentPresent.getAsBoolean() ? CompassTarget.GOBLIN_KING : CompassTarget.GOBLIN_QUEEN); - candidateTargets.remove(keyInInventory.getAsBoolean() ? CompassTarget.ODAWA : CompassTarget.JUNGLE_TEMPLE); - return candidateTargets; } @@ -633,7 +693,7 @@ public class CrystalWishingCompassSolver { } private String getNameForCompassTarget(CompassTarget compassTarget) { - boolean useSkytilsNames = (NotEnoughUpdates.INSTANCE.config.mining.wishingCompassWaypointNameType == 1); + boolean useSkytilsNames = (NotEnoughUpdates.INSTANCE.config.mining.wishingCompassWaypointNames == 1); switch (compassTarget) { case BAL: return useSkytilsNames ? "internal_bal" : "Bal"; case ODAWA: return "Odawa"; @@ -802,6 +862,14 @@ public class CrystalWishingCompassSolver { diagsMessage.append((solutionPossibleTargets == null) ? "<NONE>" : solutionPossibleTargets.toString()); diagsMessage.append("\n"); + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Seen particles:\n"); + for (ParticleData particleData : seenParticles) { + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append(particleData); + diagsMessage.append("\n"); + } + return diagsMessage.toString(); } @@ -984,4 +1052,18 @@ public class CrystalWishingCompassSolver { } } } + + private static class ParticleData { + Vec3Comparable particleLocation; + long systemTime; + + public ParticleData(Vec3Comparable particleLocation, long systemTime) { + this.particleLocation = particleLocation; + this.systemTime = systemTime; + } + + public String toString() { + return "Location: " + particleLocation.toString() + ", systemTime: " + systemTime; + } + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java index f793baf0..9ff88089 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java @@ -668,14 +668,14 @@ public class Mining { @Expose @ConfigOption( - name = "Waypoint Type", - desc = "Skytils Waypoint name type. Skytils Built-in will be overwritten by Skytils when the waypoint is nearby." + name = "Waypoint Names", + desc = "NOTE: Skytils overwrites waypoint coordinates with less accurate values for Skytils names." ) @ConfigAccordionId(id = 7) @ConfigEditorDropdown( values = {"NEU", "Skytils"} ) - public int wishingCompassWaypointNameType = 0; + public int wishingCompassWaypointNames = 0; @Expose @ConfigOption( diff --git a/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java index ed39a505..dff8749c 100644 --- a/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java +++ b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java @@ -23,6 +23,7 @@ class CrystalWishingCompassSolverTest { private static final CrystalWishingCompassSolver solver = getInstance(); long systemTimeMillis; private final long DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE = 500L; + private final int CH_LOWEST_VALID_Y = 30; private final CompassUse minesOfDivanCompassUse1 = new CompassUse( 1647528732979L, @@ -326,7 +327,8 @@ class CrystalWishingCompassSolverTest { Vec3i magmaSolution = new Vec3i(737, 56, 444); - Vec3Comparable kingMinesOrNucleusCoordsInRemnants = new Vec3Comparable(604, 100, 681); + Vec3Comparable kingOdawaMinesOrNucleusCoordsInRemnants = new Vec3Comparable(566, 100, 566); + Vec3Comparable queenKingOdawaOrCityNucleusCoordsInMithrilDeposits = new Vec3Comparable(566, 130, 466); Vec3Comparable odawaSolution = new Vec3Comparable(349, 110, 390); private final CompassUse nucleusCompass = new CompassUse( @@ -473,6 +475,7 @@ class CrystalWishingCompassSolverTest { @Test void missing_repeating_particles_sets_state_to_failed_timeout_no_repeating() { + // Arrange CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1); compassUse.particles.remove(compassUse.particles.size()-1); compassUse.particles.get(compassUse.particles.size()-1).timeIncrementMillis += ALL_PARTICLES_MAX_MILLIS; @@ -581,7 +584,8 @@ class CrystalWishingCompassSolverTest { // Arrange CompassUse compassUse1 = new CompassUse(minesOfDivanCompassUse1); CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2); - Vec3 offset = new Vec3(0.0, 200.0, 0.0); + double invalidYOffset = -(minesOfDivanSolution.getY() - (CH_LOWEST_VALID_Y -1)); + Vec3 offset = new Vec3(0.0, invalidYOffset, 0.0); compassUse1.playerPos = compassUse1.playerPos.add(offset.xCoord, offset.yCoord, offset.zCoord); for (ParticleSpawn particle : compassUse1.particles) { @@ -717,96 +721,35 @@ class CrystalWishingCompassSolverTest { } @Test - void possible_targets_only_contains_city_and_nucleus_when_in_remnants_without_sapphire_crystal() { + void possible_targets_contains_all_valid_targets_when_all_crystals_missing() { // Arrange Solution solution = new Solution( new ArrayList<>(Collections.singletonList(precursorCityCompassUse1)), Vec3i.NULL_VECTOR); + solver.foundCrystals = () -> EnumSet.noneOf(Crystal.class); + solver.keyInInventory = () -> false; + solver.kingsScentPresent = () -> false; // Act checkSolution(solution); EnumSet<CompassTarget> targets = solver.getPossibleTargets(); // Assert - Assertions.assertTrue(targets.contains(CompassTarget.PRECURSOR_CITY)); Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS)); - Assertions.assertEquals(2, targets.size()); - } - - @Test - void possible_targets_only_contains_mines_and_nucleus_when_in_deposits_without_jade_crystal() { - // Arrange - Solution solution = new Solution( - new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)), - Vec3i.NULL_VECTOR); - - // Act - checkSolution(solution); - EnumSet<CompassTarget> targets = solver.getPossibleTargets(); - - // Assert + Assertions.assertTrue(targets.contains(CompassTarget.ODAWA)); Assertions.assertTrue(targets.contains(CompassTarget.MINES_OF_DIVAN)); - Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS)); - Assertions.assertEquals(2, targets.size()); - } - - @Test - void possible_targets_only_contains_king_or_queen_and_nucleus_when_in_holdout_without_crystal() { - // Arrange - Solution solution = new Solution( - new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)), - Vec3i.NULL_VECTOR); - - // Act - checkSolution(solution); - EnumSet<CompassTarget> targets = solver.getPossibleTargets(); - - // Assert - Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING) || - targets.contains(CompassTarget.GOBLIN_QUEEN)); - Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS)); - Assertions.assertEquals(2, targets.size()); - } - - @Test - void possible_targets_only_contains_king_and_odawa_and_nucleus_when_in_jungle_without_crystal_or_key() { - // Arrange - Solution solution = new Solution( - new ArrayList<>(Collections.singletonList(jungleCompassUse1)), - Vec3i.NULL_VECTOR); - - // Act - checkSolution(solution); - EnumSet<CompassTarget> targets = solver.getPossibleTargets(); - - // Assert Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING)); - Assertions.assertTrue(targets.contains(CompassTarget.ODAWA)); - Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS)); - Assertions.assertEquals(3, targets.size()); - } - - @Test - void possible_targets_only_contains_bal_and_nucleus_when_in_magma_fields_without_crystal() { - // Arrange - Solution solution = new Solution( - new ArrayList<>(Collections.singletonList(magmaCompassUse1)), - Vec3i.NULL_VECTOR); - - // Act - checkSolution(solution); - EnumSet<CompassTarget> targets = solver.getPossibleTargets(); - - // Assert + Assertions.assertTrue(targets.contains(CompassTarget.PRECURSOR_CITY)); Assertions.assertTrue(targets.contains(CompassTarget.BAL)); - Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS)); - Assertions.assertEquals(2, targets.size()); + // No key or king's scent, so these should be false + Assertions.assertFalse(targets.contains(CompassTarget.JUNGLE_TEMPLE)); + Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_QUEEN)); } private void CheckExcludedTargetsForCrystals( - CompassUse compassUseToExecute, - ArrayList<CompassTarget> excludedTargets, - EnumSet<Crystal> foundCrystals) { + CompassUse compassUseToExecute, + ArrayList<CompassTarget> excludedTargets, + EnumSet<Crystal> foundCrystals) { // Arrange EnumSet<CompassTarget> targets; Solution solution = new Solution( @@ -838,39 +781,54 @@ class CrystalWishingCompassSolverTest { @Test void possible_targets_excludes_king_and_queen_when_amber_crystal_found() { + // Arrange ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Arrays.asList( CompassTarget.GOBLIN_KING, CompassTarget.GOBLIN_QUEEN )); + + // Act & Assert CheckExcludedTargetsForCrystals(goblinHoldoutCompassUse1, excludedTargets, EnumSet.of(Crystal.AMBER)); } @Test void possible_targets_excludes_odawa_and_temple_when_amethyst_crystal_found() { + // Arrange ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Arrays.asList( CompassTarget.ODAWA, CompassTarget.JUNGLE_TEMPLE)); + + // Act & Assert CheckExcludedTargetsForCrystals(jungleCompassUse1, excludedTargets, EnumSet.of(Crystal.AMETHYST)); } @Test void possible_targets_excludes_mines_when_jade_crystal_found() { + // Arrange ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList( CompassTarget.MINES_OF_DIVAN)); + + // Act & Assert CheckExcludedTargetsForCrystals(minesOfDivanCompassUse1, excludedTargets, EnumSet.of(Crystal.JADE)); } @Test void possible_targets_excludes_city_when_sapphire_crystal_found() { + // Arrange ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList( CompassTarget.PRECURSOR_CITY)); + + // Act & Assert CheckExcludedTargetsForCrystals(precursorCityCompassUse1, excludedTargets, EnumSet.of(Crystal.SAPPHIRE)); } @Test void possible_targets_excludes_bal_when_topaz_crystal_found() { + // Arrange ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList( CompassTarget.BAL)); + + // Act & Assert CheckExcludedTargetsForCrystals(magmaCompassUse1, excludedTargets, EnumSet.of(Crystal.TOPAZ)); } @@ -893,7 +851,7 @@ class CrystalWishingCompassSolverTest { } @Test - void solver_resets_when_possible_targets_change_based_on_location() { + void solver_resets_when_player_location_changes_zones() { // Arrange Solution solution = new Solution( new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)), @@ -911,6 +869,44 @@ class CrystalWishingCompassSolverTest { } @Test + void solver_resets_based_on_jungle_key_presence() { + // Arrange + Solution solution = new Solution( + new ArrayList<>(Collections.singletonList(jungleCompassUse1)), + Vec3i.NULL_VECTOR); + + // Act + solver.keyInInventory = () -> false; + checkSolution(solution); + systemTimeMillis += jungleCompassUse2.timeIncrementMillis; + solver.keyInInventory = () -> true; + HandleCompassResult handleCompassResult = solver.handleCompassUse(jungleCompassUse2.playerPos); + + // Assert + Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult); + Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState()); + } + + @Test + void solver_resets_based_on_kings_scent_presence() { + // Arrange + Solution solution = new Solution( + new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)), + Vec3i.NULL_VECTOR); + + // Act + solver.kingsScentPresent = () -> false; + checkSolution(solution); + systemTimeMillis += goblinHoldoutCompassUse2.timeIncrementMillis; + solver.kingsScentPresent = () -> true; + HandleCompassResult handleCompassResult = solver.handleCompassUse(goblinHoldoutCompassUse2.playerPos); + + // Assert + Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult); + Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState()); + } + + @Test void mines_of_divan_solution_is_solved() { // Arrange Solution solution = new Solution( @@ -923,7 +919,7 @@ class CrystalWishingCompassSolverTest { } @Test - void jungle_temple_solution_with_key_in_inventory_is_solved() { + void jungle_temple_solution_with_key_in_inventory_is_solved_successfully_excluding_bal() { // Arrange Solution solution = new Solution( new ArrayList<>(Arrays.asList(jungleCompassUse1, jungleCompassUse2)), @@ -984,11 +980,17 @@ class CrystalWishingCompassSolverTest { } EnumSet<CompassTarget> GetSolutionTargetsHelper( + HollowsZone compassUsedZone, + EnumSet<Crystal> foundCrystals, EnumSet<CompassTarget> possibleTargets, Vec3Comparable solutionCoords, int expectedSolutionCount) { EnumSet<CompassTarget> solutionTargets = - CrystalWishingCompassSolver.getSolutionTargets(possibleTargets, solutionCoords); + CrystalWishingCompassSolver.getSolutionTargets( + compassUsedZone, + foundCrystals, + possibleTargets, + solutionCoords); Assertions.assertEquals(expectedSolutionCount, solutionTargets.size()); return solutionTargets; } @@ -997,133 +999,229 @@ class CrystalWishingCompassSolverTest { void solutionPossibleTargets_removes_nucleus_when_coords_not_in_nucleus() { // Arrange & Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.MITHRIL_DEPOSITS, + EnumSet.noneOf(Crystal.class), EnumSet.allOf(CompassTarget.class), new Vec3Comparable(minesOfDivanSolution), - 2); + 1); - //Assert + // Assert Assertions.assertFalse(solutionTargets.contains(CompassTarget.CRYSTAL_NUCLEUS)); } @Test - void solutionPossibleTargets_includes_adjacent_zones() { + void solutionPossibleTargets_includes_jungle_temple_and_bal_from_other_zones_when_overlapping() { + // Arrange + EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); + possibleTargets.remove(CompassTarget.ODAWA); + + // Act + EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.GOBLIN_HOLDOUT, + EnumSet.of(Crystal.AMBER), + possibleTargets, + new Vec3Comparable(202, 72, 513), // upper left of Goblin Holdout + 2); + + // Assert + Assertions.assertTrue(solutionTargets.contains(CompassTarget.JUNGLE_TEMPLE)); + Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL)); + } + + @Test + void solutionPossibleTargets_includes_king_odawa_and_mines_of_divan_from_other_zones_when_overlapping() { // Arrange & Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.PRECURSOR_REMNANTS, + EnumSet.noneOf(Crystal.class), EnumSet.allOf(CompassTarget.class), - kingMinesOrNucleusCoordsInRemnants, - 2); + kingOdawaMinesOrNucleusCoordsInRemnants, + 3); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_KING)); Assertions.assertTrue(solutionTargets.contains(CompassTarget.MINES_OF_DIVAN)); + Assertions.assertTrue(solutionTargets.contains(CompassTarget.ODAWA)); } @Test - void solutionPossibleTargets_skips_y_filtering_when_single_possible_target() { - // Arrange & Act + void solutionPossibleTargets_includes_city_and_queen_from_other_zones_when_overlapping() { + // Arrange + EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); + possibleTargets.remove(CompassTarget.GOBLIN_KING); + possibleTargets.remove(CompassTarget.ODAWA); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( - EnumSet.of(CompassTarget.GOBLIN_QUEEN), - new Vec3Comparable(goblinHoldoutKingSolution), // Coords not valid for queen - 1); + HollowsZone.MITHRIL_DEPOSITS, + EnumSet.noneOf(Crystal.class), + possibleTargets, + queenKingOdawaOrCityNucleusCoordsInMithrilDeposits, + 2); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_QUEEN)); + Assertions.assertTrue(solutionTargets.contains(CompassTarget.PRECURSOR_CITY)); + } + + @Test + void solutionPossibleTargets_excludes_jungle_temple_from_other_zone_when_not_overlapping() { + // Arrange + Vec3Comparable notOverlapping = new Vec3Comparable(202, 72, 513+110); // upper left of Goblin Holdout + EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); + possibleTargets.remove(CompassTarget.ODAWA); + + // Act + EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.GOBLIN_HOLDOUT, + EnumSet.of(Crystal.AMBER), + possibleTargets, + notOverlapping, + 1); + + // Assert + Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL)); } @Test - void solutionPossibleTargets_still_filters_non_adjacent_when_single_possible_target() { - // Arrange, Act and Assert - GetSolutionTargetsHelper( - EnumSet.of(CompassTarget.ODAWA), - kingMinesOrNucleusCoordsInRemnants, + void solutionPossibleTargets_excludes_king_odawa_and_mines_of_divan_from_other_zones_when_not_overlapping() { + // Arrange + Vec3Comparable notOverlapping = kingOdawaMinesOrNucleusCoordsInRemnants.addVector(100, 0, 100); + + // Act & Assert + EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.PRECURSOR_REMNANTS, + EnumSet.noneOf(Crystal.class), + EnumSet.allOf(CompassTarget.class), + notOverlapping, + 0); + } + + @Test + void solutionPossibleTargets_excludes_city_and_queen_from_other_zones_when_not_overlapping() { + // Arrange + Vec3Comparable notOverlapping = queenKingOdawaOrCityNucleusCoordsInMithrilDeposits.addVector(100, 0, -100); + EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); + possibleTargets.remove(CompassTarget.GOBLIN_KING); + possibleTargets.remove(CompassTarget.ODAWA); + + // Act & Assert + EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.MITHRIL_DEPOSITS, + EnumSet.noneOf(Crystal.class), + possibleTargets, + notOverlapping, 0); } @Test void solutionPossibleTargets_includes_king_based_on_y_coordinate() { - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.ODAWA); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.GOBLIN_HOLDOUT, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(goblinHoldoutKingSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_KING)); } @Test void solutionPossibleTargets_includes_odawa_based_on_y_coordinate() { - // Arrange & Act - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.GOBLIN_KING); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.JUNGLE, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(odawaSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.ODAWA)); } @Test void solutionPossibleTargets_includes_mines_based_on_y_coordinate() { - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.ODAWA); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.MITHRIL_DEPOSITS, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(minesOfDivanSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.MINES_OF_DIVAN)); } @Test void solutionPossibleTargets_includes_temple_based_on_y_coordinate() { - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.BAL); possibleTargets.remove(CompassTarget.ODAWA); possibleTargets.remove(CompassTarget.GOBLIN_KING); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.JUNGLE, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(jungleSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.JUNGLE_TEMPLE)); } @Test void solutionPossibleTargets_includes_queen_based_on_y_coordinate() { - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.GOBLIN_KING); possibleTargets.remove(CompassTarget.ODAWA); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.GOBLIN_HOLDOUT, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(goblinHoldoutQueenSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_QUEEN)); } @Test void solutionPossibleTargets_includes_city_based_on_y_coordinate() { - // Arrange & Act + // Arrange EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class); possibleTargets.remove(CompassTarget.GOBLIN_KING); + + // Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.PRECURSOR_REMNANTS, + EnumSet.noneOf(Crystal.class), possibleTargets, new Vec3Comparable(precursorCitySolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.PRECURSOR_CITY)); } @@ -1131,11 +1229,13 @@ class CrystalWishingCompassSolverTest { void solutionPossibleTargets_includes_bal_based_on_y_coordinate() { // Arrange & Act EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper( + HollowsZone.MAGMA_FIELDS, + EnumSet.noneOf(Crystal.class), EnumSet.allOf(CompassTarget.class), new Vec3Comparable(magmaSolution), 1); - //Assert + // Assert Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL)); } |