From 2335b31f51f33c3d875a1f1125631f22fddf0382 Mon Sep 17 00:00:00 2001 From: Kevin <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:06:57 -0500 Subject: Mob glow refactor (#1101) * Add mob glow cache * Clean up mixins * Clear cache once a tick + Javadocs --- .../hysky/skyblocker/injected/CustomGlowInfo.java | 8 -- .../mixins/RenderPhaseDepthTestMixin.java | 12 +-- .../skyblocker/mixins/WorldRendererMixin.java | 46 ++------ .../skyblock/entity/MobBoundingBoxes.java | 2 +- .../hysky/skyblocker/skyblock/entity/MobGlow.java | 120 ++++++++++++--------- 5 files changed, 86 insertions(+), 102 deletions(-) delete mode 100644 src/main/java/de/hysky/skyblocker/injected/CustomGlowInfo.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/injected/CustomGlowInfo.java b/src/main/java/de/hysky/skyblocker/injected/CustomGlowInfo.java deleted file mode 100644 index fd1ca401..00000000 --- a/src/main/java/de/hysky/skyblocker/injected/CustomGlowInfo.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.hysky.skyblocker.injected; - -public interface CustomGlowInfo { - - default boolean atLeastOneMobHasCustomGlow() { - return false; - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixins/RenderPhaseDepthTestMixin.java b/src/main/java/de/hysky/skyblocker/mixins/RenderPhaseDepthTestMixin.java index d90606db..7595d3e2 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/RenderPhaseDepthTestMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/RenderPhaseDepthTestMixin.java @@ -8,9 +8,9 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; 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 { @@ -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); } @@ -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); } diff --git a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java index 74ad1985..27a20941 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java @@ -3,7 +3,6 @@ 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; @@ -12,10 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 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; @@ -28,23 +24,19 @@ import net.minecraft.entity.Entity; 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", @@ -52,27 +44,19 @@ public class WorldRendererMixin implements CustomGlowInfo { 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) { @@ -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; - } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java index 1f318e21..65ad6918 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java @@ -52,7 +52,7 @@ public class MobBoundingBoxes { } 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 }; } 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 8c3086bc..0a53b7fa 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -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; @@ -13,13 +14,15 @@ import de.hysky.skyblocker.skyblock.slayers.SlayerType; 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; @@ -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 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. + *

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; }; } @@ -125,33 +174,6 @@ public class MobGlow { 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. */ -- cgit