aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java352
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java6
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java318
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));
}