Skip to content

Commit

Permalink
[Slayers] Adds Bossbars
Browse files Browse the repository at this point in the history
@
  • Loading branch information
BigloBot committed Aug 19, 2024
1 parent 7a9fbeb commit 8760809
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 17 deletions.
41 changes: 41 additions & 0 deletions src/main/java/de/hysky/skyblocker/mixins/BossBarHudMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package de.hysky.skyblocker.mixins;

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 (SlayerBossBars.shouldRenderBossBar()) {
ClientBossBar bar = SlayerBossBars.getBossBar();

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();
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
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;
Expand Down Expand Up @@ -42,7 +40,7 @@ public static void checkFirePillar(Entity entity) {

// There is an edge case where the slayer has entered demon phase and temporarily despawned with
// an active fire pillar in play, So fallback to the player
Entity referenceEntity = SlayerUtils.getSlayerEntity();
Entity referenceEntity = SlayerUtils.getSlayerArmorstandEntity();
if (!(referenceEntity != null ? referenceEntity : MinecraftClient.getInstance().player).getBlockPos().isWithinDistance(entity.getPos(), 22)) return;
announceFirePillarDetails(entityName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ protected static void updateMania() {
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected static void updateStake() {
TitleContainer.removeTitle(title);
return;
}
Entity slayerEntity = SlayerUtils.getSlayerEntity();
Entity slayerEntity = SlayerUtils.getSlayerArmorstandEntity();
if (slayerEntity != null && slayerEntity.getDisplayName().toString().contains("҉")) {
RenderHelper.displayInTitleContainerAndPlaySound(title);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ protected static void updateIce() {
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
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();

public static boolean shouldRenderBossBar() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastUpdateTime < UPDATE_INTERVAL) {
return bossBar != null;
}

lastUpdateTime = currentTime;

if (!SlayerUtils.isInSlayer()) {
bossMaxHealth = -1;
bossBar = null;
return false;
}

if (SlayerUtils.getSlayerArmorstandEntity() != null && bossMaxHealth == -1) {
Matcher maxHealthMatcher = HEALTH_PATTERN.matcher(SlayerUtils.getSlayerArmorstandEntity().getDisplayName().getString());
if (maxHealthMatcher.find()) bossMaxHealth = convertToInt(maxHealthMatcher.group(0));
}

return bossBar != null || SlayerUtils.getSlayerArmorstandEntity() != null;
}

public static ClientBossBar getBossBar() {
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 (slayer == null) {
if (SlayerUtils.isInSlayer()){
bossBar.setStyle(BossBar.Style.PROGRESS);
bossBar.setColor(BossBar.Color.RED);
}
return bossBar;
}

Matcher healthMatcher = HEALTH_PATTERN.matcher(slayer.getCustomName().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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static boolean shouldGlow(UUID entityUUID) {
}

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()));
}

Expand Down
21 changes: 14 additions & 7 deletions src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,46 @@

//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";
public static final String VOIDGLOOM = "Voidgloom Seraph";
public static final String VAMPIRE = "Riftstalker Bloodfiend";
public static final String DEMONLORD = "Inferno Demonlord";
private static final Logger LOGGER = LoggerFactory.getLogger(SlayerUtils.class);
private static final Pattern SLAYER_PATTERN = Pattern.compile("Revenant Horror|Tarantula Broodfather|Sven Packmaster|Voidgloom Seraph|Inferno Demonlord|Riftstalker Bloodfiend");
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(1F, 2.5F, 1F), x -> x instanceof ArmorStandEntity && x.hasCustomName());
public static List<Entity> getEntityArmorStands(Entity entity, float scanHeight) {
return entity.getEntityWorld().getOtherEntities(entity, entity.getBoundingBox().expand(1F, scanHeight, 1F), 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() {
if (slayerArmorstandEntity != null && slayerArmorstandEntity.isAlive()) {
return slayerArmorstandEntity;
}

if (MinecraftClient.getInstance().world != null) {
for (Entity entity : MinecraftClient.getInstance().world.getEntities()) {
if (entity.hasCustomName()) {
String entityName = entity.getCustomName().getString();
Matcher matcher = SLAYER_PATTERN.matcher(entityName);
if (matcher.find()) {
String username = MinecraftClient.getInstance().getSession().getUsername();
for (Entity armorStand : getEntityArmorStands(entity)) {
for (Entity armorStand : getEntityArmorStands(entity, 1.5f)) {
if (armorStand.getDisplayName().getString().contains(username)) {
return entity;
slayerArmorstandEntity = (ArmorStandEntity) entity;
return slayerArmorstandEntity;
}
}
}
}
}
}

slayerArmorstandEntity = null;
return null;
}

Expand All @@ -64,7 +72,6 @@ public static boolean isInSlayerType(String slayer) {
boolean type = false;
for (String line : Utils.STRING_SCOREBOARD) {
switch (line) {
case String a when a.contains("Slayer Quest") -> { return false; }
case String b when b.contains("Slay the boss!") -> inFight = true;
case String c when c.contains(slayer) -> type = true;
default -> { continue; }
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/skyblocker.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"AbstractInventoryScreenMixin",
"BackgroundRendererMixin",
"BatEntityMixin",
"BossBarHudMixin",
"ClientPlayerEntityMixin",
"ClientPlayNetworkHandlerMixin",
"ClientWorldMixin",
Expand Down

0 comments on commit 8760809

Please sign in to comment.