Skip to content

Commit

Permalink
Merge pull request #502 from akarahdev/master
Browse files Browse the repository at this point in the history
Enderman Slayer Utilities
  • Loading branch information
LifeIsAParadox authored Jan 25, 2024
2 parents f3877c4 + cbe2450 commit 9e1a614
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 47 deletions.
2 changes: 2 additions & 0 deletions src/main/java/de/hysky/skyblocker/SkyblockerMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker;
import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
import de.hysky.skyblocker.skyblock.item.*;
import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
Expand Down Expand Up @@ -135,6 +136,7 @@ public void onInitializeClient() {
RenderHelper.init();
containerSolverManager.init();
statusBarTracker.init();
BeaconHighlighter.init();
Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20);
Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200);
Scheduler.INSTANCE.scheduleCyclic(LividColor::update, 10);
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public static class QuickNav {
public QuickNavItem button10 = new QuickNavItem(true, new ItemData("enchanting_table"), "Enchant Item",
"/etable");


@SerialEntry
public QuickNavItem button11 = new QuickNavItem(true, new ItemData("anvil"), "Anvil", "/anvil");

Expand Down Expand Up @@ -169,7 +170,7 @@ public static class General {

@SerialEntry
public boolean hideStatusEffectOverlay = false;

@SerialEntry
public boolean dontStripSkinAlphaValues = true;

Expand Down Expand Up @@ -943,10 +944,21 @@ public static class Relics {
}

public static class Slayer {
@SerialEntry
public EndermanSlayer endermanSlayer = new EndermanSlayer();

@SerialEntry
public VampireSlayer vampireSlayer = new VampireSlayer();
}

public static class EndermanSlayer {
@SerialEntry
public boolean highlightNukekubiHeads = true;

@SerialEntry
public boolean highlightBeacons = true;
}

public static class VampireSlayer {
@SerialEntry
public boolean enableEffigyWaypoints = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
return ConfigCategory.createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.category.slayer"))

//Enderman Slayer
.group(OptionGroup.createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.slayer.endermanSlayer"))
.collapsed(true)
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.slayer.endermanSlayer.highlightNukekubiHeads"))
.binding(defaults.slayer.endermanSlayer.highlightNukekubiHeads,
() -> config.slayer.endermanSlayer.highlightNukekubiHeads,
newValue -> config.slayer.endermanSlayer.highlightNukekubiHeads = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.slayer.endermanSlayer.highlightBeacons"))
.binding(defaults.slayer.endermanSlayer.highlightBeacons,
() -> config.slayer.endermanSlayer.highlightBeacons,
newValue -> config.slayer.endermanSlayer.highlightBeacons = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.build())

//Vampire Slayer
.group(OptionGroup.createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.slayer.vampireSlayer"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
import de.hysky.skyblocker.skyblock.FishingHelper;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.utils.SlayerUtils;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityStatuses;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket;
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
Expand All @@ -27,13 +31,17 @@

@Mixin(ClientPlayNetworkHandler.class)
public abstract class ClientPlayNetworkHandlerMixin {

@Inject(method = "onPlaySound", at = @At("RETURN"))
private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) {
FishingHelper.onSound(packet);
@Inject(method = "onBlockUpdate", at = @At("RETURN"))
private void skyblocker$onBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) {
if (Utils.isInTheEnd() && SlayerUtils.isInSlayer()) {
BeaconHighlighter.beaconPositions.remove(packet.getPos());
if (packet.getState().isOf(Blocks.BEACON)) {
BeaconHighlighter.beaconPositions.add(packet.getPos());
}
}
}

@ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "STORE", ordinal = 0))
@ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "STORE", ordinal = 0))
private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity, @Local LivingEntity collector) {
DungeonManager.onItemPickup(itemEntity, collector, collector == MinecraftClient.getInstance().player);
return itemEntity;
Expand All @@ -44,34 +52,39 @@ public abstract class ClientPlayNetworkHandlerMixin {
return !Utils.isOnHypixel();
}

@ModifyExpressionValue(method = "onEntityStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityStatusS2CPacket;getEntity(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;"))
private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) {
if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) DungeonScore.handleEntityDeath(entity);
return entity;
}

@WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$cancelPlayerListWarning(Logger instance, String format, Object arg1, Object arg2) {
return !Utils.isOnHypixel();
}

@WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) {
return !Utils.isOnHypixel();
@Inject(method = "onPlaySound", at = @At("RETURN"))
private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) {
FishingHelper.onSound(packet);
}

@WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) {
return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion"));
}

@WrapWithCondition(method = { "onScoreboardScoreUpdate", "onScoreboardScoreReset" }, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) {
return !Utils.isOnHypixel();
}

@WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) {
return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion"));
@WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) {
return !Utils.isOnHypixel();
}

@Inject(method = "onParticle", at = @At("RETURN"))
private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) {
MythologicalRitual.onParticle(packet);
}

@ModifyExpressionValue(method = "onEntityStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityStatusS2CPacket;getEntity(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;"))
private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) {
if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) DungeonScore.handleEntityDeath(entity);
return entity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.hysky.skyblocker.skyblock.end;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.RenderHelper;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.minecraft.util.math.BlockPos;

import java.util.ArrayList;
import java.util.List;

public class BeaconHighlighter {
public static final List<BlockPos> beaconPositions = new ArrayList<>();

/**
* Initializes the beacon highlighting system.
* {@link BeaconHighlighter#render(WorldRenderContext)} is called after translucent rendering.
*/
public static void init() {
WorldRenderEvents.AFTER_TRANSLUCENT.register(BeaconHighlighter::render);
}

/**
* Renders the beacon glow around it. It is rendered in a red color with 50% opacity, and
* is visible through walls.
*
* @param context An instance of WorldRenderContext for the RenderHelper to use
*/
public static void render(WorldRenderContext context) {
if (Utils.isInTheEnd() && SkyblockerConfigManager.get().slayer.endermanSlayer.highlightBeacons)
beaconPositions.forEach((position) -> RenderHelper.renderFilled(
context,
position,
new float[]{1.0f, 0.0f, 0.0f},
0.5f,
false
));
}
}
98 changes: 70 additions & 28 deletions src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,81 @@
package de.hysky.skyblocker.skyblock.entity;

import java.util.List;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.dungeon.LividColor;
import de.hysky.skyblocker.utils.SlayerUtils;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.culling.OcclusionCulling;
import net.minecraft.entity.Entity;
import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.entity.passive.BatEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.Box;
import net.minecraft.world.World;

import java.util.List;

