From b3704a19b13ccd9a2283053f60248bc5b2ae113b Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sat, 3 Aug 2024 20:32:57 +0100 Subject: [PATCH 1/9] remade slayer helpers pr --- .../de/hysky/skyblocker/SkyblockerMod.java | 4 + .../config/categories/SlayersCategory.java | 46 ++++++ .../config/configs/SlayersConfig.java | 39 +++++ .../mixins/ClientPlayNetworkHandlerMixin.java | 12 ++ .../skyblocker/mixins/WorldRendererMixin.java | 7 +- .../crimson/slayer/AttunementColours.java | 35 ++++ .../crimson/slayer/FirePillarAnnouncer.java | 60 +++++++ .../skyblock/entity/MobBoundingBoxes.java | 14 ++ .../skyblocker/skyblock/entity/MobGlow.java | 156 +++++++++++++----- .../skyblock/slayers/SlayerEntitiesGlow.java | 119 +++++++++++++ .../hysky/skyblocker/utils/SlayerUtils.java | 57 +++++-- .../assets/skyblocker/lang/en_us.json | 19 ++- 12 files changed, 514 insertions(+), 54 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index b1d25a0175..51c65abc14 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -28,6 +28,7 @@ import de.hysky.skyblocker.skyblock.end.EnderNodes; import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.entity.MobBoundingBoxes; +import de.hysky.skyblocker.skyblock.entity.MobGlow; import de.hysky.skyblocker.skyblock.events.EventNotifications; import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars; import de.hysky.skyblocker.skyblock.garden.FarmingHud; @@ -45,6 +46,7 @@ import de.hysky.skyblocker.skyblock.rift.TheRift; import de.hysky.skyblocker.skyblock.searchoverlay.SearchOverManager; import de.hysky.skyblocker.skyblock.shortcut.Shortcuts; +import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; import de.hysky.skyblocker.skyblock.special.SpecialEffects; import de.hysky.skyblocker.skyblock.tabhud.TabHud; import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; @@ -202,6 +204,8 @@ public void onInitializeClient() { TooltipManager.init(); SlotTextManager.init(); BazaarHelper.init(); + MobGlow.init(); + SlayerEntitiesGlow.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200); diff --git a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java index 0a65aa3bfd..b06cf58590 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java @@ -2,6 +2,7 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.config.configs.SlayersConfig; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.OptionDescription; @@ -17,6 +18,30 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig return ConfigCategory.createBuilder() .name(Text.translatable("skyblocker.config.slayer")) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.highlightMinis")) + .description(OptionDescription.of( + Text.translatable("skyblocker.config.slayer.highlightMinis.@Tooltip[0]"), + Text.translatable("skyblocker.config.slayer.highlightMinis.@Tooltip[1]"), + Text.translatable("skyblocker.config.slayer.highlightMinis.@Tooltip[2]"))) + .binding(defaults.slayers.highlightMinis, + () -> config.slayers.highlightMinis, + newValue -> config.slayers.highlightMinis = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.highlightBosses")) + .description(OptionDescription.of( + Text.translatable("skyblocker.config.slayer.highlightBosses.@Tooltip[0]"), + Text.translatable("skyblocker.config.slayer.highlightBosses.@Tooltip[1]"), + Text.translatable("skyblocker.config.slayer.highlightBosses.@Tooltip[2]"), + Text.translatable("skyblocker.config.slayer.highlightBosses.@Tooltip[3]"))) + .binding(defaults.slayers.highlightBosses, + () -> config.slayers.highlightBosses, + newValue -> config.slayers.highlightBosses = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + //Enderman Slayer .group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.slayer.endermanSlayer")) @@ -138,6 +163,27 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .build()) .build()) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.blazeSlayer")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.blazeSlayer.enableFirePillarAnnouncer")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.slayer.blazeSlayer.enableFirePillarAnnouncer.@Tooltip"))) + .binding(defaults.slayers.blazeSlayer.firePillarCountdown, + () -> config.slayers.blazeSlayer.firePillarCountdown, + newValue -> config.slayers.blazeSlayer.firePillarCountdown = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.blazeSlayer.attunementHighlights")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.slayer.blazeSlayer.attunementHighlights.@Tooltip"))) + .binding(defaults.slayers.blazeSlayer.attunementHighlights, + () -> config.slayers.blazeSlayer.attunementHighlights, + newValue -> config.slayers.blazeSlayer.attunementHighlights = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java index ff6c2275a4..522c5b5275 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java @@ -3,9 +3,22 @@ import dev.isxander.yacl3.config.v2.api.SerialEntry; public class SlayersConfig { + @SerialEntry + public HighlightSlayerEntities highlightMinis = HighlightSlayerEntities.OFF; + + @SerialEntry + public HighlightSlayerEntities highlightBosses = HighlightSlayerEntities.OFF; + + public enum HighlightSlayerEntities { + OFF, GLOW, HITBOX + } + @SerialEntry public EndermanSlayer endermanSlayer = new EndermanSlayer(); + @SerialEntry + public BlazeSlayer blazeSlayer = new BlazeSlayer(); + @SerialEntry public VampireSlayer vampireSlayer = new VampireSlayer(); @@ -20,6 +33,32 @@ public static class EndermanSlayer { public boolean highlightNukekubiHeads = true; } + public static class BlazeSlayer { + @SerialEntry + public FirePillar firePillarCountdown = FirePillar.SOUND_AND_VISUAL; + + @SerialEntry + public Boolean attunementHighlights = true; + + public enum FirePillar { + OFF("Off"), + VISUAL("Visual Indicator"), + SOUND_AND_VISUAL("Sound and Visual Indicator"); + + private final String description; + + FirePillar(String description) { + this.description = description; + } + + @Override + public String toString() { + return description; + } + } + + } + public static class VampireSlayer { @SerialEntry public boolean enableEffigyWaypoints = true; diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index c0cd8b7ba5..190fc5f940 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -3,16 +3,20 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.SlayersConfig; import de.hysky.skyblocker.skyblock.CompactDamage; import de.hysky.skyblocker.skyblock.FishingHelper; import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; +import de.hysky.skyblocker.skyblock.crimson.slayer.FirePillarAnnouncer; import de.hysky.skyblocker.skyblock.dungeon.DungeonScore; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dwarven.WishingCompassSolver; import de.hysky.skyblocker.skyblock.end.BeaconHighlighter; import de.hysky.skyblocker.skyblock.end.EnderNodes; import de.hysky.skyblocker.skyblock.end.TheEnd; +import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual; import de.hysky.skyblocker.utils.SlayerUtils; import de.hysky.skyblocker.utils.Utils; @@ -109,6 +113,7 @@ public abstract class ClientPlayNetworkHandlerMixin { if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) { DungeonScore.handleEntityDeath(entity); TheEnd.onEntityDeath(entity); + SlayerEntitiesGlow.onEntityDeath(entity); } return entity; } @@ -117,6 +122,13 @@ public abstract class ClientPlayNetworkHandlerMixin { private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { if (!(entity instanceof ArmorStandEntity armorStandEntity)) return; + if (SkyblockerConfigManager.get().slayers.highlightMinis == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerEntitiesGlow.isSlayerMiniMob(armorStandEntity) + || SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerEntitiesGlow.isSlayer(armorStandEntity)) { + SlayerEntitiesGlow.setSlayerMobGlow(armorStandEntity); + } + + if (SkyblockerConfigManager.get().slayers.blazeSlayer.firePillarCountdown != SlayersConfig.BlazeSlayer.FirePillar.OFF) FirePillarAnnouncer.checkFirePillar(entity); + EggFinder.checkIfEgg(armorStandEntity); try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers CompactDamage.compactDamage(armorStandEntity); diff --git a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java index 2959d4b5d1..7126cbade9 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; +import net.minecraft.entity.decoration.ArmorStandEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -42,7 +44,10 @@ public class WorldRendererMixin { boolean shouldShowBoundingBox = MobBoundingBoxes.shouldDrawMobBoundingBox(entity); if (shouldShowBoundingBox) { - MobBoundingBoxes.submitBox2BeRendered(entity.getBoundingBox(), MobBoundingBoxes.getBoxColor(entity)); + MobBoundingBoxes.submitBox2BeRendered( + entity instanceof ArmorStandEntity e ? SlayerEntitiesGlow.getSlayerMobBoundingBox(e) : entity.getBoundingBox(), + MobBoundingBoxes.getBoxColor(entity) + ); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java new file mode 100644 index 0000000000..9c38f77532 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java @@ -0,0 +1,35 @@ +package de.hysky.skyblocker.skyblock.crimson.slayer; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.SlayerUtils; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; + +import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AttunementColours { + private static final Pattern COLOUR_PATTERN = Pattern.compile("ASHEN|SPIRIT|CRYSTAL|AURIC"); + + /** + * Fetches highlight colour based on the Inferno Demonlord, or its demons', Hellion Shield Attunement + */ + public static int getColour(LivingEntity e) { + if (!SkyblockerConfigManager.get().slayers.blazeSlayer.attunementHighlights) return 0xf57738; + for (Entity entity : SlayerUtils.getEntityArmorStands(e)) { + Matcher matcher = COLOUR_PATTERN.matcher(entity.getDisplayName().getString()); + if (matcher.find()) { + String matchedColour = matcher.group(); + return switch (matchedColour) { + case "ASHEN" -> Color.DARK_GRAY.getRGB(); + case "SPIRIT" -> Color.WHITE.getRGB(); + case "CRYSTAL" -> Color.CYAN.getRGB(); + case "AURIC" -> Color.YELLOW.getRGB(); + default -> Color.RED.getRGB(); + }; + } + } + return Color.RED.getRGB(); + } +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java new file mode 100644 index 0000000000..388e66dd23 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java @@ -0,0 +1,60 @@ +package de.hysky.skyblocker.skyblock.crimson.slayer; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.SlayersConfig; +import de.hysky.skyblocker.utils.SlayerUtils; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.title.Title; +import de.hysky.skyblocker.utils.render.title.TitleContainer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.text.MutableText; +import net.minecraft.text.PlainTextContent; +import net.minecraft.util.Formatting; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class FirePillarAnnouncer { + + private static final Pattern FIRE_PILLAR_PATTERN = Pattern.compile("(\\d+)s \\d+ hits"); + + /** + * Checks if an entity is the fire pillar when it has been updated (i.e. name change). This triggers twice on + * seven seconds remaining, so it's been reduced down to only announce the last 5 seconds until explosion. + *

+ * There's also not a great way to detect ownership of the fire pillar, so a crude range calculation is used to try and + * prevent another player's FirePillar appearing on the HUD. + * + * @param entity The updated entity that is checked to be a fire pillar + */ + public static void checkFirePillar(Entity entity) { + if (Utils.isInCrimson() && SlayerUtils.isInSlayer() && entity instanceof ArmorStandEntity) { + + String entityName = entity.getName().getString(); + Matcher matcher = FIRE_PILLAR_PATTERN.matcher(entityName); + + if (matcher.matches()) { + int seconds = Integer.parseInt(matcher.group(1)); + if (seconds > 5) return; + + // There is an edge case where the slayer has entered demon phase and temporarily despawned with + // an active fire pillar in play, So fallback to the player + Entity referenceEntity = SlayerUtils.getSlayerEntity(); + if (!(referenceEntity != null ? referenceEntity : MinecraftClient.getInstance().player).getBlockPos().isWithinDistance(entity.getPos(), 24)) return; + announceFirePillarDetails(entityName); + } + } + } + + private static void announceFirePillarDetails(String entityName) { + Title title = new Title(MutableText.of(new PlainTextContent.Literal(entityName)).formatted(Formatting.BOLD, Formatting.DARK_PURPLE)); + + if (SkyblockerConfigManager.get().slayers.blazeSlayer.firePillarCountdown == SlayersConfig.BlazeSlayer.FirePillar.SOUND_AND_VISUAL) { + RenderHelper.displayInTitleContainerAndPlaySound(title, 15); + } else { + TitleContainer.addTitle(title, 15); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java index f005fc0623..ad2b9b8c0f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java @@ -1,7 +1,9 @@ package de.hysky.skyblocker.skyblock.entity; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.SlayersConfig; import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.FrustumUtils; import de.hysky.skyblocker.utils.render.RenderHelper; @@ -9,6 +11,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.player.PlayerEntity; @@ -40,6 +43,17 @@ public static boolean shouldDrawMobBoundingBox(Entity entity) { }; } + if (SkyblockerConfigManager.get().slayers.highlightMinis == SlayersConfig.HighlightSlayerEntities.HITBOX + && entity instanceof ArmorStandEntity le && SlayerEntitiesGlow.isSlayerMiniMob(le)) { + return true; + } + + if (SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.HITBOX + && entity instanceof ArmorStandEntity le) { + return le.getDisplayName().getString().contains(MinecraftClient.getInstance().getSession().getUsername()) || + entity.getDisplayName().getString().contains("Ⓣ") || entity.getDisplayName().getString().contains("Ⓐ"); + } + return false; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 22474cf8be..7c980a04aa 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -4,18 +4,20 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; +import de.hysky.skyblocker.skyblock.crimson.slayer.AttunementColours; import de.hysky.skyblocker.skyblock.dungeon.LividColor; import de.hysky.skyblocker.skyblock.end.TheEnd; +import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.SlayerUtils; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.entity.mob.EndermanEntity; -import net.minecraft.entity.mob.MagmaCubeEntity; -import net.minecraft.entity.mob.ZombieEntity; +import net.minecraft.entity.mob.*; import net.minecraft.entity.passive.BatEntity; +import net.minecraft.entity.passive.WolfEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.util.Formatting; @@ -23,60 +25,121 @@ import net.minecraft.world.World; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; public class MobGlow { + /** * The Nukekubi head texture id is eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3. */ public static final String NUKEKUBI_HEAD_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0="; + private static final long GLOW_CACHE_DURATION = 50; + private static final long PLAYER_CAN_SEE_CACHE_DURATION = 100; + private static final ConcurrentHashMap glowCache = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap canSeeCache = new ConcurrentHashMap<>(); - public static boolean shouldMobGlow(Entity entity) { - Box box = entity.getBoundingBox(); - - if (OcclusionCulling.getReducedCuller().isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { - String name = entity.getName().getString(); - + public static void init() { + Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 100*20); + } - // Dungeons - if (Utils.isInDungeons() && !entity.isInvisible()) { - return switch (entity) { - // Minibosses - case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> SkyblockerConfigManager.get().dungeons.starredMobGlow; - case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> LividColor.shouldGlow(name); + public static boolean shouldMobGlow(Entity entity) { + if (entity.isInvisible()) return false; - // Bats - case BatEntity b -> SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes; + long currentTime = System.currentTimeMillis(); - // Armor Stands - case ArmorStandEntity _armorStand -> false; + boolean shouldGlow; + CacheEntry cachedGlow = glowCache.get(entity); + if (cachedGlow == null || (currentTime - cachedGlow.timestamp) > GLOW_CACHE_DURATION) { + shouldGlow = computeShouldMobGlow(entity); + glowCache.put(entity, new CacheEntry(shouldGlow, currentTime)); + } else { + shouldGlow = cachedGlow.value; + } - // Regular Mobs - default -> SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity); - }; - } + if (shouldGlow) { + return playerCanSee(entity, currentTime); + } - return switch (entity) { - // Rift - case PlayerEntity p when Utils.isInTheRift() && !entity.isInvisible() && name.equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow; + return false; + } - // Enderman Slayer - // Highlights Nukekubi Heads - case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; + /** + * Checks if the player can see the entity. + * Has "True sight" within an small aura, but since name tags exist I think this is fine... + */ + private static boolean playerCanSee(Entity entity, long currentTime) { - // Special Zelot - case EndermanEntity enderman when Utils.isInTheEnd() && !entity.isInvisible() -> TheEnd.isSpecialZealot(enderman); + CacheEntry canSee = canSeeCache.get(entity); + if (canSee == null || (currentTime - canSee.timestamp) > PLAYER_CAN_SEE_CACHE_DURATION) { + boolean playerCanSee = entity.distanceTo(MinecraftClient.getInstance().player) <= 15 || MinecraftClient.getInstance().player.canSee(entity); + canSeeCache.put(entity, new CacheEntry(playerCanSee, currentTime)); + return playerCanSee; + } - //dojo - case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> DojoManager.shouldGlow(getArmorStandName(zombie)); + return canSee.value; + } - //Kuudra - case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE; + private static boolean computeShouldMobGlow(Entity entity) { + String name = entity.getName().getString(); - default -> false; + // Dungeons + if (Utils.isInDungeons() && !entity.isInvisible()) { + return switch (entity) { + // Minibosses + case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> + SkyblockerConfigManager.get().dungeons.starredMobGlow; + case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> + LividColor.shouldGlow(name); + // Bats + case BatEntity b -> + SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes; + + // Armor Stands + case ArmorStandEntity _armorStand -> false; + + // Regular Mobs + default -> SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity); }; } - return false; + return switch (entity) { + + // Rift Blobbercyst + case PlayerEntity p when Utils.isInTheRift() && !entity.isInvisible() && name.equals("Blobbercyst ") -> + SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow; + + // Dojo Helpers + case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> + DojoManager.shouldGlow(getArmorStandName(zombie)); + + //Kuudra + case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> + SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE; + + // Special Zealot && Slayer (Mini)Boss + case EndermanEntity enderman when Utils.isInTheEnd() && !entity.isInvisible() -> + TheEnd.isSpecialZealot(enderman) || SlayerEntitiesGlow.shouldGlow(enderman.getUuid()); + case ZombieEntity zombie when !(zombie instanceof ZombifiedPiglinEntity) && SlayerUtils.isInSlayerQuestType(SlayerUtils.REVENANT) -> + SlayerEntitiesGlow.shouldGlow(zombie.getUuid()); + case SpiderEntity spider when SlayerUtils.isInSlayerQuestType(SlayerUtils.TARA) -> + SlayerEntitiesGlow.shouldGlow(spider.getUuid()); + case WolfEntity wolf when SlayerUtils.isInSlayerQuestType(SlayerUtils.SVEN) -> + SlayerEntitiesGlow.shouldGlow(wolf.getUuid()); + case BlazeEntity blaze when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> + SlayerEntitiesGlow.shouldGlow(blaze.getUuid()); + + // Enderman Slayer's Nukekubi Skulls + case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> + SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; + + // Blaze Slayer's Demonic minions + case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses.toString().equals("GLOW") -> + SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 10; + case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses.toString().equals("GLOW") -> + SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 10; + + default -> false; + }; } /** @@ -123,10 +186,16 @@ public static int getGlowColor(Entity entity) { case PlayerEntity p when name.equals("Blobbercyst ") -> Formatting.GREEN.getColorValue(); case EndermanEntity enderman when TheEnd.isSpecialZealot(enderman) -> Formatting.RED.getColorValue(); - case ArmorStandEntity armorStand when isNukekubiHead(armorStand) -> Formatting.GREEN.getColorValue(); + case ArmorStandEntity armorStand when isNukekubiHead(armorStand) -> 0x990099; case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> DojoManager.getColor(); case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> 0xf7510f; + // Blaze Slayer Attunement Colours + case ArmorStandEntity armorStand when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> AttunementColours.getColour(armorStand); + case BlazeEntity blaze when SlayerUtils.isInSlayer() -> AttunementColours.getColour(blaze); + case ZombifiedPiglinEntity piglin when SlayerUtils.isInSlayer() -> AttunementColours.getColour(piglin); + case WitherSkeletonEntity wSkelly when SlayerUtils.isInSlayer() -> AttunementColours.getColour(wSkelly); + default -> 0xf57738; }; } @@ -137,4 +206,11 @@ public static int getGlowColor(Entity entity) { private static boolean isNukekubiHead(ArmorStandEntity entity) { return Streams.stream(entity.getArmorItems()).map(ItemUtils::getHeadTexture).anyMatch(headTexture -> headTexture.contains(NUKEKUBI_HEAD_TEXTURE)); } -} + + private record CacheEntry(boolean value, long timestamp){}; + + private static void clearCache() { + canSeeCache.clear(); + glowCache.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java new file mode 100644 index 0000000000..540608296c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java @@ -0,0 +1,119 @@ +package de.hysky.skyblocker.skyblock.slayers; + +import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.utils.Location; +import de.hysky.skyblocker.utils.SlayerUtils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.mob.*; +import net.minecraft.entity.passive.WolfEntity; +import net.minecraft.util.math.Box; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class SlayerEntitiesGlow { + private static final Map SLAYER_MINI_NAMES = Map.ofEntries( + Map.entry("Revenant Sycophant", SlayerUtils.REVENANT), + Map.entry("Revenant Champion", SlayerUtils.REVENANT), + Map.entry("Deformed Revenant", SlayerUtils.REVENANT), + Map.entry("Atoned Champion", SlayerUtils.REVENANT), + Map.entry("Atoned Revenant", SlayerUtils.REVENANT), + Map.entry("Tarantula Vermin", SlayerUtils.TARA), + Map.entry("Tarantula Beast", SlayerUtils.TARA), + Map.entry("Mutant Tarantula", SlayerUtils.TARA), + Map.entry("Pack Enforcer", SlayerUtils.SVEN), + Map.entry("Sven Follower", SlayerUtils.SVEN), + Map.entry("Sven Alpha", SlayerUtils.SVEN), + Map.entry("Voidling Devotee", SlayerUtils.VOIDGLOOM), + Map.entry("Voidling Radical", SlayerUtils.VOIDGLOOM), + Map.entry("Voidcrazed Maniac", SlayerUtils.VOIDGLOOM), + Map.entry("Flare Demon", SlayerUtils.DEMONLORD), + Map.entry("Kindleheart Demon", SlayerUtils.DEMONLORD), + Map.entry("Burningsoul Demon", SlayerUtils.DEMONLORD) + ); + + private static final Map> SLAYER_MOB_TYPE = Map.of( + SlayerUtils.REVENANT, ZombieEntity.class, + SlayerUtils.TARA, SpiderEntity.class, + SlayerUtils.SVEN, WolfEntity.class, + SlayerUtils.VOIDGLOOM, EndermanEntity.class, + SlayerUtils.DEMONLORD, BlazeEntity.class + ); + + private static final Set MOBS_TO_GLOW = new HashSet<>(); + + public static boolean shouldGlow(UUID entityUUID) { + return MOBS_TO_GLOW.contains(entityUUID); + } + + public static boolean isSlayer(LivingEntity e) { + return SlayerUtils.isInSlayer() && SlayerUtils.getEntityArmorStands(e).stream().anyMatch(entity -> entity.getDisplayName().getString().contains(MinecraftClient.getInstance().getSession().getUsername())); + } + + public static boolean isSlayerMiniMob(LivingEntity entity) { + if (entity.getCustomName() == null) return false; + String entityName = entity.getCustomName().getString(); + return SLAYER_MINI_NAMES.keySet().stream().anyMatch(slayerMobName -> entityName.contains(slayerMobName) && SlayerUtils.isInSlayerQuestType(SLAYER_MINI_NAMES.get(slayerMobName))); + } + + public static Box getSlayerMobBoundingBox(LivingEntity entity) { + return switch (SlayerUtils.getSlayerType()) { + case SlayerUtils.REVENANT -> + new Box(entity.getX() - 0.4, entity.getY() - 0.1, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 2.2, entity.getZ() + 0.4); + case SlayerUtils.TARA -> + new Box(entity.getX() - 0.9, entity.getY() - 0.2, entity.getZ() - 0.9, entity.getX() + 0.9, entity.getY() - 1.2, entity.getZ() + 0.9); + case SlayerUtils.VOIDGLOOM -> + new Box(entity.getX() - 0.4, entity.getY() - 0.2, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 3, entity.getZ() + 0.4); + case SlayerUtils.SVEN -> + new Box(entity.getX() - 0.5, entity.getY() - 0.1, entity.getZ() - 0.5, entity.getX() + 0.5, entity.getY() - 1, entity.getZ() + 0.5); + default -> + new Box(entity.getX() - 0.5, entity.getY() + 0.1, entity.getZ() - 0.5, entity.getX() + 0.5, entity.getY() - 2.2, entity.getZ() + 0.5); + }; + } + + /** + *

Finds the closest matching MobEntity for the armorStand using entityClass and armorStand age difference to filter + * out impossible candidates, returning the closest mob of those remaining in the search box by block distance

+ * + * @param entityClass the mob type of the Slayer (i.e. ZombieEntity.class) + * @param armorStand the entity that contains the display name of the Slayer (mini)boss + */ + private static MobEntity findClosestMobEntity(Class entityClass, ArmorStandEntity armorStand) { + return armorStand.getWorld().getEntitiesByClass(entityClass, armorStand.getDimensions(null) + .getBoxAt(armorStand.getPos()).expand(1.5), entity -> + !entity.isDead() && entity.age > armorStand.age - 4 && entity.age < armorStand.age + 4) + .stream() + .filter(entity -> !(entity instanceof CaveSpiderEntity)) // CaveSpider extends Spider so filter out mob for BroodFather highlight + .min(Comparator.comparingDouble((MobEntity e) -> e.distanceTo(armorStand))) + .orElse(null); + } + + /** + *

Adds the Entity UUID to the Hashset of Slayer Mobs to glow

+ * + * @param armorStand the entity that contains the display name of the Slayer (mini)boss + */ + public static void setSlayerMobGlow(ArmorStandEntity armorStand) { + String slayerType = SlayerUtils.getSlayerType(); + Class entityClass = SLAYER_MOB_TYPE.get(slayerType); + if (entityClass != null) { + MobEntity closestEntity = findClosestMobEntity(entityClass, armorStand); + if (closestEntity != null) MOBS_TO_GLOW.add(closestEntity.getUuid()); + } + } + + public static void onEntityDeath(@Nullable Entity entity) { + if (entity != null && entity.getUuid() != null) MOBS_TO_GLOW.remove(entity.getUuid()); + } + + private static void clearGlow(Location location) { + MOBS_TO_GLOW.clear(); + } + + public static void init() { + SkyblockEvents.LOCATION_CHANGE.register(SlayerEntitiesGlow::clearGlow); + } +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java index 2edd61f178..eb07dec9d8 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java @@ -7,10 +7,19 @@ import org.slf4j.LoggerFactory; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; //TODO Slayer Packet system that can provide information about the current slayer boss, abstract so that different bosses can have different info public class SlayerUtils { + public static final String REVENANT = "Revenant Horror"; + public static final String TARA = "Tarantula Broodfather"; + public static final String SVEN = "Sven Packmaster"; + public static final String VOIDGLOOM = "Voidgloom Seraph"; + public static final String VAMPIRE = "Riftstalker Bloodfiend"; + public static final String DEMONLORD = "Inferno Demonlord"; private static final Logger LOGGER = LoggerFactory.getLogger(SlayerUtils.class); + private static final Pattern SLAYER_PATTERN = Pattern.compile("Revenant Horror|Tarantula Broodfather|Sven Packmaster|Voidgloom Seraph|Inferno Demonlord|Riftstalker Bloodfiend"); //TODO: Cache this, probably included in Packet system public static List getEntityArmorStands(Entity entity) { @@ -21,15 +30,15 @@ public static List getEntityArmorStands(Entity entity) { public static Entity getSlayerEntity() { if (MinecraftClient.getInstance().world != null) { for (Entity entity : MinecraftClient.getInstance().world.getEntities()) { - //Check if entity is Bloodfiend - if (entity.hasCustomName() && entity.getCustomName().getString().contains("Bloodfiend")) { - //Grab the players username - String username = MinecraftClient.getInstance().getSession().getUsername(); - //Check all armor stands around the boss - for (Entity armorStand : getEntityArmorStands(entity)) { - //Check if the display name contains the players username - if (armorStand.getDisplayName().getString().contains(username)) { - return entity; + if (entity.hasCustomName()) { + String entityName = entity.getCustomName().getString(); + Matcher matcher = SLAYER_PATTERN.matcher(entityName); + if (matcher.find()) { + String username = MinecraftClient.getInstance().getSession().getUsername(); + for (Entity armorStand : getEntityArmorStands(entity)) { + if (armorStand.getDisplayName().getString().contains(username)) { + return entity; + } } } } @@ -40,15 +49,39 @@ public static Entity getSlayerEntity() { public static boolean isInSlayer() { try { - for (int i = 0; i < Utils.STRING_SCOREBOARD.size(); i++) { - String line = Utils.STRING_SCOREBOARD.get(i); - + for (String line : Utils.STRING_SCOREBOARD) { if (line.contains("Slay the boss!")) return true; } } catch (NullPointerException e) { LOGGER.error("[Skyblocker] Error while checking if player is in slayer", e); } + return false; + } + public static boolean isInSlayerQuestType(String slayer) { + try { + boolean quest = false; + boolean type = false; + for (String line : Utils.STRING_SCOREBOARD) { + if (line.contains("Slayer Quest")) quest = true; + if (line.contains(slayer)) type = true; + if (quest && type) return true; + } + } catch (NullPointerException e) { + LOGGER.error("[Skyblocker] Error while checking if player is in slayer quest type", e); + } return false; } + + public static String getSlayerType() { + try { + for (String line : Utils.STRING_SCOREBOARD) { + Matcher matcher = SLAYER_PATTERN.matcher(line); + if (matcher.find()) return matcher.group(); + } + } catch (NullPointerException | IndexOutOfBoundsException e) { + LOGGER.error("[Skyblocker] Error while checking slayer type", e); + } + return ""; + } } \ No newline at end of file diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 72b8946402..5e4c44621c 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -197,7 +197,7 @@ "skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip": "Draws the bounding boxes of starred mobs.", "skyblocker.config.dungeons.starredMobGlow": "Starred Mob Glow", - "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nWARNING: This feature is experimental and you may encounter issues with it.", + "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nWARNING: This feature utilises ray casting on a lot of entities which may have an impact on performance.", "skyblocker.config.dungeons.terminals": "Terminal Solvers (F7/M7)", "skyblocker.config.dungeons.terminals.blockIncorrectClicks": "Block Incorrect Clicks", @@ -600,11 +600,28 @@ "skyblocker.config.slayer": "Slayers", + "skyblocker.config.slayer.blazeSlayer": "Blaze Slayer", + "skyblocker.config.slayer.blazeSlayer.enableFirePillarAnnouncer" : "Fire Pillar Countdown Notifications", + "skyblocker.config.slayer.blazeSlayer.enableFirePillarAnnouncer.@Tooltip": "Countdowns the last five seconds before the Fire Pillar explodes. Configure 'Title Container' to customise the location on the HUD (Note: This only uses a rudimentary distance check, so the Pillar may be spawned by another player's slayer)", + "skyblocker.config.slayer.blazeSlayer.attunementHighlights" : "Attunement Highlights", + "skyblocker.config.slayer.blazeSlayer.attunementHighlights.@Tooltip": "If Boss Highlighting is on, applies a color matching the current attunement to the selected effect.", + "skyblocker.config.slayer.endermanSlayer": "Enderman Slayer", "skyblocker.config.slayer.endermanSlayer.enableYangGlyphsNotification": "Enable Yang Glyphs notification", "skyblocker.config.slayer.endermanSlayer.highlightBeacons": "Beacon Highlighting", "skyblocker.config.slayer.endermanSlayer.highlightNukekubiHeads": "Nukekubi Head Highlighting", + "skyblocker.config.slayer.highlightMinis": "Highlight Minibosses", + "skyblocker.config.slayer.highlightMinis.@Tooltip[0]": "\nOFF: Do not highlight Slayer Minibosses.", + "skyblocker.config.slayer.highlightMinis.@Tooltip[1]": "\nGLOW: Creates a glow effect on Slayer Minibosses. Due to technical limitations, there is a small chance of this option making mistakes in mob detection", + "skyblocker.config.slayer.highlightMinis.@Tooltip[2]": "\nHITBOX: Display a Hitbox around Slayer Minibosses", + + "skyblocker.config.slayer.highlightBosses": "Highlight Bosses", + "skyblocker.config.slayer.highlightBosses.@Tooltip[0]": "\nOFF: Do not highlight Slayer Bosses.", + "skyblocker.config.slayer.highlightBosses.@Tooltip[1]": "\nGLOW: Creates a glow effect on Slayer Bosses. Due to technical limitations, there is a small chance of this option making mistakes in mob detection", + "skyblocker.config.slayer.highlightBosses.@Tooltip[2]": "\nHITBOX: Display a Hitbox around the Slayer Boss", + "skyblocker.config.slayer.highlightBosses.@Tooltip[3]": "This option is required for Blazeslayer Attunement Highlighting", + "skyblocker.config.slayer.vampireSlayer": "Vampire Slayer", "skyblocker.config.slayer.vampireSlayer.compactEffigyWaypoints": "Compact Effigy Waypoints", "skyblocker.config.slayer.vampireSlayer.effigyUpdateFrequency": "Effigy Waypoints Update Frequency (Ticks)", From fb398d98ea1084ebb4248877701bf50ca8abfeb2 Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sat, 3 Aug 2024 20:43:26 +0100 Subject: [PATCH 2/9] simplify a little --- .../skyblocker/skyblock/entity/MobGlow.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 7c980a04aa..83519c327a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -47,22 +47,17 @@ public static boolean shouldMobGlow(Entity entity) { long currentTime = System.currentTimeMillis(); - boolean shouldGlow; CacheEntry cachedGlow = glowCache.get(entity); if (cachedGlow == null || (currentTime - cachedGlow.timestamp) > GLOW_CACHE_DURATION) { - shouldGlow = computeShouldMobGlow(entity); + boolean shouldGlow = computeShouldMobGlow(entity); glowCache.put(entity, new CacheEntry(shouldGlow, currentTime)); - } else { - shouldGlow = cachedGlow.value; + cachedGlow = glowCache.get(entity); } - if (shouldGlow) { - return playerCanSee(entity, currentTime); - } - - return false; + return cachedGlow.value && playerCanSee(entity, currentTime); } + /** * Checks if the player can see the entity. * Has "True sight" within an small aura, but since name tags exist I think this is fine... @@ -83,7 +78,7 @@ private static boolean computeShouldMobGlow(Entity entity) { String name = entity.getName().getString(); // Dungeons - if (Utils.isInDungeons() && !entity.isInvisible()) { + if (Utils.isInDungeons()) { return switch (entity) { // Minibosses case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> @@ -105,7 +100,7 @@ private static boolean computeShouldMobGlow(Entity entity) { return switch (entity) { // Rift Blobbercyst - case PlayerEntity p when Utils.isInTheRift() && !entity.isInvisible() && name.equals("Blobbercyst ") -> + case PlayerEntity p when Utils.isInTheRift() && name.equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow; // Dojo Helpers @@ -117,7 +112,7 @@ private static boolean computeShouldMobGlow(Entity entity) { SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE; // Special Zealot && Slayer (Mini)Boss - case EndermanEntity enderman when Utils.isInTheEnd() && !entity.isInvisible() -> + case EndermanEntity enderman when Utils.isInTheEnd() -> TheEnd.isSpecialZealot(enderman) || SlayerEntitiesGlow.shouldGlow(enderman.getUuid()); case ZombieEntity zombie when !(zombie instanceof ZombifiedPiglinEntity) && SlayerUtils.isInSlayerQuestType(SlayerUtils.REVENANT) -> SlayerEntitiesGlow.shouldGlow(zombie.getUuid()); From d167b8671da767da2335aa4eebd5335a8a790acb Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sun, 4 Aug 2024 15:04:17 +0100 Subject: [PATCH 3/9] refine detection --- .../skyblock/slayers/SlayerEntitiesGlow.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java index 540608296c..0ba3223d19 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java @@ -35,6 +35,9 @@ public class SlayerEntitiesGlow { Map.entry("Burningsoul Demon", SlayerUtils.DEMONLORD) ); + public static void init() { + SkyblockEvents.LOCATION_CHANGE.register(SlayerEntitiesGlow::clearGlow); + } private static final Map> SLAYER_MOB_TYPE = Map.of( SlayerUtils.REVENANT, ZombieEntity.class, SlayerUtils.TARA, SpiderEntity.class, @@ -50,13 +53,15 @@ public static boolean shouldGlow(UUID entityUUID) { } public static boolean isSlayer(LivingEntity e) { - return SlayerUtils.isInSlayer() && SlayerUtils.getEntityArmorStands(e).stream().anyMatch(entity -> entity.getDisplayName().getString().contains(MinecraftClient.getInstance().getSession().getUsername())); + return SlayerUtils.isInSlayer() && SlayerUtils.getEntityArmorStands(e).stream().anyMatch(entity -> + entity.getDisplayName().getString().contains(MinecraftClient.getInstance().getSession().getUsername())); } public static boolean isSlayerMiniMob(LivingEntity entity) { if (entity.getCustomName() == null) return false; String entityName = entity.getCustomName().getString(); - return SLAYER_MINI_NAMES.keySet().stream().anyMatch(slayerMobName -> entityName.contains(slayerMobName) && SlayerUtils.isInSlayerQuestType(SLAYER_MINI_NAMES.get(slayerMobName))); + return SLAYER_MINI_NAMES.keySet().stream().anyMatch(slayerMobName -> + entityName.contains(slayerMobName) && SlayerUtils.isInSlayerQuestType(SLAYER_MINI_NAMES.get(slayerMobName))); } public static Box getSlayerMobBoundingBox(LivingEntity entity) { @@ -86,11 +91,20 @@ private static MobEntity findClosestMobEntity(Class entityC .getBoxAt(armorStand.getPos()).expand(1.5), entity -> !entity.isDead() && entity.age > armorStand.age - 4 && entity.age < armorStand.age + 4) .stream() - .filter(entity -> !(entity instanceof CaveSpiderEntity)) // CaveSpider extends Spider so filter out mob for BroodFather highlight + .filter(entity -> !(entity instanceof CaveSpiderEntity)) + .filter(SlayerEntitiesGlow::isValidSlayerMob) .min(Comparator.comparingDouble((MobEntity e) -> e.distanceTo(armorStand))) .orElse(null); } + /** + * Use this func to add checks to prevent accidental highlights + * i.e. Cavespider extends spider and thus will highlight the broodfather's head pet instead and + */ + private static boolean isValidSlayerMob(MobEntity entity) { + return !(entity instanceof CaveSpiderEntity) && !(entity.isBaby()); + } + /** *

Adds the Entity UUID to the Hashset of Slayer Mobs to glow

* @@ -113,7 +127,4 @@ private static void clearGlow(Location location) { MOBS_TO_GLOW.clear(); } - public static void init() { - SkyblockEvents.LOCATION_CHANGE.register(SlayerEntitiesGlow::clearGlow); - } } \ No newline at end of file From a087b150caa15b2401717c802720332818a5245e Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sun, 4 Aug 2024 21:28:53 +0100 Subject: [PATCH 4/9] small distance tweaks --- .../crimson/slayer/FirePillarAnnouncer.java | 2 +- .../skyblocker/skyblock/entity/MobGlow.java | 13 +++++++------ .../hysky/skyblocker/utils/SlayerUtils.java | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java index 388e66dd23..534d7a2f30 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java @@ -42,7 +42,7 @@ public static void checkFirePillar(Entity entity) { // There is an edge case where the slayer has entered demon phase and temporarily despawned with // an active fire pillar in play, So fallback to the player Entity referenceEntity = SlayerUtils.getSlayerEntity(); - if (!(referenceEntity != null ? referenceEntity : MinecraftClient.getInstance().player).getBlockPos().isWithinDistance(entity.getPos(), 24)) return; + if (!(referenceEntity != null ? referenceEntity : MinecraftClient.getInstance().player).getBlockPos().isWithinDistance(entity.getPos(), 22)) return; announceFirePillarDetails(entityName); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 83519c327a..734fc8214b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -2,6 +2,7 @@ import com.google.common.collect.Streams; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.SlayersConfig; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.crimson.slayer.AttunementColours; @@ -60,13 +61,13 @@ public static boolean shouldMobGlow(Entity entity) { /** * Checks if the player can see the entity. - * Has "True sight" within an small aura, but since name tags exist I think this is fine... + * Has "True sight" within a certain aura, but since name tags exist I think this is fine... */ private static boolean playerCanSee(Entity entity, long currentTime) { CacheEntry canSee = canSeeCache.get(entity); if (canSee == null || (currentTime - canSee.timestamp) > PLAYER_CAN_SEE_CACHE_DURATION) { - boolean playerCanSee = entity.distanceTo(MinecraftClient.getInstance().player) <= 15 || MinecraftClient.getInstance().player.canSee(entity); + boolean playerCanSee = entity.distanceTo(MinecraftClient.getInstance().player) <= 20 || MinecraftClient.getInstance().player.canSee(entity); canSeeCache.put(entity, new CacheEntry(playerCanSee, currentTime)); return playerCanSee; } @@ -128,10 +129,10 @@ private static boolean computeShouldMobGlow(Entity entity) { SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; // Blaze Slayer's Demonic minions - case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses.toString().equals("GLOW") -> - SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 10; - case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses.toString().equals("GLOW") -> - SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 10; + case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> + SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; + case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> + SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; default -> false; }; diff --git a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java index eb07dec9d8..363de85a8f 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java @@ -58,6 +58,25 @@ public static boolean isInSlayer() { return false; } + public static boolean isInSlayerType(String slayer) { + try { + boolean inFight = false; + boolean type = false; + for (String line : Utils.STRING_SCOREBOARD) { + switch (line) { + case String a when a.contains("Slayer Quest") -> { return false; } + case String b when b.contains("Slay the boss!") -> inFight = true; + case String c when c.contains(slayer) -> type = true; + default -> { continue; } + } + if (inFight && type) return true; + } + } catch (NullPointerException e) { + LOGGER.error("[Skyblocker] Error while checking if player is in slayer", e); + } + return false; + } + public static boolean isInSlayerQuestType(String slayer) { try { boolean quest = false; From c4a83d81c16dc1ee9f4d643b178842355d7903cf Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Wed, 7 Aug 2024 20:03:09 +0100 Subject: [PATCH 5/9] remove semicolon --- src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 734fc8214b..174f32605b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -203,7 +203,7 @@ private static boolean isNukekubiHead(ArmorStandEntity entity) { return Streams.stream(entity.getArmorItems()).map(ItemUtils::getHeadTexture).anyMatch(headTexture -> headTexture.contains(NUKEKUBI_HEAD_TEXTURE)); } - private record CacheEntry(boolean value, long timestamp){}; + private record CacheEntry(boolean value, long timestamp){} private static void clearCache() { canSeeCache.clear(); From afd61e061d6e4b0cfe0c0cd5594e77fbbf14a9a1 Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sun, 11 Aug 2024 14:22:51 +0100 Subject: [PATCH 6/9] pr feedback --- .../config/configs/SlayersConfig.java | 51 +++++++------- ...mentColours.java => AttunementColors.java} | 8 +-- .../crimson/slayer/FirePillarAnnouncer.java | 3 +- .../skyblocker/skyblock/entity/MobGlow.java | 67 +++++++++---------- .../skyblock/slayers/SlayerEntitiesGlow.java | 24 +++---- .../assets/skyblocker/lang/en_us.json | 5 +- 6 files changed, 72 insertions(+), 86 deletions(-) rename src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/{AttunementColours.java => AttunementColors.java} (80%) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java index 522c5b5275..8586636096 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java @@ -33,32 +33,6 @@ public static class EndermanSlayer { public boolean highlightNukekubiHeads = true; } - public static class BlazeSlayer { - @SerialEntry - public FirePillar firePillarCountdown = FirePillar.SOUND_AND_VISUAL; - - @SerialEntry - public Boolean attunementHighlights = true; - - public enum FirePillar { - OFF("Off"), - VISUAL("Visual Indicator"), - SOUND_AND_VISUAL("Sound and Visual Indicator"); - - private final String description; - - FirePillar(String description) { - this.description = description; - } - - @Override - public String toString() { - return description; - } - } - - } - public static class VampireSlayer { @SerialEntry public boolean enableEffigyWaypoints = true; @@ -96,4 +70,29 @@ public static class VampireSlayer { @SerialEntry public int maniaUpdateFrequency = 5; } + + public static class BlazeSlayer { + @SerialEntry + public FirePillar firePillarCountdown = FirePillar.SOUND_AND_VISUAL; + + @SerialEntry + public Boolean attunementHighlights = true; + + public enum FirePillar { + OFF("Off"), + VISUAL("Visual Indicator"), + SOUND_AND_VISUAL("Sound and Visual Indicator"); + + private final String description; + + FirePillar(String description) { + this.description = description; + } + + @Override + public String toString() { + return description; + } + } + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java similarity index 80% rename from src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java rename to src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java index 9c38f77532..ba94812a2a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColours.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java @@ -9,16 +9,16 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class AttunementColours { - private static final Pattern COLOUR_PATTERN = Pattern.compile("ASHEN|SPIRIT|CRYSTAL|AURIC"); +public class AttunementColors { + private static final Pattern COLOR_PATTERN = Pattern.compile("ASHEN|SPIRIT|CRYSTAL|AURIC"); /** * Fetches highlight colour based on the Inferno Demonlord, or its demons', Hellion Shield Attunement */ - public static int getColour(LivingEntity e) { + public static int getColor(LivingEntity e) { if (!SkyblockerConfigManager.get().slayers.blazeSlayer.attunementHighlights) return 0xf57738; for (Entity entity : SlayerUtils.getEntityArmorStands(e)) { - Matcher matcher = COLOUR_PATTERN.matcher(entity.getDisplayName().getString()); + Matcher matcher = COLOR_PATTERN.matcher(entity.getDisplayName().getString()); if (matcher.find()) { String matchedColour = matcher.group(); return switch (matchedColour) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java index 534d7a2f30..d232809674 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java @@ -12,6 +12,7 @@ import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.text.MutableText; import net.minecraft.text.PlainTextContent; +import net.minecraft.text.Text; import net.minecraft.util.Formatting; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,7 +50,7 @@ public static void checkFirePillar(Entity entity) { } private static void announceFirePillarDetails(String entityName) { - Title title = new Title(MutableText.of(new PlainTextContent.Literal(entityName)).formatted(Formatting.BOLD, Formatting.DARK_PURPLE)); + Title title = new Title(Text.literal(entityName).formatted(Formatting.BOLD, Formatting.DARK_PURPLE)); if (SkyblockerConfigManager.get().slayers.blazeSlayer.firePillarCountdown == SlayersConfig.BlazeSlayer.FirePillar.SOUND_AND_VISUAL) { RenderHelper.displayInTitleContainerAndPlaySound(title, 15); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 174f32605b..3a5b025bfe 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -5,7 +5,7 @@ import de.hysky.skyblocker.config.configs.SlayersConfig; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; -import de.hysky.skyblocker.skyblock.crimson.slayer.AttunementColours; +import de.hysky.skyblocker.skyblock.crimson.slayer.AttunementColors; import de.hysky.skyblocker.skyblock.dungeon.LividColor; import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow; @@ -40,11 +40,10 @@ public class MobGlow { private static final ConcurrentHashMap canSeeCache = new ConcurrentHashMap<>(); public static void init() { - Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 100*20); + Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 300*20); } public static boolean shouldMobGlow(Entity entity) { - if (entity.isInvisible()) return false; long currentTime = System.currentTimeMillis(); @@ -76,19 +75,27 @@ private static boolean playerCanSee(Entity entity, long currentTime) { } private static boolean computeShouldMobGlow(Entity entity) { + + if (entity.isInvisible()) { + return switch (entity) { + case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> + SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; + default -> false; + }; + } + String name = entity.getName().getString(); // Dungeons if (Utils.isInDungeons()) { return switch (entity) { + // Minibosses - case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> - SkyblockerConfigManager.get().dungeons.starredMobGlow; - case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> - LividColor.shouldGlow(name); + case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> SkyblockerConfigManager.get().dungeons.starredMobGlow; + case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> LividColor.shouldGlow(name); + // Bats - case BatEntity b -> - SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes; + case BatEntity b -> SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes; // Armor Stands case ArmorStandEntity _armorStand -> false; @@ -101,38 +108,24 @@ private static boolean computeShouldMobGlow(Entity entity) { return switch (entity) { // Rift Blobbercyst - case PlayerEntity p when Utils.isInTheRift() && name.equals("Blobbercyst ") -> - SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow; + case PlayerEntity p when Utils.isInTheRift() && name.equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow; // Dojo Helpers - case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> - DojoManager.shouldGlow(getArmorStandName(zombie)); + case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> DojoManager.shouldGlow(getArmorStandName(zombie)); //Kuudra - case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> - SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE; + case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE; // Special Zealot && Slayer (Mini)Boss - case EndermanEntity enderman when Utils.isInTheEnd() -> - TheEnd.isSpecialZealot(enderman) || SlayerEntitiesGlow.shouldGlow(enderman.getUuid()); - case ZombieEntity zombie when !(zombie instanceof ZombifiedPiglinEntity) && SlayerUtils.isInSlayerQuestType(SlayerUtils.REVENANT) -> - SlayerEntitiesGlow.shouldGlow(zombie.getUuid()); - case SpiderEntity spider when SlayerUtils.isInSlayerQuestType(SlayerUtils.TARA) -> - SlayerEntitiesGlow.shouldGlow(spider.getUuid()); - case WolfEntity wolf when SlayerUtils.isInSlayerQuestType(SlayerUtils.SVEN) -> - SlayerEntitiesGlow.shouldGlow(wolf.getUuid()); - case BlazeEntity blaze when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> - SlayerEntitiesGlow.shouldGlow(blaze.getUuid()); - - // Enderman Slayer's Nukekubi Skulls - case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> - SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; + case EndermanEntity enderman when Utils.isInTheEnd() -> TheEnd.isSpecialZealot(enderman) || SlayerEntitiesGlow.shouldGlow(enderman.getUuid()); + case ZombieEntity zombie when !(zombie instanceof ZombifiedPiglinEntity) && SlayerUtils.isInSlayerQuestType(SlayerUtils.REVENANT) -> SlayerEntitiesGlow.shouldGlow(zombie.getUuid()); + case SpiderEntity spider when SlayerUtils.isInSlayerQuestType(SlayerUtils.TARA) -> SlayerEntitiesGlow.shouldGlow(spider.getUuid()); + case WolfEntity wolf when SlayerUtils.isInSlayerQuestType(SlayerUtils.SVEN) -> SlayerEntitiesGlow.shouldGlow(wolf.getUuid()); + case BlazeEntity blaze when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> SlayerEntitiesGlow.shouldGlow(blaze.getUuid()); // Blaze Slayer's Demonic minions - case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> - SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; - case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> - SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; + case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; + case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; default -> false; }; @@ -187,10 +180,10 @@ public static int getGlowColor(Entity entity) { case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> 0xf7510f; // Blaze Slayer Attunement Colours - case ArmorStandEntity armorStand when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> AttunementColours.getColour(armorStand); - case BlazeEntity blaze when SlayerUtils.isInSlayer() -> AttunementColours.getColour(blaze); - case ZombifiedPiglinEntity piglin when SlayerUtils.isInSlayer() -> AttunementColours.getColour(piglin); - case WitherSkeletonEntity wSkelly when SlayerUtils.isInSlayer() -> AttunementColours.getColour(wSkelly); + case ArmorStandEntity armorStand when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> AttunementColors.getColor(armorStand); + case BlazeEntity blaze when SlayerUtils.isInSlayer() -> AttunementColors.getColor(blaze); + case ZombifiedPiglinEntity piglin when SlayerUtils.isInSlayer() -> AttunementColors.getColor(piglin); + case WitherSkeletonEntity wSkelly when SlayerUtils.isInSlayer() -> AttunementColors.getColor(wSkelly); default -> 0xf57738; }; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java index 0ba3223d19..5868e55b87 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java @@ -3,6 +3,7 @@ import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.Location; import de.hysky.skyblocker.utils.SlayerUtils; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -36,7 +37,7 @@ public class SlayerEntitiesGlow { ); public static void init() { - SkyblockEvents.LOCATION_CHANGE.register(SlayerEntitiesGlow::clearGlow); + ClientPlayConnectionEvents.JOIN.register((ignore, ignore2, ignore3) -> clearGlow()); } private static final Map> SLAYER_MOB_TYPE = Map.of( SlayerUtils.REVENANT, ZombieEntity.class, @@ -60,22 +61,16 @@ public static boolean isSlayer(LivingEntity e) { public static boolean isSlayerMiniMob(LivingEntity entity) { if (entity.getCustomName() == null) return false; String entityName = entity.getCustomName().getString(); - return SLAYER_MINI_NAMES.keySet().stream().anyMatch(slayerMobName -> - entityName.contains(slayerMobName) && SlayerUtils.isInSlayerQuestType(SLAYER_MINI_NAMES.get(slayerMobName))); + return SLAYER_MINI_NAMES.keySet().stream().anyMatch(slayerMobName -> entityName.contains(slayerMobName) && SlayerUtils.isInSlayerQuestType(SLAYER_MINI_NAMES.get(slayerMobName))); } public static Box getSlayerMobBoundingBox(LivingEntity entity) { return switch (SlayerUtils.getSlayerType()) { - case SlayerUtils.REVENANT -> - new Box(entity.getX() - 0.4, entity.getY() - 0.1, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 2.2, entity.getZ() + 0.4); - case SlayerUtils.TARA -> - new Box(entity.getX() - 0.9, entity.getY() - 0.2, entity.getZ() - 0.9, entity.getX() + 0.9, entity.getY() - 1.2, entity.getZ() + 0.9); - case SlayerUtils.VOIDGLOOM -> - new Box(entity.getX() - 0.4, entity.getY() - 0.2, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 3, entity.getZ() + 0.4); - case SlayerUtils.SVEN -> - new Box(entity.getX() - 0.5, entity.getY() - 0.1, entity.getZ() - 0.5, entity.getX() + 0.5, entity.getY() - 1, entity.getZ() + 0.5); - default -> - new Box(entity.getX() - 0.5, entity.getY() + 0.1, entity.getZ() - 0.5, entity.getX() + 0.5, entity.getY() - 2.2, entity.getZ() + 0.5); + case SlayerUtils.REVENANT -> new Box(entity.getX() - 0.4, entity.getY() - 0.1, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 2.2, entity.getZ() + 0.4); + case SlayerUtils.TARA -> new Box(entity.getX() - 0.9, entity.getY() - 0.2, entity.getZ() - 0.9, entity.getX() + 0.9, entity.getY() - 1.2, entity.getZ() + 0.9); + case SlayerUtils.VOIDGLOOM -> new Box(entity.getX() - 0.4, entity.getY() - 0.2, entity.getZ() - 0.4, entity.getX() + 0.4, entity.getY() - 3, entity.getZ() + 0.4); + case SlayerUtils.SVEN -> new Box(entity.getX() - 0.5, entity.getY() - 0.1, entity.getZ() - 0.5, entity.getX() + 0.5, entity.getY() - 1, entity.getZ() + 0.5); + default -> entity.getBoundingBox(); }; } @@ -91,7 +86,6 @@ private static MobEntity findClosestMobEntity(Class entityC .getBoxAt(armorStand.getPos()).expand(1.5), entity -> !entity.isDead() && entity.age > armorStand.age - 4 && entity.age < armorStand.age + 4) .stream() - .filter(entity -> !(entity instanceof CaveSpiderEntity)) .filter(SlayerEntitiesGlow::isValidSlayerMob) .min(Comparator.comparingDouble((MobEntity e) -> e.distanceTo(armorStand))) .orElse(null); @@ -123,7 +117,7 @@ public static void onEntityDeath(@Nullable Entity entity) { if (entity != null && entity.getUuid() != null) MOBS_TO_GLOW.remove(entity.getUuid()); } - private static void clearGlow(Location location) { + private static void clearGlow() { MOBS_TO_GLOW.clear(); } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 5e4c44621c..0cb790270d 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -197,8 +197,7 @@ "skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip": "Draws the bounding boxes of starred mobs.", "skyblocker.config.dungeons.starredMobGlow": "Starred Mob Glow", - "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nWARNING: This feature utilises ray casting on a lot of entities which may have an impact on performance.", - + "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nWARNING: This feature utilises ray casting on entities which may have an impact on performance.", "skyblocker.config.dungeons.terminals": "Terminal Solvers (F7/M7)", "skyblocker.config.dungeons.terminals.blockIncorrectClicks": "Block Incorrect Clicks", "skyblocker.config.dungeons.terminals.solveColor": "Solve Select Colored", @@ -620,7 +619,7 @@ "skyblocker.config.slayer.highlightBosses.@Tooltip[0]": "\nOFF: Do not highlight Slayer Bosses.", "skyblocker.config.slayer.highlightBosses.@Tooltip[1]": "\nGLOW: Creates a glow effect on Slayer Bosses. Due to technical limitations, there is a small chance of this option making mistakes in mob detection", "skyblocker.config.slayer.highlightBosses.@Tooltip[2]": "\nHITBOX: Display a Hitbox around the Slayer Boss", - "skyblocker.config.slayer.highlightBosses.@Tooltip[3]": "This option is required for Blazeslayer Attunement Highlighting", + "skyblocker.config.slayer.highlightBosses.@Tooltip[3]": "\nThis option is required for Blazeslayer Attunement Highlighting", "skyblocker.config.slayer.vampireSlayer": "Vampire Slayer", "skyblocker.config.slayer.vampireSlayer.compactEffigyWaypoints": "Compact Effigy Waypoints", From 10f86c77db817ba3b72eef2942d57a8a57602af9 Mon Sep 17 00:00:00 2001 From: nmccullagh Date: Sun, 11 Aug 2024 18:56:16 +0100 Subject: [PATCH 7/9] update demon minion range --- .../java/de/hysky/skyblocker/skyblock/entity/MobGlow.java | 4 ++-- .../hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 3a5b025bfe..eeb4005c19 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -124,8 +124,8 @@ private static boolean computeShouldMobGlow(Entity entity) { case BlazeEntity blaze when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> SlayerEntitiesGlow.shouldGlow(blaze.getUuid()); // Blaze Slayer's Demonic minions - case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; - case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 14; + case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15; + case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15; default -> false; }; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java index 5868e55b87..79f91bfbfd 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java @@ -1,7 +1,5 @@ package de.hysky.skyblocker.skyblock.slayers; -import de.hysky.skyblocker.events.SkyblockEvents; -import de.hysky.skyblocker.utils.Location; import de.hysky.skyblocker.utils.SlayerUtils; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.minecraft.client.MinecraftClient; From 1036391bab98180a10aee525945f6a677f05b19a Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:03:50 +0800 Subject: [PATCH 8/9] Apply MobGlow suggestions --- .../skyblocker/skyblock/entity/MobGlow.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index eeb4005c19..b0436dd157 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -40,7 +40,7 @@ public class MobGlow { private static final ConcurrentHashMap canSeeCache = new ConcurrentHashMap<>(); public static void init() { - Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 300*20); + Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 300 * 20); } public static boolean shouldMobGlow(Entity entity) { @@ -75,15 +75,6 @@ private static boolean playerCanSee(Entity entity, long currentTime) { } private static boolean computeShouldMobGlow(Entity entity) { - - if (entity.isInvisible()) { - return switch (entity) { - case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> - SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; - default -> false; - }; - } - String name = entity.getName().getString(); // Dungeons @@ -123,6 +114,9 @@ private static boolean computeShouldMobGlow(Entity entity) { case WolfEntity wolf when SlayerUtils.isInSlayerQuestType(SlayerUtils.SVEN) -> SlayerEntitiesGlow.shouldGlow(wolf.getUuid()); case BlazeEntity blaze when SlayerUtils.isInSlayerQuestType(SlayerUtils.DEMONLORD) -> SlayerEntitiesGlow.shouldGlow(blaze.getUuid()); + // Enderman Slayer's Nukekubi Skulls + case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads; + // Blaze Slayer's Demonic minions case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15; case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerUtils.isInSlayerType(SlayerUtils.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15; @@ -196,7 +190,7 @@ private static boolean isNukekubiHead(ArmorStandEntity entity) { return Streams.stream(entity.getArmorItems()).map(ItemUtils::getHeadTexture).anyMatch(headTexture -> headTexture.contains(NUKEKUBI_HEAD_TEXTURE)); } - private record CacheEntry(boolean value, long timestamp){} + private record CacheEntry(boolean value, long timestamp) {} private static void clearCache() { canSeeCache.clear(); From 507e962ee8adc0b04539aa1794208e7a0d68579b Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:07:25 +0800 Subject: [PATCH 9/9] Fix SlayersConfig --- .../hysky/skyblocker/config/categories/SlayersCategory.java | 2 ++ .../de/hysky/skyblocker/config/configs/SlayersConfig.java | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java index b06cf58590..f0e256a72d 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java @@ -18,6 +18,7 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig return ConfigCategory.createBuilder() .name(Text.translatable("skyblocker.config.slayer")) + //General Slayers Options .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.slayer.highlightMinis")) .description(OptionDescription.of( @@ -163,6 +164,7 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .build()) .build()) + //Blaze Slayer .group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.slayer.blazeSlayer")) .collapsed(true) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java index 8586636096..82713e5df9 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java @@ -17,10 +17,10 @@ public enum HighlightSlayerEntities { public EndermanSlayer endermanSlayer = new EndermanSlayer(); @SerialEntry - public BlazeSlayer blazeSlayer = new BlazeSlayer(); + public VampireSlayer vampireSlayer = new VampireSlayer(); @SerialEntry - public VampireSlayer vampireSlayer = new VampireSlayer(); + public BlazeSlayer blazeSlayer = new BlazeSlayer(); public static class EndermanSlayer { @SerialEntry