From 96d7cc8ddb1aa2b54adb79da88be82aa327a297a Mon Sep 17 00:00:00 2001
From: Aaron <51387595+AzureAaron@users.noreply.github.com>
Date: Sat, 16 Nov 2024 14:37:39 -0500
Subject: [PATCH] Fix Glow (#1050)

* Fix Glow

* Remove cache
---
 .../skyblocker/mixins/WorldRendererMixin.java | 31 +++++++++++
 .../skyblocker/skyblock/entity/MobGlow.java   | 54 +------------------
 .../assets/skyblocker/lang/en_us.json         |  2 +-
 3 files changed, 34 insertions(+), 53 deletions(-)

diff --git a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java
index 6f0b9349fd..01b1a0d603 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java
@@ -1,7 +1,9 @@
 package de.hysky.skyblocker.mixins;
 
+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;
@@ -17,6 +19,7 @@
 import de.hysky.skyblocker.skyblock.entity.MobBoundingBoxes;
 import de.hysky.skyblocker.skyblock.entity.MobGlow;
 import de.hysky.skyblocker.skyblock.slayers.SlayerEntitiesGlow;
+import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.render.DefaultFramebufferSet;
 import net.minecraft.client.render.WorldRenderer;
 import net.minecraft.entity.Entity;
@@ -25,7 +28,30 @@
 @Mixin(WorldRenderer.class)
 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;
+	}
+
+	@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) {
@@ -54,4 +80,9 @@ public class WorldRendererMixin {
 			);
 		}
 	}
+
+	@Inject(method = "render", at = @At("TAIL"))
+	private void skyblocker$resetCustomGlowBool(CallbackInfo ci) {
+		atLeastOneMobHasCustomGlow = 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 91ac62bd4e..131df01069 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
@@ -1,7 +1,6 @@
 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;
@@ -14,7 +13,6 @@
 import de.hysky.skyblocker.utils.ItemUtils;
 import de.hysky.skyblocker.utils.SlayerUtils;
 import de.hysky.skyblocker.utils.Utils;
-import de.hysky.skyblocker.utils.scheduler.Scheduler;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.decoration.ArmorStandEntity;
@@ -28,63 +26,23 @@
 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 = "eyJ0aW1lc3RhbXAiOjE1MzQ5NjM0MzU5NjIsInByb2ZpbGVJZCI6ImQzNGFhMmI4MzFkYTRkMjY5NjU1ZTMzYzE0M2YwOTZjIiwicHJvZmlsZU5hbWUiOiJFbmRlckRyYWdvbiIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0=";
-	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<>();
-
-	@Init
-	public static void init() {
-		Scheduler.INSTANCE.scheduleCyclic(MobGlow::clearCache, 300 * 20);
-	}
+	private static final String NUKEKUBI_HEAD_TEXTURE = "eyJ0aW1lc3RhbXAiOjE1MzQ5NjM0MzU5NjIsInByb2ZpbGVJZCI6ImQzNGFhMmI4MzFkYTRkMjY5NjU1ZTMzYzE0M2YwOTZjIiwicHJvZmlsZU5hbWUiOiJFbmRlckRyYWdvbiIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0=";
 
 	public static boolean shouldMobGlow(Entity entity) {
-
-		long currentTime = System.currentTimeMillis();
-
-		CacheEntry cachedGlow = glowCache.get(entity);
-		if (cachedGlow == null || (currentTime - cachedGlow.timestamp) > GLOW_CACHE_DURATION) {
-			boolean shouldGlow = computeShouldMobGlow(entity);
-			glowCache.put(entity, new CacheEntry(shouldGlow, currentTime));
-			cachedGlow = glowCache.get(entity);
-		}
-
-		return cachedGlow.value && playerCanSee(entity, currentTime);
-	}
-
-
-	/**
-	 * Checks if the player can see the entity.
-	 * Has "True sight" within a certain aura, but since name tags exist I think this is fine...
-	 */
-	private static boolean playerCanSee(Entity entity, long currentTime) {
-
-		CacheEntry canSee = canSeeCache.get(entity);
-		if (canSee == null || (currentTime - canSee.timestamp) > PLAYER_CAN_SEE_CACHE_DURATION) {
-			boolean playerCanSee = entity.distanceTo(MinecraftClient.getInstance().player) <= 20 || MinecraftClient.getInstance().player.canSee(entity);
-			canSeeCache.put(entity, new CacheEntry(playerCanSee, currentTime));
-			return playerCanSee;
-		}
-
-		return canSee.value;
+		return computeShouldMobGlow(entity);
 	}
 
 	private static boolean computeShouldMobGlow(Entity entity) {
-
 		// 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);
@@ -101,7 +59,6 @@ private static boolean computeShouldMobGlow(Entity entity) {
 		}
 
 		return switch (entity) {
-
 			// Rift Blobbercyst
 			case PlayerEntity p when Utils.isInTheRift() && p.getName().getString().equals("Blobbercyst ") -> SkyblockerConfigManager.get().otherLocations.rift.blobbercystGlow;
 
@@ -193,11 +150,4 @@ public static int getGlowColor(Entity entity) {
 	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();
-	}
 }
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 43d44b41f2..c590d37605 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -216,7 +216,7 @@
   "skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip": "Draws the bounding boxes of starred mobs.",
 
   "skyblocker.config.dungeons.starredMobGlow": "Starred Mob Glow",
-  "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nWARNING: This feature utilises ray casting on entities which may have an impact on performance.",
+  "skyblocker.config.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.\n\nNote that using this will result in the teammate glow no longer being visible through walls when a starred mob is present.",
   "skyblocker.config.dungeons.terminals": "Terminal Solvers (F7/M7)",
   "skyblocker.config.dungeons.terminals.blockIncorrectClicks": "Block Incorrect Clicks",
   "skyblocker.config.dungeons.terminals.solveColor": "Solve Select Colored",