public class MobGlow {
public static boolean shouldMobGlow(Entity entity) {
Box box = entity.getBoundingBox();

if (!entity.isInvisible() && OcclusionCulling.getReducedCuller().isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) {
if (OcclusionCulling.getReducedCuller().isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) {
String name = entity.getName().getString();

// Dungeons
if (Utils.isInDungeons()) {
if (!entity.isInvisible()) {

// Dungeons
if (Utils.isInDungeons()) {

// Minibosses
if (entity instanceof PlayerEntity) {
switch (name) {
case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow;
case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid",
"Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name);
// Minibosses
if (entity instanceof PlayerEntity) {
switch (name) {
case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow;
case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid",
"Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name);
}
}
}

// Regular Mobs
if (!(entity instanceof ArmorStandEntity)) {
List<ArmorStandEntity> armorStands = getArmorStands(entity.getWorld(), box);
// Regular Mobs
if (!(entity instanceof ArmorStandEntity)) {
List<ArmorStandEntity> armorStands = getArmorStands(entity.getWorld(), box);

if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow;
}
if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯"))
return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow;
}

// Bats
return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && entity instanceof BatEntity;
}
// Bats
return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && entity instanceof BatEntity;
}

// Rift
if (Utils.isInTheRift()) {
if (entity instanceof PlayerEntity) {
switch (name) {
// They have a space in their name for some reason...
case "Blobbercyst ": return SkyblockerConfigManager.get().locations.rift.blobbercystGlow;
// Rift
if (Utils.isInTheRift()) {
if (entity instanceof PlayerEntity) {
switch (name) {
// They have a space in their name for some reason...
case "Blobbercyst ": return SkyblockerConfigManager.get().locations.rift.blobbercystGlow;
}
}
}
}

// Enderman Slayer
// Highlights Nukekubi Heads
return SkyblockerConfigManager.get().slayer.endermanSlayer.highlightNukekubiHeads
&& SlayerUtils.isInSlayer()
&& entity instanceof ArmorStandEntity armorStandEntity
&& isNukekubiHead(armorStandEntity);
}

return false;
}

private static List<ArmorStandEntity> getArmorStands(World world, Box box) {
return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED);
return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED);
}

public static int getGlowColor(Entity entity) {
Expand All @@ -72,12 +87,39 @@ public static int getGlowColor(Entity entity) {
case "Shadow Assassin" -> 0x5b2cb2;
case "Diamond Guy" -> 0x57c2f7;
case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid",
"Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name);
"Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name);
case "Blobbercyst " -> Formatting.GREEN.getColorValue();
default -> 0xf57738;
};
}

// copypaste nukekebi head logic
if (entity instanceof ArmorStandEntity armorStandEntity && isNukekubiHead(armorStandEntity)) return 0x990099;

return 0xf57738;
}

private static boolean isNukekubiHead(ArmorStandEntity entity) {
for (ItemStack armorItem : entity.getArmorItems()) {
// hacky way to check if an item is a player head w/o
// some shenanigans
if (!armorItem.toString().startsWith("1 player_head"))
continue;

// eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3 is texture id for the nukekubi head,
// compare against it to exclusively find armorstands that are nukekubi heads
NbtCompound skullOwner = armorItem.getSubNbt("SkullOwner");
if (skullOwner != null) {
// get the texture of the nukekubi head item itself and compare it
String texture = skullOwner
.getCompound("Properties")
.getList("textures", NbtElement.COMPOUND_TYPE)
.getCompound(0)
.getString("Value");

return texture.contains("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0=");
}
}
return false;
}
}
8 changes: 8 additions & 0 deletions src/main/java/de/hysky/skyblocker/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ public static boolean isInTheRift() {
return getLocationRaw().equals(TheRift.LOCATION);
}

/**
* @return if the player is in the end island
*/
public static boolean isInTheEnd() {
// /locraw returns "combat_3" when in The End
return getLocationRaw().equals("combat_3");
}

public static boolean isInjected() {
return isInjected;
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/assets/skyblocker/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@
"text.autoconfig.skyblocker.option.messages.hideDeath": "Hide Player Death Messages",
"text.autoconfig.skyblocker.option.messages.hideDeath.@Tooltip": "Filters the player death messages from chat.",
"text.autoconfig.skyblocker.category.slayer": "Slayers",
"text.autoconfig.skyblocker.option.slayer.endermanSlayer": "[Beta] Enderman Slayer",
"text.autoconfig.skyblocker.option.slayer.endermanSlayer.highlightNukekubiHeads": "Nukekubi Head Highlighting",
"text.autoconfig.skyblocker.option.slayer.endermanSlayer.highlightBeacons": "Beacon Highlighting",
"text.autoconfig.skyblocker.option.slayer.vampireSlayer": "Vampire Slayer",
"text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableEffigyWaypoints": "Enable Effigy Waypoints",
"text.autoconfig.skyblocker.option.slayer.vampireSlayer.compactEffigyWaypoints": "Compact Effigy Waypoints",
Expand Down Expand Up @@ -456,4 +459,4 @@
"skyblocker.partyFinder.join": "Click to join",

"emi.category.skyblocker.skyblock": "Skyblock"
}
}

0 comments on commit 9e1a614

Please sign in to comment.