diff options
author | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2023-11-13 21:03:26 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-13 21:03:26 -0500 |
commit | 736db8f1b0076ebe639bf0c1590e86d05191f01f (patch) | |
tree | 490e07d455521daa0579ec6b5ae49649925caa07 /src/main/java | |
parent | 4828dd781882324bd455c199bbf6ad625886a96b (diff) | |
parent | f4ff9aad7b97230fd70dd70f067c0aac4d1e2682 (diff) | |
download | Skyblocker-736db8f1b0076ebe639bf0c1590e86d05191f01f.tar.gz Skyblocker-736db8f1b0076ebe639bf0c1590e86d05191f01f.tar.bz2 Skyblocker-736db8f1b0076ebe639bf0c1590e86d05191f01f.zip |
Merge branch 'master' into batched-rendering
Diffstat (limited to 'src/main/java')
13 files changed, 221 insertions, 113 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 52c44082..ad3b6318 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.diana.MythologicalRitual; import de.hysky.skyblocker.skyblock.dungeon.*; @@ -114,6 +115,7 @@ public class SkyblockerMod implements ClientModInitializer { MuseumItemCache.init(); SecretsTracker.init(); ApiUtils.init(); + Debug.init(); RenderHelper.init(); containerSolverManager.init(); statusBarTracker.init(); diff --git a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java index b52d6ff5..218eb8d1 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java @@ -4,7 +4,6 @@ import de.hysky.skyblocker.skyblock.itemlist.SkyblockCraftingRecipe; import de.hysky.skyblocker.utils.ItemUtils; import dev.emi.emi.api.recipe.EmiCraftingRecipe; import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.stack.Comparison; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.api.widget.WidgetHolder; @@ -16,7 +15,7 @@ public class SkyblockEmiRecipe extends EmiCraftingRecipe { private final String craftText; public SkyblockEmiRecipe(SkyblockCraftingRecipe recipe) { - super(recipe.getGrid().stream().map(EmiStack::of).map(EmiIngredient.class::cast).toList(), EmiStack.of(recipe.getResult()).comparison(Comparison.compareNbt()), Identifier.of("skyblock", ItemUtils.getItemId(recipe.getResult()).toLowerCase().replace(';', '_') + "_" + recipe.getResult().getCount())); + super(recipe.getGrid().stream().map(EmiStack::of).map(EmiIngredient.class::cast).toList(), EmiStack.of(recipe.getResult()), Identifier.of("skyblock", ItemUtils.getItemId(recipe.getResult()).toLowerCase().replace(';', '_') + "_" + recipe.getResult().getCount())); this.craftText = recipe.getCraftText(); } diff --git a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java index 6ed6a32a..8dfc5dc9 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java @@ -7,6 +7,7 @@ import dev.emi.emi.api.EmiPlugin; import dev.emi.emi.api.EmiRegistry; import dev.emi.emi.api.recipe.EmiRecipeCategory; import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.Comparison; import dev.emi.emi.api.stack.EmiStack; import net.minecraft.item.Items; import net.minecraft.util.Identifier; @@ -21,7 +22,10 @@ public class SkyblockerEMIPlugin implements EmiPlugin { @Override public void register(EmiRegistry registry) { - ItemRepository.getItemsStream().map(EmiStack::of).forEach(registry::addEmiStack); + ItemRepository.getItemsStream().map(EmiStack::of).forEach(emiStack -> { + registry.addEmiStack(emiStack); + registry.setDefaultComparison(emiStack, Comparison.compareNbt()); + }); registry.addCategory(SKYBLOCK); registry.addWorkstation(SKYBLOCK, EmiStack.of(Items.CRAFTING_TABLE)); ItemRepository.getRecipesStream().map(SkyblockEmiRecipe::new).forEach(registry::addRecipe); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 699f91ef..974c451d 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -760,6 +760,9 @@ public class SkyblockerConfig { public boolean mirrorverseWaypoints = true; @SerialEntry + public boolean blobbercystGlow = true; + + @SerialEntry public boolean enigmaSoulWaypoints = false; @SerialEntry diff --git a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java index 55629a66..0b388d16 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java @@ -47,6 +47,14 @@ public class LocationsCategory { .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow.@Tooltip"))) + .binding(defaults.locations.rift.blobbercystGlow, + () -> config.locations.rift.blobbercystGlow, + newValue -> config.locations.rift.blobbercystGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints.@Tooltip"))) .binding(defaults.locations.rift.enigmaSoulWaypoints, diff --git a/src/main/java/de/hysky/skyblocker/debug/Debug.java b/src/main/java/de/hysky/skyblocker/debug/Debug.java new file mode 100644 index 00000000..1fc22d2a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/debug/Debug.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.debug; + +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; + +public class Debug { + private static final boolean DEBUG_ENABLED = Boolean.parseBoolean(System.getProperty("skyblocker.debug", "false")); + + public static void init() { + if (DEBUG_ENABLED || FabricLoader.getInstance().isDevelopmentEnvironment()) { + ClientCommandRegistrationCallback.EVENT.register(DumpPlayersCommand::register); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java b/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java new file mode 100644 index 00000000..5f6e0362 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java @@ -0,0 +1,31 @@ +package de.hysky.skyblocker.debug; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import de.hysky.skyblocker.SkyblockerMod; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.Text; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class DumpPlayersCommand { + + static void register(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("debug") + .then(literal("dumpPlayers") + .executes(context -> { + FabricClientCommandSource source = context.getSource(); + + source.getWorld().getEntities().forEach(e -> { + if (e instanceof PlayerEntity player) { + source.sendFeedback(Text.of("'" + player.getName().getString() + "'")); + } + }); + + return Command.SINGLE_SUCCESS; + })))); + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java index 78c61416..42601546 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java @@ -9,7 +9,7 @@ import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; -import de.hysky.skyblocker.skyblock.dungeon.MobGlow; +import de.hysky.skyblocker.skyblock.entity.MobGlow; import net.minecraft.client.render.WorldRenderer; import net.minecraft.entity.Entity; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/MobGlow.java deleted file mode 100644 index 523b7a98..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/MobGlow.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.hysky.skyblocker.skyblock.dungeon; - -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; -import net.minecraft.entity.Entity; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.entity.passive.BatEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.util.math.Box; -import net.minecraft.world.World; - -import java.util.List; - -public class MobGlow { - public static boolean shouldMobGlow(Entity entity) { - Box box = entity.getBoundingBox(); - - if (Utils.isInDungeons() && !entity.isInvisible() && OcclusionCulling.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { - String name = entity.getName().getString(); - - // Minibosses - if (entity instanceof PlayerEntity) { - switch (name) { - case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; - case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", - "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name); - } - } - - // Regular Mobs - if (!(entity instanceof ArmorStandEntity)) { - List<ArmorStandEntity> armorStands = getArmorStands(entity.getWorld(), box); - - if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; - } - - // Bats - return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && entity instanceof BatEntity; - } - - return false; - } - - private static List<ArmorStandEntity> getArmorStands(World world, Box box) { - return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED); - } - - public static int getGlowColor(Entity entity) { - String name = entity.getName().getString(); - - if (entity instanceof PlayerEntity) { - return switch (name) { - case "Lost Adventurer" -> 0xfee15c; - case "Shadow Assassin" -> 0x5b2cb2; - case "Diamond Guy" -> 0x57c2f7; - case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", - "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name); - default -> 0xf57738; - }; - } - - return 0xf57738; - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index eda08cf6..ee517eb8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -255,7 +255,7 @@ public class DungeonSecrets { dungeonFutures.add(CompletableFuture.runAsync(() -> { try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach((room, waypointsJson) -> - addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseThrow()) + addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseGet(ArrayList::new)) ); LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { @@ -273,7 +273,7 @@ public class DungeonSecrets { try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { JsonObject customWaypointsJson = new JsonObject(); customWaypoints.rowMap().forEach((room, waypoints) -> - customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow()) + customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseGet(JsonArray::new)) ); SkyblockerMod.GSON.toJson(customWaypointsJson, writer); LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index ecfcf496..9b95f146 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -41,6 +41,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Room { + private static final Pattern SECRET_INDEX = Pattern.compile("^(\\d+)"); private static final Pattern SECRETS = Pattern.compile("§7(\\d{1,2})/(\\d{1,2}) Secrets"); @NotNull private final Type type; @@ -70,11 +71,12 @@ public class Room { private int doubleCheckBlocks; /** * Represents the matching state of the room with the following possible values: - * <li>{@link TriState#DEFAULT} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}. - * <li>{@link TriState#FALSE} means that the room has been checked and there is no match. - * <li>{@link TriState#TRUE} means that the room has been checked and there is a match. + * <li>{@link MatchState#MATCHING} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}.</li> + * <li>{@link MatchState#DOUBLE_CHECKING} means that the room has a unique match and is being double checked.</li> + * <li>{@link MatchState#MATCHED} means that the room has a unique match ans has been double checked.</li> + * <li>{@link MatchState#FAILED} means that the room has been checked and there is no match.</li> */ - private TriState matched = TriState.DEFAULT; + private MatchState matchState = MatchState.MATCHING; private Table<Integer, BlockPos, SecretWaypoint> secretWaypoints; private String name; private Direction direction; @@ -96,7 +98,7 @@ public class Room { } public boolean isMatched() { - return matched == TriState.TRUE; + return matchState == MatchState.DOUBLE_CHECKING || matchState == MatchState.MATCHED; } /** @@ -108,7 +110,7 @@ public class Room { @Override public String toString() { - return "Room{type=" + type + ", shape=" + shape + ", matched=" + matched + ", segments=" + Arrays.toString(segments.toArray()) + "}"; + return "Room{type=%s, segments=%s, shape=%s, matchState=%s, name=%s, direction=%s, physicalCornerPos=%s}".formatted(type, Arrays.toString(segments.toArray()), shape, matchState, name, direction, physicalCornerPos); } @NotNull @@ -208,6 +210,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * * @param pos the position of the secret waypoint relative to this room * @return the removed secret waypoint or {@code null} if there was no secret waypoint at the given position */ @@ -223,6 +226,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from this instance of the room. + * * @param secretIndex the index of the secret waypoint * @param relativePos the position of the secret waypoint relative to this room */ @@ -237,7 +241,7 @@ public class Room { * This method returns immediately if any of the following conditions are met: * <ul> * <li> The room does not need to be scanned and matched. (When the room is not of type {@link Type.ROOM}, {@link Type.PUZZLE}, or {@link Type.TRAP}. See {@link Type#needsScanning()}) </li> - * <li> The room has been matched or failed to match and is on cooldown. See {@link #matched}. </li> + * <li> The room has been matched or failed to match and is on cooldown. See {@link #matchState}. </li> * <li> {@link #findRoom The previous update} has not completed. </li> * </ul> * Then this method tries to match this room through: @@ -251,7 +255,7 @@ public class Room { @SuppressWarnings("JavadocReference") protected void update() { // Logical AND has higher precedence than logical OR - if (!type.needsScanning() || matched != TriState.DEFAULT || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { + if (!type.needsScanning() || matchState != MatchState.MATCHING && matchState != MatchState.DOUBLE_CHECKING || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { return; } MinecraftClient client = MinecraftClient.getInstance(); @@ -266,6 +270,9 @@ public class Room { break; } } + }).exceptionally(e -> { + DungeonSecrets.LOGGER.error("[Skyblocker Dungeon Secrets] Encountered an unknown exception while matching room {}", this, e); + return null; }); } @@ -297,16 +304,24 @@ public class Room { * </ul> * <li> If there are no matching rooms left: </li> * <ul> - * <li> Terminate matching by setting {@link #matched} to {@link TriState#FALSE}. </li> + * <li> Terminate matching by setting {@link #matchState} to {@link TriState#FALSE}. </li> * <li> Schedule another matching attempt in 50 ticks (2.5 seconds). </li> * <li> Reset {@link #possibleRooms} and {@link #checkedBlocks} with {@link #reset()}. </li> * <li> Return {@code true} </li> * </ul> * <li> If there are exactly one room matching: </li> * <ul> - * <li> Call {@link #roomMatched()}. </li> - * <li> Discard the no longer needed fields to save memory. </li> - * <li> Return {@code true} </li> + * <li> If {@link #matchState} is {@link MatchState#MATCHING}: </li> + * <ul> + * <li> Call {@link #roomMatched()}. </li> + * <li> Return {@code false}. </li> + * </ul> + * <li> If {@link #matchState} is {@link MatchState#DOUBLE_CHECKING}: </li> + * <ul> + * <li> Set the match state to {@link MatchState#MATCHED}. </li> + * <li> Discard the no longer needed fields to save memory. </li> + * <li> Return {@code true}. </li> + * </ul> * </ul> * <li> Return {@code false} </li> * </ul> @@ -334,26 +349,29 @@ public class Room { int matchingRoomsSize = possibleRooms.stream().map(Triple::getRight).mapToInt(Collection::size).sum(); if (matchingRoomsSize == 0) { // If no rooms match, reset the fields and scan again after 50 ticks. - matched = TriState.FALSE; - DungeonSecrets.LOGGER.warn("[Skyblocker] No dungeon room matches after checking {} block(s)", checkedBlocks.size()); - Scheduler.INSTANCE.schedule(() -> matched = TriState.DEFAULT, 50); + DungeonSecrets.LOGGER.warn("[Skyblocker Dungeon Secrets] No dungeon room matched after checking {} block(s) including double checking {} block(s)", checkedBlocks.size(), doubleCheckBlocks); + Scheduler.INSTANCE.schedule(() -> matchState = MatchState.MATCHING, 50); reset(); return true; - } else if (matchingRoomsSize == 1 && ++doubleCheckBlocks >= 10) { - // If one room matches, load the secrets for that room and discard the no longer needed fields. - for (Triple<Direction, Vector2ic, List<String>> directionRooms : possibleRooms) { - if (directionRooms.getRight().size() == 1) { - name = directionRooms.getRight().get(0); - direction = directionRooms.getLeft(); - physicalCornerPos = directionRooms.getMiddle(); - roomMatched(); - discard(); - return true; - } + } else if (matchingRoomsSize == 1) { + if (matchState == MatchState.MATCHING) { + // If one room matches, load the secrets for that room and set state to double-checking. + Triple<Direction, Vector2ic, List<String>> directionRoom = possibleRooms.stream().filter(directionRooms -> directionRooms.getRight().size() == 1).findAny().orElseThrow(); + name = directionRoom.getRight().get(0); + direction = directionRoom.getLeft(); + physicalCornerPos = directionRoom.getMiddle(); + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s), starting double checking", name, checkedBlocks.size()); + roomMatched(); + return false; + } else if (matchState == MatchState.DOUBLE_CHECKING && ++doubleCheckBlocks >= 10) { + // If double-checked, set state to matched and discard the no longer needed fields. + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s) including double checking {} block(s)", name, checkedBlocks.size(), doubleCheckBlocks); + discard(); + return true; } - return false; // This should never happen, we just checked that there is one possible room, and the return true in the loop should activate + return false; } else { - DungeonSecrets.LOGGER.debug("[Skyblocker] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); + DungeonSecrets.LOGGER.debug("[Skyblocker Dungeon Secrets] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); return false; } } @@ -371,7 +389,7 @@ public class Room { /** * Loads the secret waypoints for the room from {@link DungeonSecrets#waypointsJson} once it has been matched - * and sets {@link #matched} to {@link TriState#TRUE}. + * and sets {@link #matchState} to {@link MatchState#DOUBLE_CHECKING}. * * @param directionRooms the direction, position, and name of the room */ @@ -381,25 +399,29 @@ public class Room { for (JsonElement waypointElement : DungeonSecrets.getRoomWaypoints(name)) { JsonObject waypoint = waypointElement.getAsJsonObject(); String secretName = waypoint.get("secretName").getAsString(); - int secretIndex = Integer.parseInt(secretName.substring(0, Character.isDigit(secretName.charAt(1)) ? 2 : 1)); + Matcher secretIndexMatcher = SECRET_INDEX.matcher(secretName); + int secretIndex = secretIndexMatcher.find() ? Integer.parseInt(secretIndexMatcher.group(1)) : 0; BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); - matched = TriState.TRUE; - - DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); + matchState = MatchState.DOUBLE_CHECKING; } /** * Resets fields for another round of matching after room matching fails. */ private void reset() { + matchState = MatchState.FAILED; IntSortedSet segmentsX = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::x).toArray())); IntSortedSet segmentsY = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::y).toArray())); possibleRooms = getPossibleRooms(segmentsX, segmentsY); checkedBlocks = new HashSet<>(); doubleCheckBlocks = 0; + secretWaypoints = null; + name = null; + direction = null; + physicalCornerPos = null; } /** @@ -407,6 +429,7 @@ public class Room { * These fields are no longer needed and are discarded to save memory. */ private void discard() { + matchState = MatchState.MATCHED; roomsData = null; possibleRooms = null; checkedBlocks = null; @@ -473,7 +496,7 @@ public class Room { BlockState state = world.getBlockState(hitResult.getBlockPos()); if (state.isOf(Blocks.CHEST) || state.isOf(Blocks.PLAYER_HEAD) || state.isOf(Blocks.PLAYER_WALL_HEAD)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::needsInteraction).findAny() - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); } else if (state.isOf(Blocks.LEVER)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::isLever).forEach(SecretWaypoint::setFound); } @@ -491,7 +514,7 @@ public class Room { return; } secretWaypoints.values().stream().filter(SecretWaypoint::needsItemPickup).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(collector))).filter(SecretWaypoint.getRangePredicate(collector)) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -502,7 +525,7 @@ public class Room { */ protected void onBatRemoved(AmbientEntity bat) { secretWaypoints.values().stream().filter(SecretWaypoint::isBat).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(bat))) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -575,4 +598,8 @@ public class Room { public enum Direction { NW, NE, SW, SE } + + public enum MatchState { + MATCHING, DOUBLE_CHECKING, MATCHED, FAILED + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 0c2d1b34..43f624f6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -20,6 +20,8 @@ import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.function.Predicate; @@ -27,6 +29,7 @@ import java.util.function.Supplier; import java.util.function.ToDoubleFunction; public class SecretWaypoint extends Waypoint { + protected static final Logger LOGGER = LoggerFactory.getLogger(SecretWaypoint.class); public static final Codec<SecretWaypoint> CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.INT.fieldOf("secretIndex").forGetter(secretWaypoint -> secretWaypoint.secretIndex), Category.CODEC.fieldOf("category").forGetter(secretWaypoint -> secretWaypoint.category), @@ -35,8 +38,8 @@ public class SecretWaypoint extends Waypoint { ).apply(instance, SecretWaypoint::new)); public static final Codec<List<SecretWaypoint>> LIST_CODEC = CODEC.listOf(); static final List<String> SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); - private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; - private static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.waypointType; + private static final Supplier<SkyblockerConfig.SecretWaypoints> CONFIG = () -> SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; + private static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.get().waypointType; final int secretIndex; final Category category; final Text name; @@ -95,7 +98,7 @@ public class SecretWaypoint extends Waypoint { //TODO In the future, shrink the box for wither essence and items so its more realistic super.render(context); - if (CONFIG.showSecretText) { + if (CONFIG.get().showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); RenderHelper.renderText(context, name, posUp, true); double distance = context.camera().getPos().distanceTo(centerPos); @@ -135,8 +138,8 @@ public class SecretWaypoint extends Waypoint { } } - private static Category get(JsonObject waypointJson) { - return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElseThrow(); + static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(LOGGER::error).orElse(Category.DEFAULT); } boolean needsInteraction() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java new file mode 100644 index 00000000..5e0995e6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -0,0 +1,83 @@ +package de.hysky.skyblocker.skyblock.entity; + +import java.util.List; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.passive.BatEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.Box; +import net.minecraft.world.World; + +public class MobGlow { + public static boolean shouldMobGlow(Entity entity) { + Box box = entity.getBoundingBox(); + + if (!entity.isInvisible() && OcclusionCulling.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { + String name = entity.getName().getString(); + + // Dungeons + if (Utils.isInDungeons()) { + + // Minibosses + if (entity instanceof PlayerEntity) { + switch (name) { + case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; + case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", + "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name); + } + } + + // Regular Mobs + if (!(entity instanceof ArmorStandEntity)) { + List<ArmorStandEntity> armorStands = getArmorStands(entity.getWorld(), box); + + if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; + } + + // Bats + return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && entity instanceof BatEntity; + } + + // Rift + if (Utils.isInTheRift()) { + if (entity instanceof PlayerEntity) { + switch (name) { + // They have a space in their name for some reason... + case "Blobbercyst ": return SkyblockerConfigManager.get().locations.rift.blobbercystGlow; + } + } + } + } + + return false; + } + + private static List<ArmorStandEntity> getArmorStands(World world, Box box) { + return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED); + } + + public static int getGlowColor(Entity entity) { + String name = entity.getName().getString(); + + if (entity instanceof PlayerEntity) { + return switch (name) { + case "Lost Adventurer" -> 0xfee15c; + case "Shadow Assassin" -> 0x5b2cb2; + case "Diamond Guy" -> 0x57c2f7; + case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", + "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name); + case "Blobbercyst " -> Formatting.GREEN.getColorValue(); + default -> 0xf57738; + }; + } + + return 0xf57738; + } +} |