aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorBigloBot <95036804+BigloBot@users.noreply.github.com>2024-09-08 22:37:46 +0100
committerGitHub <noreply@github.com>2024-09-08 23:37:46 +0200
commitd241b8c91fc39d2719f32b820ca205a1fc4a84c0 (patch)
tree3872b2af6c613f40d88ad211809d29eb25e217cc /src/main/java
parent04afe1aa4d5e7cd236a7c295aed7bb1bda15f2e9 (diff)
downloadSkyblocker-d241b8c91fc39d2719f32b820ca205a1fc4a84c0.tar.gz
Skyblocker-d241b8c91fc39d2719f32b820ca205a1fc4a84c0.tar.bz2
Skyblocker-d241b8c91fc39d2719f32b820ca205a1fc4a84c0.zip
[Slayers] Adds Slayer Bossbars (#940)
* [Slayers] Adds Bossbars @ * Apply suggestions from code review --------- Co-authored-by: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/BossBarHudMixin.java42
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/rift/ManiaIndicator.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/rift/StakeIndicator.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/rift/TwinClawsIndicator.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerBossBars.java102
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java27
11 files changed, 187 insertions, 22 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java
index f0e256a7..14f5c244 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java
@@ -42,6 +42,15 @@ public class SlayersCategory {
newValue -> config.slayers.highlightBosses = newValue)
.controller(ConfigUtils::createEnumCyclingListController)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.slayer.bossbar"))
+ .description(OptionDescription.of(
+ Text.translatable("skyblocker.config.slayer.bossbar.@Tooltip")))
+ .binding(defaults.slayers.displayBossbar,
+ () -> config.slayers.displayBossbar,
+ newValue -> config.slayers.displayBossbar = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
//Enderman Slayer
.group(OptionGroup.createBuilder()
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 7503108b..e3149d52 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/SlayersConfig.java
@@ -10,6 +10,9 @@ public class SlayersConfig {
@SerialEntry
public HighlightSlayerEntities highlightBosses = HighlightSlayerEntities.OFF;
+ @SerialEntry
+ public boolean displayBossbar = true;
+
public enum HighlightSlayerEntities {
OFF, GLOW, HITBOX;
diff --git a/src/main/java/de/hysky/skyblocker/mixins/BossBarHudMixin.java b/src/main/java/de/hysky/skyblocker/mixins/BossBarHudMixin.java
new file mode 100644
index 00000000..a15489c5
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/mixins/BossBarHudMixin.java
@@ -0,0 +1,42 @@
+package de.hysky.skyblocker.mixins;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.slayers.SlayerBossBars;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.hud.BossBarHud;
+import net.minecraft.client.gui.hud.ClientBossBar;
+import net.minecraft.entity.boss.BossBar;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(BossBarHud.class)
+public abstract class BossBarHudMixin {
+
+ @Final
+ @Shadow
+ private MinecraftClient client;
+
+ @Shadow
+ protected abstract void renderBossBar(DrawContext context, int x, int y, BossBar bossBar);
+
+ @Inject(method = "render", at = @At("HEAD"), cancellable = true)
+ private void onRender(DrawContext context, CallbackInfo ci) {
+
+ if (SkyblockerConfigManager.get().slayers.displayBossbar && SlayerBossBars.shouldRenderBossBar()) {
+ ClientBossBar bar = SlayerBossBars.updateBossBar();
+
+ int textWidth = this.client.textRenderer.getWidth(bar.getName());
+ context.drawTextWithShadow(this.client.textRenderer, bar.getName(), context.getScaledWindowWidth() / 2 - textWidth / 2, 3, 16777215);
+
+ this.renderBossBar(context, (context.getScaledWindowWidth() / 2) - 91, 12, bar);
+
+ ci.cancel();
+ }
+
+ }
+}
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
index ba94812a..6612d978 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/AttunementColors.java
@@ -17,7 +17,7 @@ public class AttunementColors {
*/
public static int getColor(LivingEntity e) {
if (!SkyblockerConfigManager.get().slayers.blazeSlayer.attunementHighlights) return 0xf57738;
- for (Entity entity : SlayerUtils.getEntityArmorStands(e)) {
+ for (Entity entity : SlayerUtils.getEntityArmorStands(e, 2.5f)) {
Matcher matcher = COLOR_PATTERN.matcher(entity.getDisplayName().getString());
if (matcher.find()) {
String matchedColour = matcher.group();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java
index d2328096..d5db338a 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/slayer/FirePillarAnnouncer.java
@@ -10,8 +10,6 @@ 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;
@@ -42,7 +40,7 @@ public class FirePillarAnnouncer {
// 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();
+ Entity referenceEntity = SlayerUtils.getSlayerArmorStandEntity();
if (!(referenceEntity != null ? referenceEntity : MinecraftClient.getInstance().player).getBlockPos().isWithinDistance(entity.getPos(), 22)) return;
announceFirePillarDetails(entityName);
}
@@ -58,4 +56,4 @@ public class FirePillarAnnouncer {
TitleContainer.addTitle(title, 15);
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/ManiaIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/ManiaIndicator.java
index 54ea9093..484c755d 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/rift/ManiaIndicator.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/ManiaIndicator.java
@@ -22,11 +22,11 @@ public class ManiaIndicator {
return;
}
- Entity slayerEntity = SlayerUtils.getSlayerEntity();
+ Entity slayerEntity = SlayerUtils.getSlayerArmorStandEntity();
if (slayerEntity == null) return;
boolean anyMania = false;
- for (Entity entity : SlayerUtils.getEntityArmorStands(slayerEntity)) {
+ for (Entity entity : SlayerUtils.getEntityArmorStands(slayerEntity, 2.5f)) {
if (entity.getDisplayName().toString().contains("MANIA")) {
anyMania = true;
BlockPos pos = MinecraftClient.getInstance().player.getBlockPos().down();
@@ -39,4 +39,4 @@ public class ManiaIndicator {
TitleContainer.removeTitle(title);
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/StakeIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/StakeIndicator.java
index 54bee5ec..5938d273 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/rift/StakeIndicator.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/StakeIndicator.java
@@ -17,11 +17,11 @@ public class StakeIndicator {
TitleContainer.removeTitle(title);
return;
}
- Entity slayerEntity = SlayerUtils.getSlayerEntity();
+ Entity slayerEntity = SlayerUtils.getSlayerArmorStandEntity();
if (slayerEntity != null && slayerEntity.getDisplayName().toString().contains("҉")) {
RenderHelper.displayInTitleContainerAndPlaySound(title);
} else {
TitleContainer.removeTitle(title);
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/TwinClawsIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/TwinClawsIndicator.java
index f6952ab4..b3a1f87b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/rift/TwinClawsIndicator.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/TwinClawsIndicator.java
@@ -20,11 +20,11 @@ public class TwinClawsIndicator {
return;
}
- Entity slayerEntity = SlayerUtils.getSlayerEntity();
+ Entity slayerEntity = SlayerUtils.getSlayerArmorStandEntity();
if (slayerEntity == null) return;
boolean anyClaws = false;
- for (Entity entity : SlayerUtils.getEntityArmorStands(slayerEntity)) {
+ for (Entity entity : SlayerUtils.getEntityArmorStands(slayerEntity, 2.5f)) {
if (entity.getDisplayName().toString().contains("TWINCLAWS")) {
anyClaws = true;
if (!TitleContainer.containsTitle(title) && !scheduled) {
@@ -40,4 +40,4 @@ public class TwinClawsIndicator {
TitleContainer.removeTitle(title);
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerBossBars.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerBossBars.java
new file mode 100644
index 00000000..c33d7af8
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerBossBars.java
@@ -0,0 +1,102 @@
+package de.hysky.skyblocker.skyblock.slayers;
+
+import de.hysky.skyblocker.utils.SlayerUtils;
+import net.minecraft.client.gui.hud.ClientBossBar;
+import net.minecraft.entity.boss.BossBar;
+import net.minecraft.entity.decoration.ArmorStandEntity;
+import net.minecraft.text.Text;
+
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SlayerBossBars {
+ private static final Pattern HEALTH_PATTERN = Pattern.compile("(\\d+(?:\\.\\d+)?[kM]?)(?=❤)");
+ private static int bossMaxHealth = -1;
+ private static long lastUpdateTime = 0;
+ private static final long UPDATE_INTERVAL = 400;
+ private static ClientBossBar bossBar;
+ public static final UUID uuid = UUID.randomUUID();
+
+ /**
+ * Determines if the boss bar should be rendered and updates the max health of the boss.
+ * Has a 400ms cooldown built-in.
+ */
+ public static boolean shouldRenderBossBar() {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastUpdateTime < UPDATE_INTERVAL) {
+ return bossBar != null;
+ }
+ lastUpdateTime = currentTime;
+
+ // Reset if no slayer
+ if (!SlayerUtils.isInSlayer()) {
+ bossMaxHealth = -1;
+ bossBar = null;
+ return false;
+ }
+
+ // Update boss max health
+ if (SlayerUtils.getSlayerArmorStandEntity() != null && bossMaxHealth == -1) {
+ Matcher maxHealthMatcher = HEALTH_PATTERN.matcher(SlayerUtils.getSlayerArmorStandEntity().getName().getString());
+ if (maxHealthMatcher.find()) bossMaxHealth = convertToInt(maxHealthMatcher.group(0));
+ }
+
+ return bossBar != null || SlayerUtils.getSlayerArmorStandEntity() != null;
+ }
+
+ /**
+ * Updates the boss bar with the current slayer's health, called every frame.
+ * @return The updated boss bar.
+ */
+ public static ClientBossBar updateBossBar() {
+ ArmorStandEntity slayer = SlayerUtils.getSlayerArmorStandEntity();
+ if (bossBar == null) bossBar = new ClientBossBar(uuid, slayer != null ? slayer.getDisplayName() : Text.of("Attempting to Locate Slayer..."), 1f, BossBar.Color.PURPLE, BossBar.Style.PROGRESS, false, false, false);
+
+ // If no slayer armor stand is found, display a red progress bar
+ if (slayer == null) {
+ bossBar.setStyle(BossBar.Style.PROGRESS);
+ bossBar.setColor(BossBar.Color.RED);
+ return bossBar;
+ }
+
+ // Update the boss bar with the current slayer's health
+ Matcher healthMatcher = HEALTH_PATTERN.matcher(slayer.getName().getString());
+ if (healthMatcher.find() && slayer.isAlive()) {
+ bossBar.setPercent(bossMaxHealth == -1 ? 1f : (float) convertToInt(healthMatcher.group(1)) / bossMaxHealth);
+ bossBar.setColor(BossBar.Color.PINK);
+ bossBar.setName(slayer.getDisplayName());
+ bossBar.setStyle(BossBar.Style.NOTCHED_10);
+ } else {
+ bossBar.setColor(BossBar.Color.RED);
+ bossBar.setStyle(BossBar.Style.PROGRESS);
+ bossBar.setName(slayer.getDisplayName());
+ }
+
+ return bossBar;
+ }
+
+ private static int convertToInt(String value) {
+ if (value == null || value.isEmpty()) {
+ return 0;
+ }
+
+ value = value.trim().toLowerCase();
+ double multiplier = 1.0;
+
+ if (value.endsWith("m")) {
+ multiplier = 1_000_000;
+ value = value.substring(0, value.length() - 1);
+ } else if (value.endsWith("k")) {
+ multiplier = 1_000;
+ value = value.substring(0, value.length() - 1);
+ }
+
+ try {
+ double numericValue = Double.parseDouble(value);
+ return (int) (numericValue * multiplier);
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java
index a87f737a..88ae51df 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/SlayerEntitiesGlow.java
@@ -66,7 +66,7 @@ public class SlayerEntitiesGlow {
}
public static boolean isSlayer(LivingEntity e) {
- return SlayerUtils.isInSlayer() && SlayerUtils.getEntityArmorStands(e).stream().anyMatch(entity ->
+ return SlayerUtils.isInSlayer() && SlayerUtils.getEntityArmorStands(e, 2.5f).stream().anyMatch(entity ->
entity.getDisplayName().getString().contains(MinecraftClient.getInstance().getSession().getUsername()));
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java
index 8944eb3d..6eaa7708 100644
--- a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java
@@ -12,6 +12,7 @@ import java.util.regex.Pattern;
//TODO Slayer Packet system that can provide information about the current slayer boss, abstract so that different bosses can have different info
public class SlayerUtils {
+ private static ArmorStandEntity slayerArmorStandEntity;
public static final String REVENANT = "Revenant Horror";
public static final String TARA = "Tarantula Broodfather";
public static final String SVEN = "Sven Packmaster";
@@ -19,15 +20,20 @@ public class SlayerUtils {
public static final String VAMPIRE = "Riftstalker Bloodfiend";
public static final String DEMONLORD = "Inferno Demonlord";
private static final Logger LOGGER = LoggerFactory.getLogger(SlayerUtils.class);
- private static final Pattern SLAYER_PATTERN = Pattern.compile("Revenant Horror|Tarantula Broodfather|Sven Packmaster|Voidgloom Seraph|Inferno Demonlord|Riftstalker Bloodfiend");
+ public static final Pattern SLAYER_PATTERN = Pattern.compile("Revenant Horror|Tarantula Broodfather|Sven Packmaster|Voidgloom Seraph|Inferno Demonlord|Riftstalker Bloodfiend");
//TODO: Cache this, probably included in Packet system
- public static List<Entity> getEntityArmorStands(Entity entity) {
- return entity.getEntityWorld().getOtherEntities(entity, entity.getBoundingBox().expand(0.3F, 2.5F, 0.3F), x -> x instanceof ArmorStandEntity && x.hasCustomName());
+ public static List<Entity> getEntityArmorStands(Entity entity, float expandY) {
+ return entity.getEntityWorld().getOtherEntities(entity, entity.getBoundingBox().expand(0.3F, expandY, 0.3F), x -> x instanceof ArmorStandEntity && x.hasCustomName());
}
//Eventually this should be modified so that if you hit a slayer boss all slayer features will work on that boss.
- public static Entity getSlayerEntity() {
+ public static ArmorStandEntity getSlayerArmorStandEntity() {
+ // TODO: This should be set when the system to detect isInSlayer is made event-driven
+ if (slayerArmorStandEntity != null && slayerArmorStandEntity.isAlive()) {
+ return slayerArmorStandEntity;
+ }
+
if (MinecraftClient.getInstance().world != null) {
for (Entity entity : MinecraftClient.getInstance().world.getEntities()) {
if (entity.hasCustomName()) {
@@ -35,22 +41,27 @@ public class SlayerUtils {
Matcher matcher = SLAYER_PATTERN.matcher(entityName);
if (matcher.find()) {
String username = MinecraftClient.getInstance().getSession().getUsername();
- for (Entity armorStand : getEntityArmorStands(entity)) {
+ for (Entity armorStand : getEntityArmorStands(entity, 1.5f)) {
if (armorStand.getDisplayName().getString().contains(username)) {
- return entity;
+ slayerArmorStandEntity = (ArmorStandEntity) entity;
+ return slayerArmorStandEntity;
}
}
}
}
}
}
+
+ slayerArmorStandEntity = null;
return null;
}
public static boolean isInSlayer() {
try {
for (String line : Utils.STRING_SCOREBOARD) {
- if (line.contains("Slay the boss!")) return true;
+ if (line.contains("Slay the boss!")) {
+ return true;
+ }
}
} catch (NullPointerException e) {
LOGGER.error("[Skyblocker] Error while checking if player is in slayer", e);
@@ -102,4 +113,4 @@ public class SlayerUtils {
}
return "";
}
-} \ No newline at end of file
+}