Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mob glow refactor #1101

Merged
merged 3 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.systems.RenderSystem;

import net.minecraft.client.MinecraftClient;
import de.hysky.skyblocker.skyblock.entity.MobGlow;

import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.WorldRenderer;

@Mixin(RenderPhase.DepthTest.class)
public class RenderPhaseDepthTestMixin {
Expand All @@ -19,9 +19,7 @@ public class RenderPhaseDepthTestMixin {
private static Runnable skyblocker$modifyOutlineAlwaysStartAction(Runnable original, @Local(argsOnly = true) String depthFunctionName) {
if (depthFunctionName.equals("outline_always")) {
return () -> {
WorldRenderer worldRenderer = MinecraftClient.getInstance().worldRenderer;

if (worldRenderer != null && worldRenderer.atLeastOneMobHasCustomGlow()) {
if (MobGlow.atLeastOneMobHasCustomGlow()) {
RenderSystem.enableDepthTest();
RenderSystem.depthFunc(GL11.GL_LEQUAL);
}
Expand All @@ -35,9 +33,7 @@ public class RenderPhaseDepthTestMixin {
private static Runnable skyblocker$modifyOutlineAlwaysEndAction(Runnable original, @Local(argsOnly = true) String depthFunctionName) {
if (depthFunctionName.equals("outline_always")) {
return () -> {
WorldRenderer worldRenderer = MinecraftClient.getInstance().worldRenderer;

if (worldRenderer != null && worldRenderer.atLeastOneMobHasCustomGlow()) {
if (MobGlow.atLeastOneMobHasCustomGlow()) {
RenderSystem.disableDepthTest();
RenderSystem.depthFunc(GL11.GL_LEQUAL);
}
Expand Down
46 changes: 10 additions & 36 deletions src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
Expand All @@ -12,10 +11,7 @@

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;

import de.hysky.skyblocker.injected.CustomGlowInfo;
import de.hysky.skyblocker.skyblock.dungeon.LividColor;
import de.hysky.skyblocker.skyblock.entity.MobBoundingBoxes;
import de.hysky.skyblocker.skyblock.entity.MobGlow;
Expand All @@ -28,51 +24,39 @@
import net.minecraft.entity.decoration.ArmorStandEntity;

@Mixin(WorldRenderer.class)
public class WorldRendererMixin implements CustomGlowInfo {
public class WorldRendererMixin {
@Shadow
@Final
private MinecraftClient client;
@Shadow
@Final
private DefaultFramebufferSet framebufferSet;
@Unique
private boolean atLeastOneMobHasCustomGlow;

@ModifyExpressionValue(method = "getEntitiesToRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;hasOutline(Lnet/minecraft/entity/Entity;)Z"))
private boolean skyblocker$setupEntityOutlineFramebufferIfCustomGlow(boolean original, @Local Entity entity) {
boolean hasCustomGlow = MobGlow.shouldMobGlow(entity);

if (hasCustomGlow) atLeastOneMobHasCustomGlow = true;

return original || hasCustomGlow;
@ModifyExpressionValue(method = {"getEntitiesToRender", "renderEntities"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;hasOutline(Lnet/minecraft/entity/Entity;)Z"))
private boolean skyblocker$shouldMobGlow(boolean original, @Local Entity entity) {
boolean allowGlow = LividColor.allowGlow();
boolean customGlow = MobGlow.hasOrComputeMobGlow(entity);
return allowGlow && original || customGlow;
}

@Inject(method = "method_62214",
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;canDrawEntityOutlines()Z")),
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gl/Framebuffer;clear()V", ordinal = 0, shift = At.Shift.AFTER)
)
private void skyblocker$copyFramebufferDepth2AdjustGlowVisibility(CallbackInfo ci) {
if (atLeastOneMobHasCustomGlow) framebufferSet.entityOutlineFramebuffer.get().copyDepthFrom(client.getFramebuffer());
}

@ModifyExpressionValue(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;hasOutline(Lnet/minecraft/entity/Entity;)Z"))
private boolean skyblocker$shouldMobGlow(boolean original, @Local Entity entity, @Share("hasCustomGlow") LocalBooleanRef hasCustomGlow) {
boolean allowGlow = LividColor.allowGlow();
boolean shouldGlow = MobGlow.shouldMobGlow(entity);
hasCustomGlow.set(shouldGlow);
return allowGlow && original || shouldGlow;
if (MobGlow.atLeastOneMobHasCustomGlow()) framebufferSet.entityOutlineFramebuffer.get().copyDepthFrom(client.getFramebuffer());
}

@ModifyVariable(method = "renderEntities",
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;hasOutline(Lnet/minecraft/entity/Entity;)Z"), to = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/OutlineVertexConsumerProvider;setColor(IIII)V")),
at = @At("STORE"), ordinal = 0
)
private int skyblocker$modifyGlowColor(int color, @Local Entity entity, @Share("hasCustomGlow") LocalBooleanRef hasCustomGlow) {
return hasCustomGlow.get() ? MobGlow.getGlowColor(entity) : color;
private int skyblocker$modifyGlowColor(int color, @Local Entity entity) {
return MobGlow.getMobGlowOrDefault(entity, color);
}

@Inject(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderEntity(Lnet/minecraft/entity/Entity;DDDFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;)V"))
private void skyblocker$beforeEntityIsRendered(CallbackInfo ci, @Local Entity entity) {
private void skyblocker$renderMobBoundingBox(CallbackInfo ci, @Local Entity entity) {
boolean shouldShowBoundingBox = MobBoundingBoxes.shouldDrawMobBoundingBox(entity);

if (shouldShowBoundingBox) {
Expand All @@ -82,14 +66,4 @@ public class WorldRendererMixin implements CustomGlowInfo {
);
}
}

@Override
public boolean atLeastOneMobHasCustomGlow() {
return atLeastOneMobHasCustomGlow;
}

@Inject(method = "render", at = @At("TAIL"))
private void skyblocker$resetCustomGlowBool(CallbackInfo ci) {
atLeastOneMobHasCustomGlow = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static boolean shouldDrawMobBoundingBox(Entity entity) {
}

public static float[] getBoxColor(Entity entity) {
int color = MobGlow.getGlowColor(entity);
int color = MobGlow.getMobGlow(entity);

return new float[] { ((color >> 16) & 0xFF) / 255f, ((color >> 8) & 0xFF) / 255f, (color & 0xFF) / 255f };
}
Expand Down
120 changes: 71 additions & 49 deletions src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.hysky.skyblocker.skyblock.entity;

import com.google.common.collect.Streams;
import de.hysky.skyblocker.annotations.Init;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.SlayersConfig;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
Expand All @@ -13,13 +14,15 @@
import de.hysky.skyblocker.skyblock.slayers.boss.demonlord.AttunementColors;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.decoration.ArmorStandEntity;
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;
Expand All @@ -34,61 +37,107 @@ public class MobGlow {
*/
private static final String NUKEKUBI_HEAD_TEXTURE = "eyJ0aW1lc3RhbXAiOjE1MzQ5NjM0MzU5NjIsInByb2ZpbGVJZCI6ImQzNGFhMmI4MzFkYTRkMjY5NjU1ZTMzYzE0M2YwOTZjIiwicHJvZmlsZU5hbWUiOiJFbmRlckRyYWdvbiIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0=";
private static final String FEL_HEAD_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTcyMDAyNTQ4Njg2MywKICAicHJvZmlsZUlkIiA6ICIzZDIxZTYyMTk2NzQ0Y2QwYjM3NjNkNTU3MWNlNGJlZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJTcl83MUJsYWNrYmlyZCIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jMjg2ZGFjYjBmMjE0NGQ3YTQxODdiZTM2YmJhYmU4YTk4ODI4ZjdjNzlkZmY1Y2UwMTM2OGI2MzAwMTU1NjYzIiwKICAgICAgIm1ldGFkYXRhIiA6IHsKICAgICAgICAibW9kZWwiIDogInNsaW0iCiAgICAgIH0KICAgIH0KICB9Cn0=";
/**
* Cache for mob glow. Absence means the entity does not have custom glow.
* If an entity is in the cache, it must have custom glow.
*/
private static final Object2IntMap<Entity> CACHE = new Object2IntOpenHashMap<>();

@Init
public static void init() {
// Clear the cache every tick
ClientTickEvents.END_WORLD_TICK.register(client -> clearCache());
}

public static boolean atLeastOneMobHasCustomGlow() {
return !CACHE.isEmpty();
}

public static boolean hasOrComputeMobGlow(Entity entity) {
if (CACHE.containsKey(entity)) {
return true;
}
int color = computeMobGlow(entity);
if (color != 0) {
CACHE.put(entity, color);
return true;
}
return false;
}

public static int getMobGlow(Entity entity) {
return CACHE.getInt(entity);
}

public static int getMobGlowOrDefault(Entity entity, int defaultColor) {
return CACHE.getOrDefault(entity, defaultColor);
}

public static boolean shouldMobGlow(Entity entity) {
return computeShouldMobGlow(entity);
public static void clearCache() {
CACHE.clear();
}

private static boolean computeShouldMobGlow(Entity entity) {
/**
* Computes the glow color for the given entity.
* <p>Only non-zero colors are valid.
*/
private static int computeMobGlow(Entity entity) {
String name = entity.getName().getString();

// Dungeons
if (Utils.isInDungeons()) {
String name = entity.getName().getString();

return switch (entity) {
// Minibosses
case PlayerEntity p when (name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy")) && !DungeonManager.getBoss().isFloor(4) -> SkyblockerConfigManager.get().dungeons.starredMobGlow;
case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> LividColor.shouldGlow(name);
case PlayerEntity p when SkyblockerConfigManager.get().dungeons.starredMobGlow && !DungeonManager.getBoss().isFloor(4) && name.equals("Lost Adventurer") -> 0xfee15c;
case PlayerEntity p when SkyblockerConfigManager.get().dungeons.starredMobGlow && !DungeonManager.getBoss().isFloor(4) && name.equals("Shadow Assassin") -> 0x5b2cb2;
case PlayerEntity p when SkyblockerConfigManager.get().dungeons.starredMobGlow && !DungeonManager.getBoss().isFloor(4) && name.equals("Diamond Guy") -> 0x57c2f7;
case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() && LividColor.shouldGlow(name) -> LividColor.getGlowColor(name);

// Bats
case BatEntity b -> SkyblockerConfigManager.get().dungeons.starredMobGlow || SkyblockerConfigManager.get().dungeons.starredMobBoundingBoxes;
case BatEntity b when SkyblockerConfigManager.get().dungeons.starredMobGlow -> 0xf57738;

//Fel Heads
case ArmorStandEntity as when SkyblockerConfigManager.get().dungeons.starredMobGlow && as.isMarker() && as.hasStackEquipped(EquipmentSlot.HEAD) -> ItemUtils.getHeadTexture(as.getEquippedStack(EquipmentSlot.HEAD)).equals(FEL_HEAD_TEXTURE);
// Fel Heads
case ArmorStandEntity as when SkyblockerConfigManager.get().dungeons.starredMobGlow && as.isMarker() && as.hasStackEquipped(EquipmentSlot.HEAD) && ItemUtils.getHeadTexture(as.getEquippedStack(EquipmentSlot.HEAD)).equals(FEL_HEAD_TEXTURE) -> 0xcc00fa; // Enderman eye color

// Armor Stands
case ArmorStandEntity _armorStand -> false;
case ArmorStandEntity _armorStand -> 0;

// Regular Mobs
default -> SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity);
case Entity e when SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity) -> 0xf57738;
default -> 0;
};
}

// Slayer
if (SlayerManager.shouldGlow(entity, SlayersConfig.HighlightSlayerEntities.GLOW)) {
return true;
return switch (entity) {
case ArmorStandEntity e when SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(e);
case BlazeEntity e when SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(e);
default -> 0xf57738;
};
}

return switch (entity) {
// Rift Blobbercyst
case PlayerEntity p when Utils.isInTheRift() && p.getName().getString().equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow;
case PlayerEntity p when SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow && Utils.isInTheRift() && name.equals("Blobbercyst ") -> Formatting.GREEN.getColorValue();

// Dojo Helpers
case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena -> DojoManager.shouldGlow(getArmorStandName(zombie));
case ZombieEntity zombie when Utils.isInCrimson() && DojoManager.inArena && DojoManager.shouldGlow(getArmorStandName(zombie)) -> DojoManager.getColor();

//Kuudra
case MagmaCubeEntity magmaCube when Utils.isInKuudra() -> SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE;
case MagmaCubeEntity magmaCube when SkyblockerConfigManager.get().crimsonIsle.kuudra.kuudraGlow && Utils.isInKuudra() && magmaCube.getSize() == Kuudra.KUUDRA_MAGMA_CUBE_SIZE -> 0xf7510f;

// Special Zealot && Slayer (Mini)Boss
case EndermanEntity enderman when Utils.isInTheEnd() -> TheEnd.isSpecialZealot(enderman);
case EndermanEntity enderman when Utils.isInTheEnd() && TheEnd.isSpecialZealot(enderman) -> Formatting.RED.getColorValue();

// Enderman Slayer's Nukekubi Skulls
case ArmorStandEntity armorStand when Utils.isInTheEnd() && armorStand.isMarker() && SlayerManager.isInSlayer() && isNukekubiHead(armorStand) -> SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads;
case ArmorStandEntity armorStand when SkyblockerConfigManager.get().slayers.endermanSlayer.highlightNukekubiHeads && Utils.isInTheEnd() && armorStand.isMarker() && SlayerManager.isInSlayer() && isNukekubiHead(armorStand) -> 0x990099;

// Blaze Slayer's Demonic minions
case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15;
case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW -> SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15;
case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15 -> AttunementColors.getColor(e);
case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15 -> AttunementColors.getColor(e);

default -> false;
default -> 0;
};
}

Expand Down Expand Up @@ -125,33 +174,6 @@ public static List<ArmorStandEntity> getArmorStands(World world, Box box) {
return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED);
}

public static int getGlowColor(Entity entity) {
String name = entity.getName().getString();

//TODO maybe make this more like the compute method where dungeons stuff is separate
return switch (entity) {
case PlayerEntity p when name.equals("Lost Adventurer") -> 0xfee15c;
case PlayerEntity p when name.equals("Shadow Assassin") -> 0x5b2cb2;
case PlayerEntity p when name.equals("Diamond Guy") -> 0x57c2f7;
case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() -> LividColor.getGlowColor(name);
case PlayerEntity p when name.equals("Blobbercyst ") -> Formatting.GREEN.getColorValue();
case ArmorStandEntity as when Utils.isInDungeons() && ItemUtils.getHeadTexture(as.getEquippedStack(EquipmentSlot.HEAD)).equals(FEL_HEAD_TEXTURE)-> 0xcc00fa; //Enderman eye color

case EndermanEntity enderman when TheEnd.isSpecialZealot(enderman) -> Formatting.RED.getColorValue();
case ArmorStandEntity armorStand when armorStand.isMarker() && 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 SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(armorStand);
case BlazeEntity blaze when SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(blaze);
case ZombifiedPiglinEntity piglin when SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(piglin);
case WitherSkeletonEntity wSkelly when SlayerManager.isInSlayerType(SlayerType.DEMONLORD) -> AttunementColors.getColor(wSkelly);

default -> 0xf57738;
};
}

/**
* Compares the armor items of an armor stand to the Nukekubi head texture to determine if it is a Nukekubi head.
*/
Expand Down
3 changes: 0 additions & 3 deletions src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@
"loom:injected_interfaces": {
"net/minecraft/class_1799": [
"de/hysky/skyblocker/injected/SkyblockerStack"
],
"net/minecraft/class_761": [
"de/hysky/skyblocker/injected/CustomGlowInfo"
]
}
}
Expand Down
Loading