aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2024-08-12 19:28:30 -0400
committerGitHub <noreply@github.com>2024-08-12 19:28:30 -0400
commit3830cea067dd2d0cdb2910dd624e0d9f0e46b7c3 (patch)
treec934a3a23b854b935fb54ca6afc541a23bf99fb0 /src/main/java
parent11fc3c22ffb57834a3b95dcacafa252dd67a658e (diff)
parent507e962ee8adc0b04539aa1794208e7a0d68579b (diff)
downloadSkyblocker-3830cea067dd2d0cdb2910dd624e0d9f0e46b7c3.tar.gz
Skyblocker-3830cea067dd2d0cdb2910dd624e0d9f0e46b7c3.tar.bz2
Skyblocker-3830cea067dd2d0cdb2910dd624e0d9f0e46b7c3.zip
Merge pull request #888 from BigloBot/new-slayer-highlighting-pr
[Slayer Helpers] Slayer Highlights, Blaze Helpers and Glow Caching
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java38
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java35
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java61
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java133
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java122
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java76
11 files changed, 500 insertions, 50 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 5e573598..405827e0 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -31,6 +31,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;
@@ -48,6 +49,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;
@@ -212,6 +214,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..f0e256a7 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,31 @@ public class SlayersCategory {
return ConfigCategory.createBuilder()
.name(Text.translatable("skyblocker.config.slayer"))
+ //General Slayers Options
+ .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 +164,28 @@ public class SlayersCategory {
.build())
.build())
+ //Blaze Slayer
+ .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..82713e5d 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java
@@ -4,11 +4,24 @@ 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 VampireSlayer vampireSlayer = new VampireSlayer();
+ @SerialEntry
+ public BlazeSlayer blazeSlayer = new BlazeSlayer();
+
public static class EndermanSlayer {
@SerialEntry
public boolean enableYangGlyphsNotification = true;
@@ -57,4 +70,29 @@ public class SlayersConfig {
@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/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
index 4e263015..8cafb601 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
@@ -3,10 +3,13 @@ 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;
@@ -14,6 +17,7 @@ import de.hysky.skyblocker.skyblock.dwarven.CrystalsChestHighlighter;
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;
@@ -112,6 +116,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;
}
@@ -120,6 +125,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/AttunementColors.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java
new file mode 100644
index 00000000..ba94812a
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.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 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 getColor(LivingEntity e) {
+ if (!SkyblockerConfigManager.get().slayers.blazeSlayer.attunementHighlights) return 0xf57738;
+ for (Entity entity : SlayerUtils.getEntityArmorStands(e)) {
+ Matcher matcher = COLOR_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..d2328096
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java
@@ -0,0 +1,61 @@
+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.text.Text;
+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(), 22)) return;
+ announceFirePillarDetails(entityName);
+ }
+ }
+ }
+
+ private static void announceFirePillarDetails(String entityName) {
+ 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);
+ } 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..b0436dd1 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
@@ -2,20 +2,23 @@ package de.hysky.skyblocker.skyblock.entity;
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.AttunementColors;
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 +26,103 @@ 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 void init() {
+ Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 300 * 20);
+ }
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();
+ long currentTime = System.currentTimeMillis();
+ CacheEntry cachedGlow = glowCache.get(entity);
+ if (cachedGlow == null || (currentTime - cachedGlow.timestamp) > GLOW_CACHE_DURATION) {
+ boolean shouldGlow = computeShouldMobGlow(entity);
+ glowCache.put(entity, new CacheEntry(shouldGlow, currentTime));
+ cachedGlow = glowCache.get(entity);
+ }
- // 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);
+ return cachedGlow.value && playerCanSee(entity, currentTime);
+ }
- // Bats
- case BatEntity b -> SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes;
- // Armor Stands
- case ArmorStandEntity _armorStand -> false;
+ /**
+ * Checks if the player can see the entity.
+ * 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) {
- // Regular Mobs
- default -> SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity);
- };
- }
+ CacheEntry canSee = canSeeCache.get(entity);
+ if (canSee == null || (currentTime - canSee.timestamp) > PLAYER_CAN_SEE_CACHE_DURATION) {
+ boolean playerCanSee = entity.distanceTo(MinecraftClient.getInstance().player) <= 20 || MinecraftClient.getInstance().player.canSee(entity);
+ canSeeCache.put(entity, new CacheEntry(playerCanSee, currentTime));
+ return playerCanSee;
+ }
- return switch (entity) {
- // Rift
- case PlayerEntity p when Utils.isInTheRift() && !entity.isInvisible() && name.equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow;
+ return canSee.value;
+ }
- // Enderman Slayer
- // Highlights Nukekubi Heads
- case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads;
+ private static boolean computeShouldMobGlow(Entity entity) {
+ String name = entity.getName().getString();
+
+ // Dungeons
+ if (Utils.isInDungeons()) {
+ return switch (entity) {
- // Special Zelot
- case EndermanEntity enderman when Utils.isInTheEnd() && !entity.isInvisible() -> TheEnd.isSpecialZealot(enderman);
+ // 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);
- //dojo
- case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> DojoManager.shouldGlow(getArmorStandName(zombie));
+ // Bats
+ case BatEntity b -> SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes;
- //Kuudra
- case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE;
+ // Armor Stands
+ case ArmorStandEntity _armorStand -> false;
- default -> false;
+ // Regular Mobs
+ default -> SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity);
};
}
- return false;
+ return switch (entity) {
+
+ // Rift Blobbercyst
+ 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));
+
+ //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() -> 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 == 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;
+ };
}
/**
@@ -123,10 +169,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) -> 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;
};
}
@@ -137,4 +189,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..79f91bfb
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java
@@ -0,0 +1,122 @@
+package de.hysky.skyblocker.skyblock.slayers;
+
+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;
+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)
+ );
+
+ public static void init() {
+ ClientPlayConnectionEvents.JOIN.register((ignore, ignore2, ignore3) -> clearGlow());
+ }
+ 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);