aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authornmccullagh <narhanael64@gmail.com>2024-08-03 20:32:57 +0100
committernmccullagh <narhanael64@gmail.com>2024-08-03 20:32:57 +0100
commitb3704a19b13ccd9a2283053f60248bc5b2ae113b (patch)
tree4fc125c8708b2b6bb464b66f6691ce4caf5176c9 /src/main/java
parent9b4ca8ccb61154117f163774ab4d4aff8f6c5e50 (diff)
downloadSkyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.tar.gz
Skyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.tar.bz2
Skyblocker-b3704a19b13ccd9a2283053f60248bc5b2ae113b.zip
remade slayer helpers pr
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.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java39
-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/AttunementColours.java35
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java60
-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.java156
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java119
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java57
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,