/*
* Copyright (C) 2022 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.CompassTarget;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.HandleCompassResult;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.SolverState;
import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
import net.minecraft.util.BlockPos;
import net.minecraft.util.Vec3;
import net.minecraft.util.Vec3i;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.ALL_PARTICLES_MAX_MILLIS;
import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.Crystal;
import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.HollowsZone;
import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.getInstance;
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,
new BlockPos(754, 137, 239),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(754.358459, 138.536407, 239.200928), 137),
new ParticleSpawn(new Vec3Comparable(754.315735, 138.444351, 239.690521), 45),
new ParticleSpawn(new Vec3Comparable(754.272278, 138.352051, 240.180008), 51),
new ParticleSpawn(new Vec3Comparable(754.228760, 138.259750, 240.669479), 49),
new ParticleSpawn(new Vec3Comparable(754.185303, 138.167435, 241.158966), 57),
new ParticleSpawn(new Vec3Comparable(754.141846, 138.075134, 241.648438), 50),
new ParticleSpawn(new Vec3Comparable(754.098328, 137.982819, 242.137909), 51),
new ParticleSpawn(new Vec3Comparable(754.054871, 137.890518, 242.627396), 57),
new ParticleSpawn(new Vec3Comparable(754.011353, 137.798203, 243.116867), 44),
new ParticleSpawn(new Vec3Comparable(753.967896, 137.705887, 243.606354), 59),
new ParticleSpawn(new Vec3Comparable(753.924438, 137.613586, 244.095825), 35),
new ParticleSpawn(new Vec3Comparable(753.880920, 137.521271, 244.585297), 48),
new ParticleSpawn(new Vec3Comparable(753.837463, 137.428970, 245.074783), 70),
new ParticleSpawn(new Vec3Comparable(753.793945, 137.336655, 245.564255), 33),
new ParticleSpawn(new Vec3Comparable(753.750488, 137.244354, 246.053741), 55),
new ParticleSpawn(new Vec3Comparable(753.707031, 137.152039, 246.543213), 42),
new ParticleSpawn(new Vec3Comparable(753.663513, 137.059738, 247.032700), 56),
new ParticleSpawn(new Vec3Comparable(753.620056, 136.967422, 247.522171), 48),
new ParticleSpawn(new Vec3Comparable(753.576538, 136.875122, 248.011642), 56),
new ParticleSpawn(new Vec3Comparable(754.333618, 138.527710, 239.197800), 55)
)),
HandleCompassResult.SUCCESS,
SolverState.NEED_SECOND_COMPASS
);
private final CompassUse minesOfDivanCompassUse2 = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
new BlockPos(760, 134, 266),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(759.686951, 135.524994, 266.190704), 129),
new ParticleSpawn(new Vec3Comparable(759.625183, 135.427887, 266.677277), 69),
new ParticleSpawn(new Vec3Comparable(759.561707, 135.330704, 267.163635), 31),
new ParticleSpawn(new Vec3Comparable(759.498230, 135.233536, 267.649963), 115),
new ParticleSpawn(new Vec3Comparable(759.434753, 135.136368, 268.136322), 0),
new ParticleSpawn(new Vec3Comparable(759.371277, 135.039200, 268.622650), 46),
new ParticleSpawn(new Vec3Comparable(759.307800, 134.942017, 269.109009), 49),
new ParticleSpawn(new Vec3Comparable(759.244324, 134.844849, 269.595337), 59),
new ParticleSpawn(new Vec3Comparable(759.180847, 134.747681, 270.081696), 45),
new ParticleSpawn(new Vec3Comparable(759.117371, 134.650513, 270.568024), 39),
new ParticleSpawn(new Vec3Comparable(759.053894, 134.553329, 271.054352), 67),
new ParticleSpawn(new Vec3Comparable(758.990356, 134.456161, 271.540710), 49),
new ParticleSpawn(new Vec3Comparable(758.926880, 134.358994, 272.027039), 32),
new ParticleSpawn(new Vec3Comparable(758.863403, 134.261826, 272.513397), 61),
new ParticleSpawn(new Vec3Comparable(758.799927, 134.164642, 272.999725), 44),
new ParticleSpawn(new Vec3Comparable(758.736450, 134.067474, 273.486084), 48),
new ParticleSpawn(new Vec3Comparable(758.672974, 133.970306, 273.972412), 57),
new ParticleSpawn(new Vec3Comparable(758.609497, 133.873138, 274.458740), 55),
new ParticleSpawn(new Vec3Comparable(758.546021, 133.775955, 274.945099), 59),
new ParticleSpawn(new Vec3Comparable(758.482544, 133.678787, 275.431427), 38),
new ParticleSpawn(new Vec3Comparable(759.636658, 135.522827, 266.186371), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.SOLVED
);
Vec3i minesOfDivanSolution = new Vec3i(735, 98, 451);
private final CompassUse goblinHoldoutCompassUse1 = new CompassUse(
1647776326763L,
new BlockPos(454, 87, 776),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(454.171722, 88.616852, 775.807190), 188),
new ParticleSpawn(new Vec3Comparable(454.010315, 88.613464, 775.333984), 44),
new ParticleSpawn(new Vec3Comparable(453.849243, 88.610069, 774.860657), 61),
new ParticleSpawn(new Vec3Comparable(453.688141, 88.606674, 774.387329), 51),
new ParticleSpawn(new Vec3Comparable(453.527069, 88.603271, 773.914001), 40),
new ParticleSpawn(new Vec3Comparable(453.365997, 88.599876, 773.440674), 57),
new ParticleSpawn(new Vec3Comparable(453.204926, 88.596481, 772.967346), 45),
new ParticleSpawn(new Vec3Comparable(453.043854, 88.593086, 772.494019), 49),
new ParticleSpawn(new Vec3Comparable(452.882782, 88.589691, 772.020691), 46),
new ParticleSpawn(new Vec3Comparable(452.721710, 88.586288, 771.547302), 65),
new ParticleSpawn(new Vec3Comparable(452.560638, 88.582893, 771.073975), 43),
new ParticleSpawn(new Vec3Comparable(452.399567, 88.579498, 770.600647), 50),
new ParticleSpawn(new Vec3Comparable(452.238495, 88.576103, 770.127319), 48),
new ParticleSpawn(new Vec3Comparable(452.077423, 88.572701, 769.653992), 47),
new ParticleSpawn(new Vec3Comparable(451.916351, 88.569305, 769.180664), 60),
new ParticleSpawn(new Vec3Comparable(451.755280, 88.565910, 768.707336), 40),
new ParticleSpawn(new Vec3Comparable(451.594208, 88.562515, 768.234009), 69),
new ParticleSpawn(new Vec3Comparable(451.433136, 88.559120, 767.760681), 40),
new ParticleSpawn(new Vec3Comparable(451.272064, 88.555717, 767.287354), 42),
new ParticleSpawn(new Vec3Comparable(454.183441, 88.616600, 775.803040), 54)
)),
HandleCompassResult.SUCCESS,
SolverState.NEED_SECOND_COMPASS
);
private final CompassUse goblinHoldoutCompassUse2 = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
new BlockPos(439, 85, 777),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(439.068848, 86.624870, 776.043701), 136),
new ParticleSpawn(new Vec3Comparable(438.936066, 86.625786, 775.561646), 46),
new ParticleSpawn(new Vec3Comparable(438.804352, 86.626595, 775.079346), 65),
new ParticleSpawn(new Vec3Comparable(438.672699, 86.627396, 774.596985), 40),
new ParticleSpawn(new Vec3Comparable(438.541016, 86.628197, 774.114624), 51),
new ParticleSpawn(new Vec3Comparable(438.409332, 86.628998, 773.632263), 50),
new ParticleSpawn(new Vec3Comparable(438.277679, 86.629799, 773.149902), 50),
new ParticleSpawn(new Vec3Comparable(438.145996, 86.630608, 772.667603), 56),
new ParticleSpawn(new Vec3Comparable(438.014343, 86.631409, 772.185242), 40),
new ParticleSpawn(new Vec3Comparable(437.882660, 86.632210, 771.702881), 65),
new ParticleSpawn(new Vec3Comparable(437.751007, 86.633011, 771.220520), 45),
new ParticleSpawn(new Vec3Comparable(437.619324, 86.633812, 770.738159), 42),
new ParticleSpawn(new Vec3Comparable(437.487671, 86.634613, 770.255798), 60),
new ParticleSpawn(new Vec3Comparable(437.355988, 86.635414, 769.773499), 51),
new ParticleSpawn(new Vec3Comparable(437.224335, 86.636215, 769.291138), 44),
new ParticleSpawn(new Vec3Comparable(437.092651, 86.637024, 768.808777), 56),
new ParticleSpawn(new Vec3Comparable(436.960999, 86.637825, 768.326416), 56),
new ParticleSpawn(new Vec3Comparable(436.829315, 86.638626, 767.844055), 40),
new ParticleSpawn(new Vec3Comparable(436.697632, 86.639427, 767.361694), 50),
new ParticleSpawn(new Vec3Comparable(436.565979, 86.640228, 766.879395), 46),
new ParticleSpawn(new Vec3Comparable(439.108551, 86.620811, 776.031067), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.SOLVED
);
Vec3i goblinHoldoutKingSolution = new Vec3i(377, 87, 550);
Vec3i goblinHoldoutQueenSolution = new Vec3i(322, 139, 769);
private final CompassUse precursorCityCompassUse1 = new CompassUse(
1647744920365L,
new BlockPos(570, 120, 565),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(570.428955, 121.630745, 565.674500), 192),
new ParticleSpawn(new Vec3Comparable(570.572998, 121.642563, 566.153137), 52),
new ParticleSpawn(new Vec3Comparable(570.714233, 121.654442, 566.632629), 45),
new ParticleSpawn(new Vec3Comparable(570.855286, 121.666321, 567.112183), 51),
new ParticleSpawn(new Vec3Comparable(570.996338, 121.678200, 567.591736), 0),
new ParticleSpawn(new Vec3Comparable(571.137390, 121.690079, 568.071289), 111),
new ParticleSpawn(new Vec3Comparable(571.278442, 121.701958, 568.550781), 38),
new ParticleSpawn(new Vec3Comparable(571.419495, 121.713844, 569.030334), 51),
new ParticleSpawn(new Vec3Comparable(571.560547, 121.725723, 569.509888), 49),
new ParticleSpawn(new Vec3Comparable(571.701599, 121.737602, 569.989441), 0),
new ParticleSpawn(new Vec3Comparable(571.842651, 121.749481, 570.468994), 101),
new ParticleSpawn(new Vec3Comparable(571.983704, 121.761360, 570.948547), 53),
new ParticleSpawn(new Vec3Comparable(572.124756, 121.773239, 571.428101), 47),
new ParticleSpawn(new Vec3Comparable(572.265747, 121.785118, 571.907654), 49),
new ParticleSpawn(new Vec3Comparable(572.406799, 121.796997, 572.387207), 49),
new ParticleSpawn(new Vec3Comparable(572.547852, 121.808876, 572.866699), 51),
new ParticleSpawn(new Vec3Comparable(572.688904, 121.820755, 573.346252), 57),
new ParticleSpawn(new Vec3Comparable(572.829956, 121.832634, 573.825806), 42),
new ParticleSpawn(new Vec3Comparable(572.971008, 121.844513, 574.305359), 50),
new ParticleSpawn(new Vec3Comparable(573.112061, 121.856392, 574.784912), 52),
new ParticleSpawn(new Vec3Comparable(570.372192, 121.631874, 565.694946), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.NEED_SECOND_COMPASS
);
private final CompassUse precursorCityCompassUse2 = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
new BlockPos(591, 136, 579),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(590.847961, 137.589584, 579.776672), 192),
new ParticleSpawn(new Vec3Comparable(590.918945, 137.528259, 580.267761), 50),
new ParticleSpawn(new Vec3Comparable(590.985229, 137.465118, 580.759338), 56),
new ParticleSpawn(new Vec3Comparable(591.051147, 137.401855, 581.250916), 47),
new ParticleSpawn(new Vec3Comparable(591.117126, 137.338593, 581.742493), 47),
new ParticleSpawn(new Vec3Comparable(591.183044, 137.275330, 582.234070), 49),
new ParticleSpawn(new Vec3Comparable(591.249023, 137.212067, 582.725647), 60),
new ParticleSpawn(new Vec3Comparable(591.314941, 137.148804, 583.217224), 55),
new ParticleSpawn(new Vec3Comparable(591.380920, 137.085541, 583.708801), 47),
new ParticleSpawn(new Vec3Comparable(591.446838, 137.022263, 584.200378), 50),
new ParticleSpawn(new Vec3Comparable(591.512817, 136.959000, 584.691956), 39),
new ParticleSpawn(new Vec3Comparable(591.578735, 136.895737, 585.183533), 53),
new ParticleSpawn(new Vec3Comparable(591.644714, 136.832474, 585.675110), 53),
new ParticleSpawn(new Vec3Comparable(591.710632, 136.769211, 586.166687), 45),
new ParticleSpawn(new Vec3Comparable(591.776611, 136.705948, 586.658264), 79),
new ParticleSpawn(new Vec3Comparable(591.842529, 136.642685, 587.149841), 20),
new ParticleSpawn(new Vec3Comparable(591.908508, 136.579407, 587.641418), 62),
new ParticleSpawn(new Vec3Comparable(591.974426, 136.516144, 588.132996), 48),
new ParticleSpawn(new Vec3Comparable(592.040344, 136.452881, 588.624573), 40),
new ParticleSpawn(new Vec3Comparable(592.106323, 136.389618, 589.116150), 51),
new ParticleSpawn(new Vec3Comparable(590.766357, 137.556885, 579.791565), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.SOLVED
);
Vec3i precursorCitySolution = new Vec3i(604, 124, 681);
private final CompassUse jungleCompassUse1 = new CompassUse(
1647744980313L,
new BlockPos(454, 122, 459),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(453.954895, 122.958122, 458.687866), 141),
new ParticleSpawn(new Vec3Comparable(453.515991, 122.760010, 458.553314), 59),
new ParticleSpawn(new Vec3Comparable(453.078156, 122.560112, 458.417877), 41),
new ParticleSpawn(new Vec3Comparable(452.640381, 122.360123, 458.282349), 50),
new ParticleSpawn(new Vec3Comparable(452.202606, 122.160133, 458.146851), 66),
new ParticleSpawn(new Vec3Comparable(451.764832, 121.960136, 458.011353), 35),
new ParticleSpawn(new Vec3Comparable(451.327057, 121.760147, 457.875854), 49),
new ParticleSpawn(new Vec3Comparable(450.889313, 121.560150, 457.740356), 50),
new ParticleSpawn(new Vec3Comparable(450.451538, 121.360161, 457.604858), 49),
new ParticleSpawn(new Vec3Comparable(450.013763, 121.160172, 457.469330), 51),
new ParticleSpawn(new Vec3Comparable(449.575989, 120.960175, 457.333832), 59),
new ParticleSpawn(new Vec3Comparable(449.138214, 120.760185, 457.198334), 41),
new ParticleSpawn(new Vec3Comparable(448.700439, 120.560196, 457.062836), 55),
new ParticleSpawn(new Vec3Comparable(448.262695, 120.360199, 456.927338), 50),
new ParticleSpawn(new Vec3Comparable(447.824921, 120.160210, 456.791840), 49),
new ParticleSpawn(new Vec3Comparable(447.387146, 119.960213, 456.656311), 53),
new ParticleSpawn(new Vec3Comparable(446.949371, 119.760223, 456.520813), 43),
new ParticleSpawn(new Vec3Comparable(446.511597, 119.560234, 456.385315), 51),
new ParticleSpawn(new Vec3Comparable(446.073853, 119.360237, 456.249817), 49),
new ParticleSpawn(new Vec3Comparable(445.636078, 119.160248, 456.114319), 56),
new ParticleSpawn(new Vec3Comparable(453.975647, 122.920158, 458.668488), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.NEED_SECOND_COMPASS
);
private final CompassUse jungleCompassUse2 = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
new BlockPos(438, 126, 468),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(437.701721, 127.395279, 467.455048), 139),
new ParticleSpawn(new Vec3Comparable(437.297852, 127.161415, 467.275604), 35),
new ParticleSpawn(new Vec3Comparable(436.895813, 126.927208, 467.092529), 68),
new ParticleSpawn(new Vec3Comparable(436.493896, 126.692986, 466.909241), 41),
new ParticleSpawn(new Vec3Comparable(436.091980, 126.458763, 466.725952), 54),
new ParticleSpawn(new Vec3Comparable(435.690033, 126.224533, 466.542664), 39),
new ParticleSpawn(new Vec3Comparable(435.288116, 125.990311, 466.359375), 52),
new ParticleSpawn(new Vec3Comparable(434.886200, 125.756088, 466.176086), 66),
new ParticleSpawn(new Vec3Comparable(434.484283, 125.521866, 465.992767), 40),
new ParticleSpawn(new Vec3Comparable(434.082367, 125.287636, 465.809479), 41),
new ParticleSpawn(new Vec3Comparable(433.680420, 125.053413, 465.626190), 50),
new ParticleSpawn(new Vec3Comparable(433.278503, 124.819191, 465.442902), 59),
new ParticleSpawn(new Vec3Comparable(432.876587, 124.584969, 465.259613), 54),
new ParticleSpawn(new Vec3Comparable(432.474670, 124.350746, 465.076294), 38),
new ParticleSpawn(new Vec3Comparable(432.072723, 124.116516, 464.893005), 63),
new ParticleSpawn(new Vec3Comparable(431.670807, 123.882294, 464.709717), 36),
new ParticleSpawn(new Vec3Comparable(431.268890, 123.648071, 464.526428), 64),
new ParticleSpawn(new Vec3Comparable(430.866974, 123.413849, 464.343140), 48),
new ParticleSpawn(new Vec3Comparable(430.465057, 123.179619, 464.159821), 53),
new ParticleSpawn(new Vec3Comparable(430.063110, 122.945396, 463.976532), 46),
new ParticleSpawn(new Vec3Comparable(437.732666, 127.385803, 467.381592), 1)
)),
HandleCompassResult.SUCCESS,
SolverState.SOLVED
);
Vec3i jungleSolution = new Vec3i(343, 72, 424);
Vec3i jungleSolutionTempleDoor = new Vec3i(
jungleSolution.getX() - 57,
jungleSolution.getY() + 36,
jungleSolution.getZ() - 21
);
private final CompassUse magmaCompassUse1 = new CompassUse(
1647745029814L,
new BlockPos(462, 58, 550),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(462.226898, 59.614380, 550.032654), 160),
new ParticleSpawn(new Vec3Comparable(462.693848, 59.609089, 549.853943), 47),
new ParticleSpawn(new Vec3Comparable(463.160706, 59.603809, 549.674988), 48),
new ParticleSpawn(new Vec3Comparable(463.627533, 59.598526, 549.496033), 136),
new ParticleSpawn(new Vec3Comparable(464.094391, 59.593246, 549.317017), 0),
new ParticleSpawn(new Vec3Comparable(464.561218, 59.587963, 549.138062), 0),
new ParticleSpawn(new Vec3Comparable(465.028076, 59.582684, 548.959106), 53),
new ParticleSpawn(new Vec3Comparable(465.494904, 59.577400, 548.780090), 48),
new ParticleSpawn(new Vec3Comparable(465.961761, 59.572117, 548.601135), 55),
new ParticleSpawn(new Vec3Comparable(466.428589, 59.566837, 548.422180), 47),
new ParticleSpawn(new Vec3Comparable(466.895416, 59.561554, 548.243164), 46),
new ParticleSpawn(new Vec3Comparable(467.362274, 59.556274, 548.064209), 53),
new ParticleSpawn(new Vec3Comparable(467.829102, 59.550991, 547.885254), 50),
new ParticleSpawn(new Vec3Comparable(468.295959, 59.545712, 547.706238), 54),
new ParticleSpawn(new Vec3Comparable(468.762787, 59.540428, 547.527283), 52),
new ParticleSpawn(new Vec3Comparable(469.229645, 59.535145, 547.348328), 105),
new ParticleSpawn(new Vec3Comparable(469.696472, 59.529865, 547.169312), 1),
new ParticleSpawn(new Vec3Comparable(470.163300, 59.524582, 546.990356), 51),
new ParticleSpawn(new Vec3Comparable(470.630157, 59.519302, 546.811401), 40),
new ParticleSpawn(new Vec3Comparable(471.096985, 59.514019, 546.632385), 49),
new ParticleSpawn(new Vec3Comparable(462.221954, 59.614719, 550.019165), 0)
)),
HandleCompassResult.SUCCESS,
SolverState.NEED_SECOND_COMPASS
);
private final CompassUse magmaCompassUse2 = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
new BlockPos(449, 53, 556),
new ArrayList<>(Arrays.asList(
new ParticleSpawn(new Vec3Comparable(449.120911, 54.624340, 556.108948), 204),
new ParticleSpawn(new Vec3Comparable(449.587433, 54.627399, 555.929138), 102),
new ParticleSpawn(new Vec3Comparable(450.053741, 54.630432, 555.748657), 0),
new ParticleSpawn(new Vec3Comparable(450.520020, 54.633465, 555.568237), 62),
new ParticleSpawn(new Vec3Comparable(450.986298, 54.636497, 555.387756), 38),
new ParticleSpawn(new Vec3Comparable(451.452606, 54.639530, 555.207275), 48),
new ParticleSpawn(new Vec3Comparable(451.918884, 54.642563, 555.026794), 63),
new ParticleSpawn(new Vec3Comparable(452.385162, 54.645596, 554.846375), 52),
new ParticleSpawn(new Vec3Comparable(452.851471, 54.648628, 554.665894), 35),
new ParticleSpawn(new Vec3Comparable(453.317749, 54.651661, 554.485413), 53),
new ParticleSpawn(new Vec3Comparable(453.784027, 54.654694, 554.304993), 54),
new ParticleSpawn(new Vec3Comparable(454.250305, 54.657726, 554.124512), 50),
new ParticleSpawn(new Vec3Comparable(454.716614, 54.660759, 553.944031), 55),
new ParticleSpawn(new Vec3Comparable(455.182892, 54.663792, 553.763550), 49),
new ParticleSpawn(new Vec3Comparable(455.649170, 54.666824, 553.583130), 41),
new ParticleSpawn(new Vec3Comparable(456.115479, 54.669857, 553.402649), 48),
new ParticleSpawn(new Vec3Comparable(456.581757, 54.672890, 553.222168), 54),
new ParticleSpawn(new Vec3Comparable(457.048035, 54.675922, 553.041687), 45),
new ParticleSpawn(new Vec3Comparable(457.514313, 54.678959, 552.861267), 55),
new ParticleSpawn(new Vec3Comparable(449.110443, 54.623035, 556.079163), 49)
)),
HandleCompassResult.SUCCESS,
SolverState.SOLVED
);
Vec3i magmaSolution = new Vec3i(737, 56, 444);
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(
1647745029814L,
new BlockPos(512, 106, 512),
null,
HandleCompassResult.PLAYER_IN_NUCLEUS,
SolverState.NOT_STARTED
);
private void resetSolverState() {
solver.initWorld();
systemTimeMillis = 0;
solver.currentTimeMillis = () -> (systemTimeMillis);
// These must be overridden for all test cases or an exception will be thrown when
// data that is only present when running in the context of Minecraft is accessed.
solver.keyInInventory = () -> false;
solver.kingsScentPresent = () -> false;
solver.foundCrystals = () -> EnumSet.noneOf(Crystal.class);
}
@BeforeEach
void setUp() {
NEUDebugLogger.logMethod = CrystalWishingCompassSolverTest::neuDebugLog;
NEUDebugLogger.allFlagsEnabled = true;
resetSolverState();
}
private void checkSolution(Solution solution) {
int index = 0;
for (CompassUse compassUse : solution.compassUses) {
systemTimeMillis += compassUse.timeIncrementMillis;
HandleCompassResult handleCompassResult = solver.handleCompassUse(compassUse.playerPos);
Assertions.assertEquals(
compassUse.expectedHandleCompassUseResult,
handleCompassResult,
"CompassUse index " + index
);
for (ParticleSpawn particle : compassUse.particles) {
systemTimeMillis += particle.timeIncrementMillis;
solver.solveUsingParticle(
particle.spawnLocation.xCoord,
particle.spawnLocation.yCoord,
particle.spawnLocation.zCoord,
systemTimeMillis
);
}
Assertions.assertEquals(
compassUse.expectedSolverState,
solver.getSolverState(),
"CompassUse index " + index
);
if (compassUse.expectedSolverState == SolverState.SOLVED) {
Assertions.assertEquals(
solution.expectedSolutionCoords,
solver.getSolutionCoords()
);
}
index++;
}
}
@Test
void first_compass_without_particles_sets_solver_state_to_processing_first_use() {
// Arrange
CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1);
compassUse.particles.clear();
compassUse.expectedSolverState = SolverState.PROCESSING_FIRST_USE;
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(compassUse)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void new_compass_resets_processing_first_use_state_after_timeout() {
// Arrange
CompassUse processingFirstUseCompassUse = new CompassUse(minesOfDivanCompassUse1);
processingFirstUseCompassUse.particles.clear();
processingFirstUseCompassUse.expectedSolverState = SolverState.PROCESSING_FIRST_USE;
Solution processingFirstUseSolution = new Solution(
new ArrayList<>(Collections.singletonList(processingFirstUseCompassUse)),
Vec3i.NULL_VECTOR
);
checkSolution(processingFirstUseSolution);
Assertions.assertEquals(SolverState.PROCESSING_FIRST_USE, solver.getSolverState());
CompassUse resetStateCompassUse = new CompassUse(jungleCompassUse1);
resetStateCompassUse.timeIncrementMillis = ALL_PARTICLES_MAX_MILLIS + 1;
resetStateCompassUse.expectedHandleCompassUseResult = HandleCompassResult.NO_PARTICLES_FOR_PREVIOUS_COMPASS;
resetStateCompassUse.expectedSolverState = SolverState.FAILED_TIMEOUT_NO_REPEATING;
Solution goodSolution = new Solution(
new ArrayList<>(Collections.singletonList(resetStateCompassUse)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(goodSolution);
}
@Test
void first_compass_with_repeating_particles_sets_state_to_need_second_compass() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void first_compass_in_nucleus_sets_state_to_player_in_nucleus() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(nucleusCompass)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void use_while_handling_previous_returns_still_processing_first_use() {
// Arrange
CompassUse compassUse1 = new CompassUse(
1647528732979L,
new BlockPos(754, 137, 239),
new ArrayList<>(Collections.singletonList(
new ParticleSpawn(new Vec3Comparable(754.358459, 138.536407, 239.200928), 137)
)),
HandleCompassResult.SUCCESS,
SolverState.PROCESSING_FIRST_USE
);
// STILL_PROCESSING_FIRST_USE is expected instead of LOCATION_TOO_CLOSE since the solver
// isn't ready for the second compass use, which includes the location check
CompassUse compassUse2 = new CompassUse(compassUse1);
compassUse2.expectedHandleCompassUseResult = HandleCompassResult.STILL_PROCESSING_PRIOR_USE;
compassUse2.timeIncrementMillis = 500;
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(compassUse1, compassUse2)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@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;
compassUse.expectedSolverState = SolverState.FAILED_TIMEOUT_NO_REPEATING;
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(compassUse)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void compasses_too_close_returns_location_too_close_and_solver_state_is_still_need_second_compass() {
// Arrange
CompassUse secondCompassUse = new CompassUse(
DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
minesOfDivanCompassUse1.playerPos.add(2, 2, 2),
null,
HandleCompassResult.LOCATION_TOO_CLOSE,
SolverState.NEED_SECOND_COMPASS
);
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, secondCompassUse)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void second_compass_sets_solver_state_to_processing_second_use() {
// Arrange
CompassUse secondCompassUse = new CompassUse(minesOfDivanCompassUse2);
secondCompassUse.expectedSolverState = SolverState.PROCESSING_SECOND_USE;
secondCompassUse.particles.clear();
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
minesOfDivanSolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void second_compass_with_repeating_particles_sets_state_to_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
minesOfDivanSolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void particles_from_first_compass_are_ignored_by_second_compass() {
// Arrange
CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
compassUse2.particles.add(0, minesOfDivanCompassUse1.particles.get(0));
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, compassUse2)),
minesOfDivanSolution
);
// Act & Assert
checkSolution(solution);
}
private void execInvalidParticlesInvalidSolution() {
// Arrange
CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
// reverse the direction of the particles, moving the repeat particle
// to "new" end
compassUse2.particles.remove(compassUse2.particles.size() - 1);
Collections.reverse(compassUse2.particles);
// add a new repeat particle
compassUse2.particles.add(new ParticleSpawn(compassUse2.particles.get(0)));
// Adjust the player position
compassUse2.playerPos = new BlockPos(compassUse2.particles.get(0).spawnLocation);
compassUse2.expectedSolverState = SolverState.FAILED_INVALID_SOLUTION;
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, compassUse2)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void second_compass_with_inverted_particles_sets_state_to_invalid_solution() {
// Arrange, Act, and Assert
execInvalidParticlesInvalidSolution();
}
@Test
void solution_outside_hollows_sets_state_to_invalid_solution() {
// Arrange
CompassUse compassUse1 = new CompassUse(minesOfDivanCompassUse1);
CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
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) {
particle.spawnLocation = particle.spawnLocation.add(offset);
}
compassUse2.playerPos = compassUse2.playerPos.add(offset.xCoord, offset.yCoord, offset.zCoord);
for (ParticleSpawn particle : compassUse2.particles) {
particle.spawnLocation = particle.spawnLocation.add(offset);
}
compassUse2.expectedSolverState = SolverState.FAILED_INVALID_SOLUTION;
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(compassUse1, compassUse2)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void second_solution_can_be_solved_after_state_is_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
minesOfDivanSolution
);
checkSolution(solution);
Solution solution2 = new Solution(
new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
precursorCitySolution
);
// Act & Assert
checkSolution(solution2);
}
@Test
void second_solution_can_be_solved_after_state_is_failed() {
// Arrange
execInvalidParticlesInvalidSolution();
Assertions.assertEquals(solver.getSolverState(), SolverState.FAILED_INVALID_SOLUTION);
Solution solution2 = new Solution(
new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
precursorCitySolution
);
// Act & Assert
checkSolution(solution2);
}
@Test
void distant_particles_are_ignored() {
// Arrange
CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1);
compassUse.particles.get(2).spawnLocation.addVector(100.0, 100.0, 100.0);
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
Vec3i.NULL_VECTOR
);
// Act & Assert
checkSolution(solution);
}
@Test
void possible_targets_includes_queen_and_excludes_king_when_kings_scent_is_present() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)),
Vec3i.NULL_VECTOR
);
solver.kingsScentPresent = () -> true;
// Act
checkSolution(solution);
EnumSet targets = solver.getPossibleTargets();
// Assert
Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_QUEEN));
Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_KING));
}
@Test
void possible_targets_excludes_king_and_includes_queen_when_kings_scent_is_not_present() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)),
Vec3i.NULL_VECTOR
);
solver.kingsScentPresent = () -> false;
// Act
checkSolution(solution);
EnumSet targets = solver.getPossibleTargets();
// Assert
Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_QUEEN));
Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING));
}
@Test
void possible_targets_excludes_odawa_and_includes_temple_when_key_in_inventory() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(jungleCompassUse1)),
Vec3i.NULL_VECTOR
);
solver.keyInInventory = () -> true;
// Act
checkSolution(solution);
EnumSet targets = solver.getPossibleTargets();
// Assert
Assertions.assertFalse(targets.contains(CompassTarget.ODAWA));
Assertions.assertTrue(targets.contains(CompassTarget.JUNGLE_TEMPLE));
}
@Test
void possible_targets_includes_odawa_and_excludes_temple_when_key_not_in_inventory() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(jungleCompassUse1)),
Vec3i.NULL_VECTOR
);
solver.keyInInventory = () -> false;
// Act
checkSolution(solution);
EnumSet targets = solver.getPossibleTargets();
// Assert
Assertions.assertTrue(targets.contains(CompassTarget.ODAWA));
Assertions.assertFalse(targets.contains(CompassTarget.JUNGLE_TEMPLE));
}
@Test
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 targets = solver.getPossibleTargets();
// Assert
Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS));
Assertions.assertTrue(targets.contains(CompassTarget.ODAWA));
Assertions.assertTrue(targets.contains(CompassTarget.MINES_OF_DIVAN));
Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING));
Assertions.assertTrue(targets.contains(CompassTarget.PRECURSOR_CITY));
Assertions.assertTrue(targets.contains(CompassTarget.BAL));
// 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 excludedTargets,
EnumSet foundCrystals
) {
// Arrange
EnumSet targets;
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(compassUseToExecute)),
Vec3i.NULL_VECTOR
);
// Act
checkSolution(solution);
targets = solver.getPossibleTargets();
boolean targetFound = false;
for (CompassTarget target : excludedTargets) {
if (targets.contains(target)) {
targetFound = true;
break;
}
}
Assertions.assertTrue(targetFound);
resetSolverState();
solver.foundCrystals = () -> foundCrystals;
checkSolution(solution);
targets = solver.getPossibleTargets();
// Assert
for (CompassTarget target : excludedTargets) {
Assertions.assertFalse(targets.contains(target));
}
}
@Test
void possible_targets_excludes_king_and_queen_when_amber_crystal_found() {
// Arrange
ArrayList 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 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 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 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 excludedTargets = new ArrayList<>(Collections.singletonList(
CompassTarget.BAL));
// Act & Assert
CheckExcludedTargetsForCrystals(magmaCompassUse1, excludedTargets, EnumSet.of(Crystal.TOPAZ));
}
@Test
void solver_resets_when_possible_targets_change_based_on_found_crystals() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
Vec3i.NULL_VECTOR
);
// Act
checkSolution(solution);
systemTimeMillis += minesOfDivanCompassUse2.timeIncrementMillis;
solver.foundCrystals = () -> EnumSet.of(Crystal.JADE);
HandleCompassResult handleCompassResult = solver.handleCompassUse(minesOfDivanCompassUse2.playerPos);
// Assert
Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
}
@Test
void solver_resets_when_player_location_changes_zones() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
Vec3i.NULL_VECTOR
);
// Act
checkSolution(solution);
systemTimeMillis += minesOfDivanCompassUse2.timeIncrementMillis;
BlockPos newLocation = minesOfDivanCompassUse2.playerPos.add(-400, 0, 0);
HandleCompassResult handleCompassResult = solver.handleCompassUse(newLocation);
// Assert
Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
}
@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(
new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
minesOfDivanSolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void jungle_temple_solution_with_key_in_inventory_is_solved_successfully_excluding_bal() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(jungleCompassUse1, jungleCompassUse2)),
jungleSolutionTempleDoor
);
solver.keyInInventory = () -> true;
// Act & Assert
checkSolution(solution);
}
@Test
void jungle_temple_solution_is_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(jungleCompassUse1, jungleCompassUse2)),
jungleSolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void precursor_city_solution_is_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
precursorCitySolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void goblin_king_solution_is_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(goblinHoldoutCompassUse1, goblinHoldoutCompassUse2)),
goblinHoldoutKingSolution
);
// Act & Assert
checkSolution(solution);
}
@Test
void bal_solution_is_solved() {
// Arrange
Solution solution = new Solution(
new ArrayList<>(Arrays.asList(magmaCompassUse1, magmaCompassUse2)),
magmaSolution
);
// Act & Assert
checkSolution(solution);
}
EnumSet GetSolutionTargetsHelper(
HollowsZone compassUsedZone,
EnumSet foundCrystals,
EnumSet possibleTargets,
Vec3Comparable solutionCoords,
int expectedSolutionCount
) {
EnumSet solutionTargets =
CrystalWishingCompassSolver.getSolutionTargets(
compassUsedZone,
foundCrystals,
possibleTargets,
solutionCoords
);
Assertions.assertEquals(expectedSolutionCount, solutionTargets.size());
return solutionTargets;
}
@Test
void solutionPossibleTargets_removes_nucleus_when_coords_not_in_nucleus() {
// Arrange & Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.MITHRIL_DEPOSITS,
EnumSet.noneOf(Crystal.class),
EnumSet.allOf(CompassTarget.class),
new Vec3Comparable(minesOfDivanSolution),
1
);
// Assert
Assertions.assertFalse(solutionTargets.contains(CompassTarget.CRYSTAL_NUCLEUS));
}
@Test
void solutionPossibleTargets_includes_jungle_temple_and_bal_from_other_zones_when_overlapping() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet 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 solutionTargets = GetSolutionTargetsHelper(
HollowsZone.PRECURSOR_REMNANTS,
EnumSet.noneOf(Crystal.class),
EnumSet.allOf(CompassTarget.class),
kingOdawaMinesOrNucleusCoordsInRemnants,
3
);
// 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_includes_city_and_queen_from_other_zones_when_overlapping() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.MITHRIL_DEPOSITS,
EnumSet.noneOf(Crystal.class),
possibleTargets,
queenKingOdawaOrCityNucleusCoordsInMithrilDeposits,
2
);
// 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 possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.GOBLIN_HOLDOUT,
EnumSet.of(Crystal.AMBER),
possibleTargets,
notOverlapping,
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL));
}
@Test
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 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 possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
possibleTargets.remove(CompassTarget.ODAWA);
// Act & Assert
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.MITHRIL_DEPOSITS,
EnumSet.noneOf(Crystal.class),
possibleTargets,
notOverlapping,
0
);
}
@Test
void solutionPossibleTargets_includes_king_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.GOBLIN_HOLDOUT,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(goblinHoldoutKingSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_KING));
}
@Test
void solutionPossibleTargets_includes_odawa_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.JUNGLE,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(odawaSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.ODAWA));
}
@Test
void solutionPossibleTargets_includes_mines_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.MITHRIL_DEPOSITS,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(minesOfDivanSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.MINES_OF_DIVAN));
}
@Test
void solutionPossibleTargets_includes_temple_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.BAL);
possibleTargets.remove(CompassTarget.ODAWA);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.JUNGLE,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(jungleSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.JUNGLE_TEMPLE));
}
@Test
void solutionPossibleTargets_includes_queen_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
possibleTargets.remove(CompassTarget.ODAWA);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.GOBLIN_HOLDOUT,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(goblinHoldoutQueenSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_QUEEN));
}
@Test
void solutionPossibleTargets_includes_city_based_on_y_coordinate() {
// Arrange
EnumSet possibleTargets = EnumSet.allOf(CompassTarget.class);
possibleTargets.remove(CompassTarget.GOBLIN_KING);
// Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.PRECURSOR_REMNANTS,
EnumSet.noneOf(Crystal.class),
possibleTargets,
new Vec3Comparable(precursorCitySolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.PRECURSOR_CITY));
}
@Test
void solutionPossibleTargets_includes_bal_based_on_y_coordinate() {
// Arrange & Act
EnumSet solutionTargets = GetSolutionTargetsHelper(
HollowsZone.MAGMA_FIELDS,
EnumSet.noneOf(Crystal.class),
EnumSet.allOf(CompassTarget.class),
new Vec3Comparable(magmaSolution),
1
);
// Assert
Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL));
}
// Represents a particle spawn, including:
// - Milliseconds to increment the "system time" prior to spawn.
// - The particle spawn location.
static class ParticleSpawn {
long timeIncrementMillis;
Vec3Comparable spawnLocation;
ParticleSpawn(Vec3Comparable spawnLocation, long timeIncrementMillis) {
this.timeIncrementMillis = timeIncrementMillis;
this.spawnLocation = spawnLocation;
}
ParticleSpawn(ParticleSpawn source) {
timeIncrementMillis = source.timeIncrementMillis;
spawnLocation = new Vec3Comparable(source.spawnLocation);
}
}
// Represents a use of the wishing compass, including:
// - Milliseconds to increment the "system time" prior to use.
// - The player's position when the compass is used.
// - The resulting set of particles
// - The expected state of the wishing compass solver after this compass is used
static class CompassUse {
long timeIncrementMillis;
BlockPos playerPos;
ArrayList particles;
HandleCompassResult expectedHandleCompassUseResult;
SolverState expectedSolverState;
CompassUse(
long timeIncrementMillis,
BlockPos playerPos,
ArrayList particles,
HandleCompassResult expectedHandleCompassUseResult,
SolverState expectedState
) {
this.timeIncrementMillis = timeIncrementMillis;
this.playerPos = playerPos;
this.particles = particles != null ? particles : new ArrayList<>();
this.expectedHandleCompassUseResult = expectedHandleCompassUseResult;
this.expectedSolverState = expectedState;
}
CompassUse(CompassUse source) {
this.timeIncrementMillis = source.timeIncrementMillis;
this.playerPos = new BlockPos(source.playerPos);
this.particles = new ArrayList<>(source.particles);
this.expectedHandleCompassUseResult = source.expectedHandleCompassUseResult;
this.expectedSolverState = source.expectedSolverState;
}
}
static class Solution {
ArrayList compassUses;
Vec3i expectedSolutionCoords;
Solution(ArrayList compassUses, Vec3i expectedSolutionCoords) {
this.compassUses = compassUses;
this.expectedSolutionCoords = new Vec3i(
expectedSolutionCoords.getX(),
expectedSolutionCoords.getY(),
expectedSolutionCoords.getZ()
);
}
}
private static void neuDebugLog(String message) {
System.out.println(message);
}
}