diff options
| author | nmccullagh <narhanael64@gmail.com> | 2024-08-03 20:32:57 +0100 |
|---|---|---|
| committer | nmccullagh <narhanael64@gmail.com> | 2024-08-03 20:32:57 +0100 |
| commit | b3704a19b13ccd9a2283053f60248bc5b2ae113b (patch) | |
| tree | 4fc125c8708b2b6bb464b66f6691ce4caf5176c9 /src/main/java | |
| parent | 9b4ca8ccb61154117f163774ab4d4aff8f6c5e50 (diff) | |
| download | Skyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.tar.gz Skyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.tar.bz2 Skyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.zip | |
remade slayer helpers pr
Diffstat (limited to 'src/main/java')
11 files changed, 496 insertions, 53 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index b1d25a01..51c65abc 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.BeaconHighlighter; 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.profileviewer.ProfileViewerScreen; 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 class SkyblockerMod implements ClientModInitializer { 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 0a65aa3b..b06cf585 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 @@ package de.hysky.skyblocker.config.categories; 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 class SlayersCategory { return ConfigCategory.createBuilder() .name(Text.translatable("skyblocker.config.slayer")) + .option(Option.<SlayersConfig.HighlightSlayerEntities>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.<SlayersConfig.HighlightSlayerEntities>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 class SlayersCategory { .build()) .build()) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.slayer.blazeSlayer")) + .collapsed(true) + .option(Option.<SlayersConfig.BlazeSlayer.FirePillar>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.<Boolean>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 ff6c2275..522c5b52 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java @@ -4,9 +4,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(); public static class EndermanSlayer { @@ -20,6 +33,32 @@ public class SlayersConfig { 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 c0cd8b7b..190fc5f9 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 @@ package de.hysky.skyblocker.mixins; 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 2959d4b5..7126cbad 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 00000000..9c38f775 --- /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 00000000..388e66dd --- /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. + * <p> + * 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 f005fc06..ad2b9b8c 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 de.hysky.skyblocker.utils.render.Renderable; 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 class MobBoundingBoxes { }; } + 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 22474cf8..7c980a04 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 com.google.common.collect.Streams; 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.util.math.Box; 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<Entity, CacheEntry> glowCache = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<Entity, CacheEntry> 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 class MobGlow { 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 class MobGlow { 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 00000000..54060829 --- /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<String, String> 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<String, Class<? extends MobEntity>> 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<UUID> 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, |
