diff --git a/api/api/api.api b/api/api/api.api index 609ad19..f43e723 100644 --- a/api/api/api.api +++ b/api/api/api.api @@ -423,13 +423,13 @@ public abstract interface class gg/essential/api/utils/GuiUtil { public abstract fun openScreen (Lnet/minecraft/client/gui/screens/Screen;)V @1.17.1-forge,1.18.2-forge,1.19.2-forge,1.19.3-forge,1.19.4-forge,1.20.1-forge,1.20.2-forge,1.20.4-forge public abstract fun openedScreen ()Lnet/minecraft/client/gui/screens/Screen; - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public static fun getOpenedScreen ()Lnet/minecraft/client/gui/screen/Screen; - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public static fun open (Lnet/minecraft/client/gui/screen/Screen;)V - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public abstract fun openScreen (Lnet/minecraft/client/gui/screen/Screen;)V - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public abstract fun openedScreen ()Lnet/minecraft/client/gui/screen/Screen; @1.12.2-forge,1.8.9-forge public static fun getOpenedScreen ()Lnet/minecraft/client/gui/GuiScreen; @@ -446,9 +446,9 @@ public final class gg/essential/api/utils/GuiUtil$Companion { public final fun getOpenedScreen ()Lnet/minecraft/client/gui/screens/Screen; @1.17.1-forge,1.18.2-forge,1.19.2-forge,1.19.3-forge,1.19.4-forge,1.20.1-forge,1.20.2-forge,1.20.4-forge public final fun open (Lnet/minecraft/client/gui/screens/Screen;)V - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public final fun getOpenedScreen ()Lnet/minecraft/client/gui/screen/Screen; - @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.16.2-forge,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public final fun open (Lnet/minecraft/client/gui/screen/Screen;)V @1.12.2-forge,1.8.9-forge public final fun getOpenedScreen ()Lnet/minecraft/client/gui/GuiScreen; @@ -512,7 +512,7 @@ public final class gg/essential/api/utils/KotlinAdapter : net/minecraftforge/fml public abstract interface class gg/essential/api/utils/MinecraftUtils { @1.17.1-forge,1.18.2-forge,1.19.2-forge,1.19.3-forge,1.19.4-forge,1.20.1-forge,1.20.2-forge,1.20.4-forge public abstract fun getResourceImage (Lnet/minecraft/resources/ResourceLocation;)Ljava/awt/image/BufferedImage; - @1.16.2-fabric,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric + @1.16.2-fabric,1.17.1-fabric,1.18.1-fabric,1.18.2-fabric,1.19-fabric,1.19.2-fabric,1.19.3-fabric,1.19.4-fabric,1.20-fabric,1.20.1-fabric,1.20.2-fabric,1.20.4-fabric,1.20.6-fabric,1.21-fabric,1.21.2-fabric,1.21.4-fabric public abstract fun getResourceImage (Lnet/minecraft/util/Identifier;)Ljava/awt/image/BufferedImage; @1.12.2-forge,1.16.2-forge,1.8.9-forge public abstract fun getResourceImage (Lnet/minecraft/util/ResourceLocation;)Ljava/awt/image/BufferedImage; diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 0f84ae1..8bf14de 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { // Core Gui Libraries val ucMcVersion = when (platform.mcVersion) { + 12104 -> "1.21.2" 11802 -> "1.18.1" else -> mcVersionStr } diff --git a/build-logic/src/main/kotlin/essential/preprocessor.kt b/build-logic/src/main/kotlin/essential/preprocessor.kt index 644db54..5a9d21d 100644 --- a/build-logic/src/main/kotlin/essential/preprocessor.kt +++ b/build-logic/src/main/kotlin/essential/preprocessor.kt @@ -20,6 +20,7 @@ fun Project.configurePreprocessTree(versions: File) { configure { strictExtraMappings.set(true) + val fabric12104 = createNode("1.21.4-fabric", 12104, "yarn") val fabric12102 = createNode("1.21.2-fabric", 12102, "yarn") val fabric12100 = createNode("1.21-fabric", 12100, "yarn") val fabric12006 = createNode("1.20.6-fabric", 12006, "yarn") @@ -47,6 +48,7 @@ fun Project.configurePreprocessTree(versions: File) { val forge11202 = createNode("1.12.2-forge", 11202, "srg") val forge10809 = createNode("1.8.9-forge", 10809, "srg") + fabric12104.link(fabric12102, versions.resolve("1.21.4-1.21.2.txt")) fabric12102.link(fabric12100) fabric12100.link(fabric12006) fabric12006.link(fabric12004) diff --git a/build.gradle.kts b/build.gradle.kts index 890fea9..e72c9a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -127,6 +127,7 @@ dependencies { 12006 -> "0.97.8+1.20.6" 12100 -> "0.99.2+1.21" 12102 -> "0.106.0+1.21.2" + 12104 -> "0.110.0+1.21.4" else -> error("No fabric API version configured!") } include(modImplementation(fabricApi.module("fabric-api-base", fapiVersion))!!) diff --git a/changelog/release-1.3.5.4.md b/changelog/release-1.3.5.4.md new file mode 100644 index 0000000..9bd2690 --- /dev/null +++ b/changelog/release-1.3.5.4.md @@ -0,0 +1,14 @@ +Title: Bug Patch +Summary: Minor bug fixes + +## New Versions +- Added support for 1.21.4 Fabric + +## Bug Fixes +- Fixed some emotes not playing properly when cosmetics are disabled in the Essential settings +- Fixed some particles being unaffected by the "Show cosmetics" setting +- Fixed Essential nametag indicator not showing when sneaking on Minecraft 1.21.2 and newer +- Fixed Wardrobe mute / unmute button showing even for emotes which do not have sound + +## Compatibility +- Fixed not being able to join friends with ViaFabricPlus diff --git a/gradle.properties b/gradle.properties index bdebf09..84d68e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ essential.defaults.loom=0 -essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.16.7 +essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.16.9 kotlin.stdlib.default.dependency=false org.gradle.daemon=false org.gradle.parallel=true @@ -7,4 +7,4 @@ org.gradle.configureondemand=true org.gradle.parallel.threads=128 org.gradle.jvmargs=-Xmx16G minecraftVersion=11202 -version=1.3.5.3 +version=1.3.5.4 diff --git a/gui/essential/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/EquippedCosmeticsManager.kt b/gui/essential/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/EquippedCosmeticsManager.kt index 38e9dcc..f6a868f 100644 --- a/gui/essential/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/EquippedCosmeticsManager.kt +++ b/gui/essential/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/EquippedCosmeticsManager.kt @@ -12,6 +12,7 @@ package gg.essential.network.connectionmanager.cosmetics import com.google.common.collect.ImmutableMap +import com.google.common.collect.MapMaker import gg.essential.config.EssentialConfig import gg.essential.connectionmanager.common.packet.cosmetic.ServerCosmeticPlayerSettingsPacket import gg.essential.connectionmanager.common.packet.cosmetic.ServerCosmeticsUserEquippedPacket @@ -19,7 +20,10 @@ import gg.essential.connectionmanager.common.packet.cosmetic.outfit.ClientCosmet import gg.essential.connectionmanager.common.packet.cosmetic.outfit.ServerCosmeticOutfitSelectedResponsePacket import gg.essential.cosmetics.EquippedCosmetic import gg.essential.elementa.state.v2.ReferenceHolder +import gg.essential.gui.elementa.state.v2.MutableState import gg.essential.gui.elementa.state.v2.ReferenceHolderImpl +import gg.essential.gui.elementa.state.v2.State +import gg.essential.gui.elementa.state.v2.mutableStateOf import gg.essential.mod.Model import gg.essential.mod.Skin import gg.essential.mod.cosmetics.CAPE_DISABLED_COSMETIC_ID @@ -47,6 +51,8 @@ class EquippedCosmeticsManager( private val refHolder: ReferenceHolder = ReferenceHolderImpl() private val equippedCosmetics: MutableMap> = mutableMapOf() private val visibleCosmetics: MutableMap> = mutableMapOf() + private val visibleCosmeticsStates: MutableMap>> = + MapMaker().weakValues().makeMap() private val cosmeticSettings: MutableMap>> = mutableMapOf() private var ownCosmeticsVisible = true @@ -153,6 +159,7 @@ class EquippedCosmeticsManager( // Keep old instance if unchanged, so external comparisons against it can continue to take the fast path if (visibleCosmetics[playerId] != newValue) { visibleCosmetics[playerId] = newValue + visibleCosmeticsStates[playerId]?.set(newValue) } } @@ -160,7 +167,7 @@ class EquippedCosmeticsManager( val cosmeticIds = equippedCosmetics[playerId] ?: return ImmutableMap.of() val settings = cosmeticSettings[playerId] ?: emptyMap() - val cosmeticsHidden = !ownCosmeticsVisible && playerId == ownUuid + val cosmeticsHidden = EssentialConfig.disableCosmetics || (!ownCosmeticsVisible && playerId == ownUuid) fun isVisible(slot: CosmeticSlot): Boolean { if (slot == CosmeticSlot.ICON) { @@ -193,9 +200,17 @@ class EquippedCosmeticsManager( return visibleCosmetics[playerId] ?: ImmutableMap.of() } + fun getVisibleCosmeticsState(playerId: UUID): State> { + return visibleCosmeticsStates.getOrPut(playerId) { mutableStateOf(visibleCosmetics[playerId] ?: emptyMap()) } + } + override fun resetState() { equippedCosmetics.clear() visibleCosmetics.clear() + // Note: The visibleCosmeticsState map MUST NOT be cleared here because downstream states won't necessarily be + // re-created on reconnect but should still continue to receive future updates. + // It'll be cleaned up automatically as its entries become unused by virtue of having weak values. + visibleCosmeticsStates.values.forEach { it.set(emptyMap()) } cosmeticSettings.clear() } @@ -211,6 +226,8 @@ class EquippedCosmeticsManager( equippedCosmetics.remove(uuid) visibleCosmetics.remove(uuid) cosmeticSettings.remove(uuid) + // Note: The entry MUST NOT be removed from the visibleCosmeticsState map. See comment in [resetState]. + visibleCosmeticsStates[uuid]?.set(emptyMap()) } } } diff --git a/root.gradle.kts b/root.gradle.kts index ee4b6f6..cb31524 100644 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -13,6 +13,10 @@ import essential.* import gg.essential.gradle.util.* import net.fabricmc.loom.task.RemapJarTask +buildscript { + dependencies.constraints.classpath("com.github.replaymod:remap:63aef8561!!") +} + plugins { id("base") id("essential.utils") diff --git a/settings.gradle.kts b/settings.gradle.kts index f30fe9e..97d56e6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -102,6 +102,7 @@ listOf( "1.20.6-fabric", "1.21-fabric", "1.21.2-fabric", + "1.21.4-fabric", ).forEach { version -> include(":$version") project(":$version").apply { diff --git a/src/main/java/gg/essential/Essential.java b/src/main/java/gg/essential/Essential.java index 1492fe1..25936f7 100644 --- a/src/main/java/gg/essential/Essential.java +++ b/src/main/java/gg/essential/Essential.java @@ -21,7 +21,7 @@ import gg.essential.config.EssentialConfigApiImpl; import gg.essential.config.McEssentialConfig; import gg.essential.cosmetics.PlayerWearableManager; -import gg.essential.cosmetics.events.AnimationEffectHandler; +import gg.essential.cosmetics.events.CosmeticEventEmitter; import gg.essential.data.OnboardingData; import gg.essential.elementa.components.image.FileImageCache; import gg.essential.elementa.components.image.ImageCache; @@ -139,7 +139,7 @@ public class Essential implements EssentialAPI { private PlayerWearableManager playerWearableManager; private final GameProfileManager gameProfileManager = new GameProfileManager(); private final MojangSkinManager skinManager = new MojangSkinManager(gameProfileManager, () -> Wardrobe.getInstance() != null); - private AnimationEffectHandler animationEffectHandler; + private CosmeticEventEmitter cosmeticEventEmitter; private Map dynamicListeners = new HashMap<>(); private EssentialGameRules gameRules; @@ -304,8 +304,8 @@ private void init() { registerListener(new WindowedFullscreenHandler()); registerListener(connectionManager.getSpsManager()); registerListener(connectionManager.getSocialManager()); - registerListenerRequiresEssential(animationEffectHandler = new AnimationEffectHandler()); - registerListenerRequiresEssential((playerWearableManager = new PlayerWearableManager(connectionManager, connectionManager.getCosmeticsManager()))); + registerListenerRequiresEssential(cosmeticEventEmitter = new CosmeticEventEmitter()); + registerListener(playerWearableManager = new PlayerWearableManager(connectionManager, connectionManager.getCosmeticsManager())); registerListener(WikiToastListener.INSTANCE); if (!OptiFineUtil.isLoaded()) { registerListenerRequiresEssential(ZoomHandler.getInstance()); @@ -522,8 +522,8 @@ public gg.essential.api.data.OnboardingData onboardingData() { return OnboardingData.INSTANCE; } - public AnimationEffectHandler getAnimationEffectHandler() { - return animationEffectHandler; + public CosmeticEventEmitter getCosmeticEventEmitter() { + return cosmeticEventEmitter; } public OverlayManager getOverlayManager() { diff --git a/src/main/java/gg/essential/cosmetics/CosmeticsRenderState.java b/src/main/java/gg/essential/cosmetics/CosmeticsRenderState.java new file mode 100644 index 0000000..0e9e16b --- /dev/null +++ b/src/main/java/gg/essential/cosmetics/CosmeticsRenderState.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2024 ModCore Inc. All rights reserved. + * + * This code is part of ModCore Inc.'s Essential Mod repository and is protected + * under copyright registration # TX0009138511. For the full license, see: + * https://github.com/EssentialGG/Essential/blob/main/LICENSE + * + * You may not use, copy, reproduce, modify, sell, license, distribute, + * commercialize, or otherwise exploit, or create derivative works based + * upon, this file or any other in this repository, all of which is reserved by Essential. + */ +package gg.essential.cosmetics; + +import gg.essential.Essential; +import gg.essential.config.EssentialConfig; +import gg.essential.connectionmanager.common.enums.ProfileStatus; +import gg.essential.gui.common.EmulatedUI3DPlayer; +import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; +import gg.essential.model.backend.PlayerPose; +import gg.essential.model.util.PlayerPoseManager; +import gg.essential.network.connectionmanager.profile.ProfileManager; +import gg.essential.util.UIdentifier; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Set; +import java.util.UUID; + +import static gg.essential.util.UIdentifierKt.toMC; + +public interface CosmeticsRenderState { + @Nullable WearablesManager wearablesManager(); // TODO should capture render state only + @Nullable PlayerPoseManager poseManager(); // TODO should capture render state only + + Set blockedArmorSlots(); + + /** The player skin texture WITHOUT our skin mask applied (used by cosmetics/emotes to e.g. create fake limbs). */ + ResourceLocation skinTexture(); + + ResourceLocation emissiveCapeTexture(); + + boolean onlineIndicator(); + + boolean isSneaking(); + + void setRenderedPose(PlayerPose pose); + void setPoseModified(boolean poseModified); + void setSuppressedArmor(boolean[] slots); + + /** + * Implementation which delegates to the underlying entity. + * Cheap to construct but not thread safe. + * Used primarily on older MC versions and on non-standard rendering paths. + */ + final class Live implements CosmeticsRenderState { + private final AbstractClientPlayer player; + + public Live(AbstractClientPlayer player) { + this.player = player; + } + + private AbstractClientPlayerExt playerExt() { + return (AbstractClientPlayerExt) player; + } + + @Override + public WearablesManager wearablesManager() { + return EssentialModelRenderer.shouldRender(player) ? playerExt().getWearablesManager() : null; + } + + @Override + public PlayerPoseManager poseManager() { + if (EssentialConfig.INSTANCE.getDisableEmotes() && !(player instanceof EmulatedUI3DPlayer.EmulatedPlayer)) { + return null; + } + return playerExt().getPoseManager(); + } + + @Override + public Set blockedArmorSlots() { + if (!EssentialModelRenderer.shouldRender(player)) { + return Collections.emptySet(); + } + int armorHidingSetting = ArmorRenderingUtil.getCosmeticArmorSetting(player); + if (armorHidingSetting != 1) { + return Collections.emptySet(); + } + return playerExt().getCosmeticsState().getPartsEquipped(); + } + + @Override + public ResourceLocation skinTexture() { + //#if MC>=12002 + //$$ return player.getSkinTextures().texture(); + //#else + return player.getLocationSkin(); + //#endif + } + + @Override + public ResourceLocation emissiveCapeTexture() { + if (!EssentialModelRenderer.shouldRender(player)) { + return null; + } + UIdentifier identifier = playerExt().getEmissiveCapeTexture(); + if (identifier == null) { + return null; + } + return toMC(identifier); + } + + @Override + public boolean onlineIndicator() { + if (!EssentialConfig.INSTANCE.getShowEssentialIndicatorOnNametag()) return false; + ProfileManager profileManager = Essential.getInstance().getConnectionManager().getProfileManager(); + UUID uuid = player.getGameProfile().getId(); + ProfileStatus status = profileManager.getStatus(uuid); + return status != ProfileStatus.OFFLINE; + } + + @Override + public boolean isSneaking() { + return player.isSneaking(); + } + + @Override + public void setRenderedPose(PlayerPose pose) { + playerExt().setRenderedPose(pose); + } + + @Override + public void setPoseModified(boolean poseModified) { + playerExt().setPoseModified(poseModified); + } + + @Override + public void setSuppressedArmor(boolean[] slots) { + System.arraycopy(slots, 0, playerExt().wasArmorRenderingSuppressed(), 0, slots.length); + } + } + + /** + * Implementation which snapshots the state of the entity on {@link #update}. + * Relatively expensive to construct but safe to use from any thread afterwards. + */ + final class Snapshot implements CosmeticsRenderState { + private Live live; // only for smuggling the rendered player pose out of the renderer! + private WearablesManager wearablesManager; + private PlayerPoseManager poseManager; + private Set blockedArmorSlots = Collections.emptySet(); + private ResourceLocation skinTexture; + private ResourceLocation emissiveCapeTexture; + private boolean onlineIndicator; + private boolean isSneaking; + + @Override + public WearablesManager wearablesManager() { + return wearablesManager; + } + + @Override + public PlayerPoseManager poseManager() { + return poseManager; + } + + @Override + public Set blockedArmorSlots() { + return blockedArmorSlots; + } + + @Override + public ResourceLocation skinTexture() { + return skinTexture; + } + + @Override + public ResourceLocation emissiveCapeTexture() { + return emissiveCapeTexture; + } + + @Override + public boolean onlineIndicator() { + return onlineIndicator; + } + + @Override + public boolean isSneaking() { + return isSneaking; + } + + public void update(AbstractClientPlayer entity) { + Live live = new Live(entity); + this.live = live; + wearablesManager = live.wearablesManager(); + poseManager = live.poseManager(); + blockedArmorSlots = live.blockedArmorSlots(); + skinTexture = live.skinTexture(); + emissiveCapeTexture = live.emissiveCapeTexture(); + onlineIndicator = live.onlineIndicator(); + isSneaking = live.isSneaking(); + } + + @Override + public void setRenderedPose(PlayerPose pose) { + Live live = this.live; + if (live != null) { + live.setRenderedPose(pose); + } + } + + @Override + public void setPoseModified(boolean poseModified) { + Live live = this.live; + if (live != null) { + live.setPoseModified(poseModified); + } + } + + @Override + public void setSuppressedArmor(boolean[] slots) { + Live live = this.live; + if (live != null) { + live.setSuppressedArmor(slots); + } + } + } +} diff --git a/src/main/java/gg/essential/cosmetics/EssentialModelRenderer.java b/src/main/java/gg/essential/cosmetics/EssentialModelRenderer.java index 3b40989..6d222e4 100644 --- a/src/main/java/gg/essential/cosmetics/EssentialModelRenderer.java +++ b/src/main/java/gg/essential/cosmetics/EssentialModelRenderer.java @@ -11,31 +11,18 @@ */ package gg.essential.cosmetics; -import gg.essential.config.EssentialConfig; -import gg.essential.gui.common.EmulatedUI3DPlayer; -import gg.essential.gui.elementa.state.v2.State; -import gg.essential.handlers.EssentialSoundManager; -import gg.essential.mixins.ext.client.ParticleSystemHolder; import gg.essential.model.EnumPart; -import gg.essential.model.ModelAnimationState; import gg.essential.model.ModelInstance; -import gg.essential.model.ParticleSystem; -import gg.essential.model.PlayerMolangQuery; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.RenderBackend; import gg.essential.model.backend.minecraft.MinecraftRenderBackend; import gg.essential.model.backend.minecraft.PlayerPoseKt; import gg.essential.network.cosmetics.Cosmetic; import gg.essential.universal.UMatrixStack; -import gg.essential.universal.UMinecraft; -import kotlin.Unit; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.RenderPlayer; import net.minecraft.client.renderer.entity.layers.LayerRenderer; -import gg.essential.data.OnboardingData; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; -import net.minecraft.world.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,7 +30,6 @@ import static gg.essential.cosmetics.EssentialModelRendererKt.flush; import static gg.essential.cosmetics.EssentialModelRendererKt.renderForHoverOutline; -import static gg.essential.gui.elementa.state.v2.StateKt.stateOf; import static gg.essential.util.ExtensionsKt.toCommon; //#if MC>=12102 @@ -82,68 +68,31 @@ public EssentialModelRenderer(RenderPlayer playerRenderer) { this.playerRenderer = playerRenderer; } - // this is modified in Patcher to take Entity Render Distance into consideration, don't remove or rename - public static boolean cosmeticsShouldRender(AbstractClientPlayer player) { - if (!EssentialConfig.INSTANCE.getEssentialEnabled()) { - return false; - } - - if (((AbstractClientPlayerExt) player).getCosmeticsSource().getShouldOverrideRenderCosmeticsCheck()) { - return true; - } - - if (EssentialConfig.INSTANCE.getHideCosmeticsWhenServerOverridesSkin() - && ((AbstractClientPlayerExt) player).isSkinOverrodeByServer()) { - return false; - } - - if (EssentialConfig.INSTANCE.getDisableCosmetics()) { - return false; - } - + public static boolean shouldRender(AbstractClientPlayer player) { if (suppressCosmeticRendering) { return false; } - // If a 3rd party mod has an emulated player which doesn't override the client fields, mc.player will be null while rendering their player - if (UMinecraft.getMinecraft().player != null) { - final double distance = player.getDistanceToEntity(UMinecraft.getMinecraft().player); - if (distance >= 4096D) { - return false; - } - } return !player.isInvisible() && !player.isSpectator(); } public void render( UMatrixStack matrixStack, RenderBackend.VertexConsumerProvider vertexConsumerProvider, - @Nullable Set parts, - @NotNull AbstractClientPlayer player + @NotNull CosmeticsRenderState cState, + @Nullable Set parts ) { - if (!OnboardingData.hasAcceptedTos() || !EssentialConfig.INSTANCE.getEssentialEnabled()) { - return; - } - - final AbstractClientPlayerExt abstractClientPlayerExt = (AbstractClientPlayerExt) player; - if (!cosmeticsShouldRender(player)) { + WearablesManager wearablesManager = cState.wearablesManager(); + if (wearablesManager == null) { return; } - - WearablesManager wearablesManager = abstractClientPlayerExt.getWearablesManager(); Map models = wearablesManager.getModels(); if (models.isEmpty()) { return; } PlayerPose pose = PlayerPoseKt.toPose(playerRenderer); - RenderBackend.Texture skin = new MinecraftRenderBackend.SkinTexture( - //#if MC>=12002 - //$$ player.getSkinTextures().texture() - //#else - player.getLocationSkin() - //#endif - ); + RenderBackend.Texture skin = new MinecraftRenderBackend.SkinTexture(cState.skinTexture()); matrixStack.push(); @@ -161,7 +110,7 @@ public void render( //#endif //#if MC<11400 - if (player.isSneaking() && parts == null) { + if (cState.isSneaking() && parts == null) { matrixStack.translate(0.0F, 0.2F, 0.0F); // from LayerCustomHead } //#endif @@ -189,56 +138,17 @@ public void render( UGraphics.GL.popMatrix(); //#endif - //#if MC>=12000 - //$$ World world = player.clientWorld; - //#else - World world = player.world; - //#endif - ParticleSystem particleSystem; - if (player instanceof EmulatedUI3DPlayer.EmulatedPlayer) { - particleSystem = ((EmulatedUI3DPlayer.EmulatedPlayer) player).getParticleSystem(); - } else if (world instanceof ParticleSystemHolder) { - particleSystem = ((ParticleSystemHolder) world).getParticleSystem(); - } else { - particleSystem = null; - } - wearablesManager.collectEvents(event -> { - if (event instanceof ModelAnimationState.ParticleEvent) { - if (particleSystem != null) { - particleSystem.spawn((ModelAnimationState.ParticleEvent) event); - } - } else if (event instanceof ModelAnimationState.SoundEvent) { - boolean forceGlobal; - State volume; - boolean enforceEmoteSoundSettings; - if (player instanceof EmulatedUI3DPlayer.EmulatedPlayer) { - EmulatedUI3DPlayer component = ((EmulatedUI3DPlayer.EmulatedPlayer) player).getEmulatedUI3DPlayer(); - if (!component.getSounds().getUntracked()) { - return Unit.INSTANCE; - } - forceGlobal = true; - volume = component.getSoundsVolume(); - enforceEmoteSoundSettings = false; - } else { - forceGlobal = false; - volume = stateOf(1f); - enforceEmoteSoundSettings = true; - } - EssentialSoundManager.INSTANCE.playSound((ModelAnimationState.SoundEvent) event, forceGlobal, volume, enforceEmoteSoundSettings); - } - return Unit.INSTANCE; - }); - - abstractClientPlayerExt.setLastCosmeticsUpdateTime(new PlayerMolangQuery(player).getLifeTime()); + cState.setRenderedPose(pose); } @Override //#if MC>=11400 //#if MC>=12102 //$$ public void render(MatrixStack vMatrixStack, VertexConsumerProvider buffer, int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) { - //$$ AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); //#else //$$ public void render(@NotNull MatrixStack vMatrixStack, @NotNull IRenderTypeBuffer buffer, int light, @NotNull AbstractClientPlayerEntity player, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { + //$$ CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); //#endif //$$ UMatrixStack matrixStack = new UMatrixStack(vMatrixStack); //$$ RenderBackend.VertexConsumerProvider vertexConsumerProvider = new MinecraftRenderBackend.VertexConsumerProvider(buffer, light); @@ -246,8 +156,9 @@ public void render( public void doRenderLayer(@NotNull AbstractClientPlayer player, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale) { UMatrixStack matrixStack = new UMatrixStack(); RenderBackend.VertexConsumerProvider vertexConsumerProvider = new MinecraftRenderBackend.VertexConsumerProvider(); + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); //#endif - render(matrixStack, vertexConsumerProvider, null, player); + render(matrixStack, vertexConsumerProvider, cState, null); } //#if MC < 11400 diff --git a/src/main/java/gg/essential/cosmetics/PlayerWearableManager.java b/src/main/java/gg/essential/cosmetics/PlayerWearableManager.java index 100d438..3ca80d9 100644 --- a/src/main/java/gg/essential/cosmetics/PlayerWearableManager.java +++ b/src/main/java/gg/essential/cosmetics/PlayerWearableManager.java @@ -11,12 +11,11 @@ */ package gg.essential.cosmetics; -import com.google.common.collect.ImmutableMap; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import gg.essential.api.cosmetics.RenderCosmetic; -import gg.essential.cosmetics.source.CosmeticsSource; import gg.essential.event.entity.PlayerTickEvent; import gg.essential.gui.common.EmulatedUI3DPlayer; +import gg.essential.gui.elementa.state.v2.State; import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; import gg.essential.mod.Model; @@ -80,7 +79,7 @@ public void tick(PlayerTickEvent tickEvent) { private void updateCosmetics(AbstractClientPlayer player) { AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - CosmeticsSource cosmeticsSource = playerExt.getCosmeticsSource(); + State> cosmeticsSource = playerExt.getCosmeticsSource(); CosmeticsState oldState = playerExt.getCosmeticsState(); //#if MC>=12002 @@ -90,7 +89,8 @@ private void updateCosmetics(AbstractClientPlayer player) { //#endif Model oldSkinType = oldState.getSkinType(); - ImmutableMap newCosmetics = cosmeticsSource.getCosmetics(); + // FIXME should use State effect instead of checking every tick + Map newCosmetics = cosmeticsSource.getUntracked(); Map oldCosmetics = oldState.getCosmetics(); Set newArmour = getArmourFromPlayer(player); Set oldArmour = oldState.getArmor(); diff --git a/src/main/java/gg/essential/cosmetics/events/CosmeticEventDispatcher.java b/src/main/java/gg/essential/cosmetics/events/CosmeticEventDispatcher.java new file mode 100644 index 0000000..f11fc15 --- /dev/null +++ b/src/main/java/gg/essential/cosmetics/events/CosmeticEventDispatcher.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 ModCore Inc. All rights reserved. + * + * This code is part of ModCore Inc.'s Essential Mod repository and is protected + * under copyright registration # TX0009138511. For the full license, see: + * https://github.com/EssentialGG/Essential/blob/main/LICENSE + * + * You may not use, copy, reproduce, modify, sell, license, distribute, + * commercialize, or otherwise exploit, or create derivative works based + * upon, this file or any other in this repository, all of which is reserved by Essential. + */ +package gg.essential.cosmetics.events; + +import gg.essential.cosmetics.WearablesManager; +import gg.essential.gui.common.EmulatedUI3DPlayer; +import gg.essential.gui.elementa.state.v2.State; +import gg.essential.handlers.EssentialSoundManager; +import gg.essential.mixins.ext.client.ParticleSystemHolder; +import gg.essential.model.ModelAnimationState; +import gg.essential.model.ParticleSystem; +import kotlin.Unit; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.world.World; + +import static gg.essential.gui.elementa.state.v2.StateKt.stateOf; + +public class CosmeticEventDispatcher { + public static void dispatchEvents(AbstractClientPlayer player, WearablesManager wearablesManager) { + //#if MC>=12000 + //$$ World world = player.clientWorld; + //#else + World world = player.world; + //#endif + ParticleSystem particleSystem; + if (player instanceof EmulatedUI3DPlayer.EmulatedPlayer) { + particleSystem = ((EmulatedUI3DPlayer.EmulatedPlayer) player).getParticleSystem(); + } else if (world instanceof ParticleSystemHolder) { + particleSystem = ((ParticleSystemHolder) world).getParticleSystem(); + } else { + particleSystem = null; + } + wearablesManager.collectEvents(event -> { + if (event instanceof ModelAnimationState.ParticleEvent) { + if (particleSystem != null) { + particleSystem.spawn((ModelAnimationState.ParticleEvent) event); + } + } else if (event instanceof ModelAnimationState.SoundEvent) { + boolean forceGlobal; + State volume; + boolean enforceEmoteSoundSettings; + if (player instanceof EmulatedUI3DPlayer.EmulatedPlayer) { + EmulatedUI3DPlayer component = ((EmulatedUI3DPlayer.EmulatedPlayer) player).getEmulatedUI3DPlayer(); + if (!component.getSounds().getUntracked()) { + return Unit.INSTANCE; + } + forceGlobal = true; + volume = component.getSoundsVolume(); + enforceEmoteSoundSettings = false; + } else { + forceGlobal = false; + volume = stateOf(1f); + enforceEmoteSoundSettings = true; + } + EssentialSoundManager.INSTANCE.playSound((ModelAnimationState.SoundEvent) event, forceGlobal, volume, enforceEmoteSoundSettings); + } + return Unit.INSTANCE; + }); + } +} diff --git a/src/main/java/gg/essential/cosmetics/events/AnimationEffectHandler.java b/src/main/java/gg/essential/cosmetics/events/CosmeticEventEmitter.java similarity index 88% rename from src/main/java/gg/essential/cosmetics/events/AnimationEffectHandler.java rename to src/main/java/gg/essential/cosmetics/events/CosmeticEventEmitter.java index bf9a13c..1da4436 100644 --- a/src/main/java/gg/essential/cosmetics/events/AnimationEffectHandler.java +++ b/src/main/java/gg/essential/cosmetics/events/CosmeticEventEmitter.java @@ -11,8 +11,6 @@ */ package gg.essential.cosmetics.events; -import gg.essential.cosmetics.source.CosmeticsSource; -import gg.essential.cosmetics.source.LiveCosmeticsSource; import gg.essential.mod.cosmetics.CosmeticSlot; import gg.essential.model.ModelInstance; import gg.essential.network.cosmetics.Cosmetic; @@ -27,9 +25,9 @@ import java.util.Map; import java.util.UUID; -public class AnimationEffectHandler { +public class CosmeticEventEmitter { - public AnimationEffectHandler() { + public CosmeticEventEmitter() { } @@ -66,8 +64,7 @@ private AbstractClientPlayerExt findPlayerByCosmeticsSourceUuid(WorldClient worl //#endif if (player instanceof AbstractClientPlayerExt) { AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - CosmeticsSource cosmeticsSource = playerExt.getCosmeticsSource(); - if (cosmeticsSource instanceof LiveCosmeticsSource && ((LiveCosmeticsSource) cosmeticsSource).getUuid().equals(uuid)) { + if (playerExt.getCosmeticsSourceUuid().equals(uuid)) { return playerExt; } } diff --git a/src/main/java/gg/essential/cosmetics/skinmask/MaskedSkinProvider.java b/src/main/java/gg/essential/cosmetics/skinmask/MaskedSkinProvider.java index ef7b2ef..db231d6 100644 --- a/src/main/java/gg/essential/cosmetics/skinmask/MaskedSkinProvider.java +++ b/src/main/java/gg/essential/cosmetics/skinmask/MaskedSkinProvider.java @@ -16,7 +16,6 @@ import gg.essential.lib.caffeine.cache.RemovalCause; import gg.essential.lib.caffeine.cache.RemovalListener; import gg.essential.lib.caffeine.cache.Scheduler; -import gg.essential.mixins.ext.client.renderer.PlayerSkinTextureExt; import gg.essential.universal.UImage; import gg.essential.universal.UMinecraft; import gg.essential.util.ExtensionsKt; @@ -25,7 +24,7 @@ import gg.essential.util.image.bitmap.Bitmap; import gg.essential.util.image.bitmap.UImageBitmap; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ThreadDownloadImageData; +import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.ITextureObject; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.resources.DefaultPlayerSkin; @@ -39,6 +38,14 @@ import static gg.essential.util.image.bitmap.GuiEssentialExtensionsKt.toUImage; +//#if MC>=12104 +//$$ import net.minecraft.client.texture.NativeImage; +//$$ import net.minecraft.client.texture.NativeImageBackedTexture; +//#else +import gg.essential.mixins.ext.client.renderer.PlayerSkinTextureExt; +import net.minecraft.client.renderer.ThreadDownloadImageData; +//#endif + public class MaskedSkinProvider { private static final DynamicTextureManager dynamicTextureManager = new DynamicTextureManager(); @@ -72,6 +79,18 @@ public ResourceLocation provide(ResourceLocation skin, SkinMask config) { return null; // if not, then we cannot yet apply the mask } + //#if MC>=12104 + //$$ if (!(skinTexture instanceof NativeImageBackedTexture)) { + //$$ return null; + //$$ } + //$$ + //$$ NativeImage skinNativeImage = ((NativeImageBackedTexture) skinTexture).getImage(); + //$$ if (skinNativeImage == null) { + //$$ return null; + //$$ } + //$$ + //$$ UImage skinImage = new UImage(skinNativeImage); + //#else // Sanity check, this should always be the case at least for vanilla if (!(skinTexture instanceof PlayerSkinTextureExt)) { return null; // this is bad, nothing we can do @@ -86,13 +105,18 @@ public ResourceLocation provide(ResourceLocation skin, SkinMask config) { if (skinImage == null) { return null; // in that case, we cannot yet apply the mask } + //#endif // All good, compute the masked skin, store it for later, and register it with MC Bitmap generatedTexture = config.apply(new UImageBitmap(skinImage)); generatedSkin = skin; generatedConfig = config; generatedId = dynamicTextureManager.generateUniqueId(generatedSkin.toString().replace(':', '/')); + //#if MC>=12104 + //$$ dynamicTextureManager.register(this, generatedId, new NativeImageBackedTexture(toUImage(generatedTexture).getNativeImage())); + //#else dynamicTextureManager.register(this, generatedId, new MaskedSkinTexture(toUImage(generatedTexture))); + //#endif return generatedId; } @@ -117,7 +141,7 @@ public ResourceLocation generateUniqueId(String name) { return HelpersKt.identifier("essential", String.format(Locale.ROOT, "masked_skins/%s/%d", name, nextUniqueId++)); } - public void register(MaskedSkinProvider provider, ResourceLocation id, MaskedSkinTexture texture) { + public void register(MaskedSkinProvider provider, ResourceLocation id, AbstractTexture texture) { Minecraft.getMinecraft().getTextureManager().loadTexture(id, texture); loaded.put(provider, id); } @@ -135,6 +159,7 @@ public void onRemoval(@Nullable MaskedSkinProvider provider, @Nullable ResourceL } } + //#if MC<12104 // Intentionally using a class which extends the vanilla skin texture class for better compatibility. private static class MaskedSkinTexture extends ThreadDownloadImageData { public MaskedSkinTexture(UImage image) { @@ -157,5 +182,6 @@ protected void loadTextureFromServer() { } //#endif } + //#endif } diff --git a/src/main/java/gg/essential/cosmetics/source/ConfigurableCosmeticsSource.java b/src/main/java/gg/essential/cosmetics/source/ConfigurableCosmeticsSource.java deleted file mode 100644 index 8702708..0000000 --- a/src/main/java/gg/essential/cosmetics/source/ConfigurableCosmeticsSource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2024 ModCore Inc. All rights reserved. - * - * This code is part of ModCore Inc.'s Essential Mod repository and is protected - * under copyright registration # TX0009138511. For the full license, see: - * https://github.com/EssentialGG/Essential/blob/main/LICENSE - * - * You may not use, copy, reproduce, modify, sell, license, distribute, - * commercialize, or otherwise exploit, or create derivative works based - * upon, this file or any other in this repository, all of which is reserved by Essential. - */ -package gg.essential.cosmetics.source; - -import com.google.common.collect.ImmutableMap; -import gg.essential.cosmetics.EquippedCosmetic; -import gg.essential.mod.cosmetics.CosmeticSlot; -import org.jetbrains.annotations.NotNull; - -public class ConfigurableCosmeticsSource implements CosmeticsSource { - - private ImmutableMap cosmetics = ImmutableMap.of(); - - private boolean shouldOverrideRenderCosmeticsCheck = false; - - public void setCosmetics(ImmutableMap cosmetics) { - this.cosmetics = cosmetics; - } - - public void setShouldOverrideRenderCosmeticsCheck(boolean shouldOverrideRenderCosmeticsCheck) { - this.shouldOverrideRenderCosmeticsCheck = shouldOverrideRenderCosmeticsCheck; - } - - @Override - @NotNull - public ImmutableMap getCosmetics() { - return this.cosmetics; - } - - @Override - public boolean getShouldOverrideRenderCosmeticsCheck() { - return this.shouldOverrideRenderCosmeticsCheck; - } -} diff --git a/src/main/java/gg/essential/cosmetics/source/LiveCosmeticsSource.java b/src/main/java/gg/essential/cosmetics/source/LiveCosmeticsSource.java deleted file mode 100644 index 9f7b301..0000000 --- a/src/main/java/gg/essential/cosmetics/source/LiveCosmeticsSource.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024 ModCore Inc. All rights reserved. - * - * This code is part of ModCore Inc.'s Essential Mod repository and is protected - * under copyright registration # TX0009138511. For the full license, see: - * https://github.com/EssentialGG/Essential/blob/main/LICENSE - * - * You may not use, copy, reproduce, modify, sell, license, distribute, - * commercialize, or otherwise exploit, or create derivative works based - * upon, this file or any other in this repository, all of which is reserved by Essential. - */ -package gg.essential.cosmetics.source; - -import com.google.common.collect.ImmutableMap; -import gg.essential.mod.cosmetics.CosmeticSlot; -import gg.essential.network.connectionmanager.cosmetics.CosmeticsManager; -import gg.essential.cosmetics.EquippedCosmetic; -import org.jetbrains.annotations.NotNull; - -import java.util.UUID; - -public class LiveCosmeticsSource implements CosmeticsSource { - - private final CosmeticsManager cosmeticsManager; - private final UUID uuid; - - public LiveCosmeticsSource(CosmeticsManager cosmeticsManager, UUID uuid) { - this.cosmeticsManager = cosmeticsManager; - this.uuid = uuid; - } - - @NotNull - public UUID getUuid() { - return uuid; - } - - @Override - @NotNull - public ImmutableMap getCosmetics() { - return this.cosmeticsManager.getVisibleCosmetics(this.uuid); - } - - @Override - public boolean getShouldOverrideRenderCosmeticsCheck() { - return false; - } -} diff --git a/src/main/java/gg/essential/handlers/NetworkSubscriptionStateHandler.java b/src/main/java/gg/essential/handlers/NetworkSubscriptionStateHandler.java index 21b8501..303604e 100644 --- a/src/main/java/gg/essential/handlers/NetworkSubscriptionStateHandler.java +++ b/src/main/java/gg/essential/handlers/NetworkSubscriptionStateHandler.java @@ -12,8 +12,6 @@ package gg.essential.handlers; import gg.essential.Essential; -import gg.essential.cosmetics.source.CosmeticsSource; -import gg.essential.cosmetics.source.LiveCosmeticsSource; import gg.essential.data.OnboardingData; import gg.essential.event.client.ClientTickEvent; import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; @@ -56,10 +54,7 @@ public void tick(ClientTickEvent tickEvent) { //#endif currentTickList.add(playerEntity.getUniqueID()); if (playerEntity instanceof AbstractClientPlayerExt) { - CosmeticsSource cosmeticsSource = ((AbstractClientPlayerExt) playerEntity).getCosmeticsSource(); - if (cosmeticsSource instanceof LiveCosmeticsSource) { - currentTickList.add(((LiveCosmeticsSource) cosmeticsSource).getUuid()); - } + currentTickList.add(((AbstractClientPlayerExt) playerEntity).getCosmeticsSourceUuid()); } } } diff --git a/src/main/java/gg/essential/handlers/OnlineIndicator.java b/src/main/java/gg/essential/handlers/OnlineIndicator.java index 00ff607..9e2e534 100644 --- a/src/main/java/gg/essential/handlers/OnlineIndicator.java +++ b/src/main/java/gg/essential/handlers/OnlineIndicator.java @@ -15,6 +15,7 @@ import gg.essential.Essential; import gg.essential.config.EssentialConfig; import gg.essential.connectionmanager.common.enums.ProfileStatus; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.data.OnboardingData; import gg.essential.gui.EssentialPalette; import gg.essential.mixins.ext.client.network.NetHandlerPlayClientExt; @@ -30,7 +31,6 @@ import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.network.NetworkPlayerInfo; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.text.ITextComponent; //#if MC>=11800 @@ -50,11 +50,15 @@ import static gg.essential.elementa.utils.ExtensionsKt.withAlpha; public class OnlineIndicator { + //#if MC!=11202 + //$$ public static final ThreadLocal currentlyDrawingEntityName = new ThreadLocal<>(); + //#else /** * Set while {@link #currentlyDrawingEntityName()}. * Only useful for 1.12.2, all other versions get the entity via regular method arguments. */ public static Entity nametagEntity; + //#endif /** * When called from a {@code drawNameplate} mixin, returns whether this nameplate is the primary name nameplate, as @@ -62,7 +66,11 @@ public class OnlineIndicator { * @return {@code true} if this is the primary name nameplate */ public static boolean currentlyDrawingEntityName() { + //#if MC!=11202 + //$$ return currentlyDrawingEntityName.get(); + //#else return nametagEntity != null; + //#endif } public static void drawNametagIndicator( @@ -70,32 +78,32 @@ public static void drawNametagIndicator( //#if MC>=11600 //$$ IRenderTypeBuffer vertexConsumerProvider, //#endif - Entity entity, + CosmeticsRenderState cState, String str, int light ) { - if (!OnboardingData.hasAcceptedTos() || !EssentialConfig.INSTANCE.getShowEssentialIndicatorOnNametag() || !(entity instanceof EntityPlayer)) + if (!cState.onlineIndicator()) { return; + } - ConnectionManager connectionManager = Essential.getInstance().getConnectionManager(); - ProfileManager profileManager = connectionManager.getProfileManager(); - UUID playerId = ((EntityPlayer) entity).getGameProfile().getId(); - ProfileStatus status = profileManager.getStatus(playerId); - if (status == ProfileStatus.OFFLINE) return; - - boolean alwaysOnTop = !entity.isSneaking(); + boolean alwaysOnTop = !cState.isSneaking(); int stringWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(str); + //#if MC>=12102 + //$$ float vanillaX = (float)(-stringWidth) / 2f; + //#else + float vanillaX = -(float)(stringWidth / 2); + //#endif Color color = EssentialPalette.ESSENTIAL_BLUE; //#if MC<11600 UGraphics.enableAlpha(); UGraphics.disableLighting(); UGraphics.depthMask(false); //#endif - float x1 = -(stringWidth >> 1) - 11; + float x1 = vanillaX - 11; float y1 = -1; - float x2 = -(stringWidth >> 1) - 1; + float x2 = vanillaX - 1; float y2 = getDiamondBackgroundYMin(); //#if MC<11600 @@ -108,7 +116,9 @@ public static void drawNametagIndicator( UGraphics.tryBlendFuncSeparate(770, 771, 1,0); int backgroundOpacity = getTextBackgroundOpacity(); - //#if MC>=11600 + //#if MC>=12102 + //$$ double z = -0.01; + //#elseif MC>=11600 //$$ double z = 0.01; //#else double z = 0; @@ -127,7 +137,7 @@ public static void drawNametagIndicator( vertexConsumer.pos(matrixStack, x2, y1, z).color(0, 0, 0, backgroundOpacity).tex(0, 0).light(light).endVertex(); float diamondCenter = (y1 + y2) / 2 + getDiamondYOffset(); - Diamond.drawDiamond(matrixStack, vertexConsumer, 6, -(stringWidth >> 1) + -6, diamondCenter, withAlpha(color,32).getRGB(), light); + Diamond.drawDiamond(matrixStack, vertexConsumer, 6, vanillaX - 6, diamondCenter, withAlpha(color,32).getRGB(), light); // On 1.16+, we get a vertex provider from the entity rendering pipeline, so we don't need to draw anything // manually like we do on older versions. @@ -149,7 +159,7 @@ public static void drawNametagIndicator( //#else vertexConsumer = TextRenderTypeVertexConsumer.create(buffer); //#endif - Diamond.drawDiamond(matrixStack, vertexConsumer, 6, -(stringWidth >> 1) + -6, diamondCenter, color.getRGB(), light); + Diamond.drawDiamond(matrixStack, vertexConsumer, 6, vanillaX - 6, diamondCenter, color.getRGB(), light); //#if MC<11600 buffer.drawDirect(); diff --git a/src/main/java/gg/essential/mixins/impl/client/entity/AbstractClientPlayerExt.java b/src/main/java/gg/essential/mixins/impl/client/entity/AbstractClientPlayerExt.java index e37e18e..a765f9d 100644 --- a/src/main/java/gg/essential/mixins/impl/client/entity/AbstractClientPlayerExt.java +++ b/src/main/java/gg/essential/mixins/impl/client/entity/AbstractClientPlayerExt.java @@ -12,8 +12,11 @@ package gg.essential.mixins.impl.client.entity; import gg.essential.cosmetics.CosmeticsState; +import gg.essential.cosmetics.EquippedCosmetic; import gg.essential.cosmetics.WearablesManager; -import gg.essential.cosmetics.source.CosmeticsSource; +import gg.essential.gui.elementa.state.v2.State; +import gg.essential.mod.cosmetics.CosmeticSlot; +import gg.essential.model.backend.PlayerPose; import gg.essential.model.util.PlayerPoseManager; import gg.essential.util.UIdentifier; import kotlin.Pair; @@ -22,11 +25,15 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; +import java.util.UUID; public interface AbstractClientPlayerExt { - CosmeticsSource getCosmeticsSource(); + UUID getCosmeticsSourceUuid(); - void setCosmeticsSource(CosmeticsSource source); + State> getCosmeticsSource(); + + void setCosmeticsSource(State> source); @NotNull WearablesManager getWearablesManager(); @@ -39,12 +46,6 @@ public interface AbstractClientPlayerExt { ResourceLocation applyEssentialCosmeticsMask(ResourceLocation skin); - boolean isSkinOverrodeByServer(); - - void assumeArmorRenderingSuppressed(); - - void armorRenderingNotSuppressed(int slot); - boolean[] wasArmorRenderingSuppressed(); @NotNull @@ -54,7 +55,6 @@ public interface AbstractClientPlayerExt { void setPoseModified(boolean poseModified); - float getLastCosmeticsUpdateTime(); - - void setLastCosmeticsUpdateTime(float time); + @Nullable PlayerPose getRenderedPose(); + void setRenderedPose(PlayerPose pose); } diff --git a/src/main/java/gg/essential/mixins/impl/client/model/ModelBipedUtil.java b/src/main/java/gg/essential/mixins/impl/client/model/ModelBipedUtil.java index 161dfd1..783558b 100644 --- a/src/main/java/gg/essential/mixins/impl/client/model/ModelBipedUtil.java +++ b/src/main/java/gg/essential/mixins/impl/client/model/ModelBipedUtil.java @@ -11,16 +11,12 @@ */ package gg.essential.mixins.impl.client.model; -import gg.essential.config.EssentialConfig; -import gg.essential.cosmetics.WearablesManager; -import gg.essential.gui.common.EmulatedUI3DPlayer; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.gui.emotes.EmoteWheel; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.PlayerPoseKt; import gg.essential.model.util.PlayerPoseManager; import net.minecraft.client.model.ModelBiped; -import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class ModelBipedUtil { @@ -46,30 +42,23 @@ public static void resetPose(ModelBiped model) { } } - public static void applyPoseTransform(ModelBiped model, Entity entity) { - if (!(entity instanceof AbstractClientPlayerExt)) return; + public static void applyPoseTransform(ModelBiped model, CosmeticsRenderState cState) { if (EmoteWheel.isPlayerArmRendering) return; - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entity; - playerExt.setPoseModified(false); + cState.setPoseModified(false); - if (EssentialConfig.INSTANCE.getDisableEmotes() && !(entity instanceof EmulatedUI3DPlayer.EmulatedPlayer)) - return; - - WearablesManager wearablesManager = playerExt.getWearablesManager(); - PlayerPoseManager poseManager = playerExt.getPoseManager(); - - poseManager.update(wearablesManager); + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager == null) return; PlayerPose basePose = PlayerPoseKt.toPose(model); - PlayerPose transformedPose = poseManager.computePose(wearablesManager, basePose); + PlayerPose transformedPose = poseManager.computePose(cState.wearablesManager(), basePose); if (basePose.equals(transformedPose)) { return; } PlayerPoseKt.applyTo(transformedPose, model); - playerExt.setPoseModified(true); + cState.setPoseModified(true); } } diff --git a/src/main/java/gg/essential/mixins/impl/client/model/PlayerEntityRenderStateExt.java b/src/main/java/gg/essential/mixins/impl/client/model/PlayerEntityRenderStateExt.java index a8b2066..fad2bce 100644 --- a/src/main/java/gg/essential/mixins/impl/client/model/PlayerEntityRenderStateExt.java +++ b/src/main/java/gg/essential/mixins/impl/client/model/PlayerEntityRenderStateExt.java @@ -11,13 +11,8 @@ */ package gg.essential.mixins.impl.client.model; -import net.minecraft.client.entity.AbstractClientPlayer; +import gg.essential.cosmetics.CosmeticsRenderState; public interface PlayerEntityRenderStateExt { - // Workaround until we've properly migrated everything to the new system - AbstractClientPlayer essential$getEntity(); - void essential$setEntity(AbstractClientPlayer entity); - - float essential$getTickDelta(); - void essential$setTickDelta(float tickDelta); + CosmeticsRenderState.Snapshot essential$getCosmetics(); } diff --git a/src/main/java/gg/essential/mixins/impl/client/renderer/entity/ArmorRenderingUtil.java b/src/main/java/gg/essential/mixins/impl/client/renderer/entity/ArmorRenderingUtil.java index 3430f70..15f327b 100644 --- a/src/main/java/gg/essential/mixins/impl/client/renderer/entity/ArmorRenderingUtil.java +++ b/src/main/java/gg/essential/mixins/impl/client/renderer/entity/ArmorRenderingUtil.java @@ -12,30 +12,10 @@ package gg.essential.mixins.impl.client.renderer.entity; import gg.essential.config.EssentialConfig; -import gg.essential.cosmetics.EssentialModelRenderer; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; public class ArmorRenderingUtil { - /** - * If rendering armor should be disabled based on the user's Essential settings and if cosmetics are conflicting with armor. - * @param entity The entity which the armor and cosmetics are being rendered on - * @param slotIndex The slot which armor is being rendered - * @return true if cosmetics are conflicting with armor in the current slot, false if armor is okay to be rendered - */ - public static boolean shouldDisableArmor(EntityLivingBase entity, int slotIndex) { - if (entity instanceof AbstractClientPlayerExt) { - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entity; - - int armorHidingSetting = getCosmeticArmorSetting(entity); - return armorHidingSetting == 1 && playerExt.getCosmeticsState().getPartsEquipped().contains(slotIndex) && !EssentialModelRenderer.suppressCosmeticRendering; - } - - return false; - } - public static int getCosmeticArmorSetting(Entity entity) { if (entity instanceof EntityPlayerSP) { return EssentialConfig.INSTANCE.getCosmeticArmorSettingSelf(); diff --git a/src/main/java/gg/essential/mixins/transformers/client/entity/MixinAbstractClientPlayer.java b/src/main/java/gg/essential/mixins/transformers/client/entity/MixinAbstractClientPlayer.java index 3800402..084fb49 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/entity/MixinAbstractClientPlayer.java +++ b/src/main/java/gg/essential/mixins/transformers/client/entity/MixinAbstractClientPlayer.java @@ -19,20 +19,23 @@ import gg.essential.cosmetics.*; import gg.essential.cosmetics.events.AnimationTarget; import gg.essential.cosmetics.skinmask.MaskedSkinProvider; -import gg.essential.cosmetics.source.CosmeticsSource; -import gg.essential.cosmetics.source.LiveCosmeticsSource; import gg.essential.gui.common.EmulatedUI3DPlayer; +import gg.essential.gui.elementa.state.v2.MutableState; +import gg.essential.gui.elementa.state.v2.Observer; +import gg.essential.gui.elementa.state.v2.State; import gg.essential.handlers.GameProfileManager; import gg.essential.mod.cosmetics.CosmeticSlot; import gg.essential.model.BedrockModel; import gg.essential.model.PlayerMolangQuery; +import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.MinecraftRenderBackend; import gg.essential.model.util.PlayerPoseManager; -import gg.essential.network.connectionmanager.cosmetics.CosmeticsManager; import gg.essential.util.UIdentifier; import gg.essential.util.UUIDUtil; import kotlin.Pair; import kotlin.Unit; +import kotlin.collections.MapsKt; +import kotlin.jvm.functions.Function1; import net.minecraft.client.entity.AbstractClientPlayer; import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; import net.minecraft.client.entity.EntityPlayerSP; @@ -49,7 +52,11 @@ import java.util.*; +import static gg.essential.gui.elementa.state.v2.FlattenKt.flatten; +import static gg.essential.gui.elementa.state.v2.StateKt.memo; +import static gg.essential.gui.elementa.state.v2.StateKt.mutableStateOf; import static gg.essential.network.cosmetics.ConversionsKt.toInfra; +import static gg.essential.util.Let.let; import static gg.essential.util.UIdentifierKt.toMC; //#if MC>=12002 @@ -63,7 +70,31 @@ public abstract class MixinAbstractClientPlayer implements AbstractClientPlayerE @Unique private final PlayerMolangQuery molangQuery = new PlayerMolangQuery((AbstractClientPlayer) (Object) this); @Unique - private CosmeticsSource cosmeticsSource; + private final UUID cosmeticsSourceUuid = computeCosmeticsSourceUuid(); + @Unique + private final boolean skinOverriddenByServer = let(((EntityPlayer) (Object) this).getGameProfile(), gameProfile -> { + String values = GameProfileManager.getSafeTexturesValue(gameProfile); + final JsonHolder root = new JsonHolder(new String(Base64.getDecoder().decode(values))); + return !root.optString("profileId").isEmpty() && !gameProfile.getId().equals(UUIDUtil.formatWithDashes(root.optString("profileId"))); + }); + @Unique + private final MutableState>> cosmeticsSourceState = mutableStateOf( + let(Essential.getInstance().getConnectionManager().getCosmeticsManager().getEquippedCosmeticsManager().getVisibleCosmeticsState(cosmeticsSourceUuid), cosmeticsSource -> { + if (!skinOverriddenByServer) { + return cosmeticsSource; + } else { + return memo((Function1>) obs -> { + Map cosmetics = cosmeticsSource.get(obs); + if (skinOverriddenByServer && EssentialConfig.INSTANCE.getHideCosmeticsWhenServerOverridesSkinState().get(obs)) { + cosmetics = MapsKt.filterKeys(cosmetics, it -> it == CosmeticSlot.EMOTE || it == CosmeticSlot.ICON); + } + return cosmetics; + }); + } + }) + ); + @Unique + private final State> cosmeticsSource = flatten(cosmeticsSourceState); @Unique private WearablesManager wearablesManager; @Unique @@ -72,8 +103,6 @@ public abstract class MixinAbstractClientPlayer implements AbstractClientPlayerE private String essentialCosmeticsCape; @Unique private Pair, @Nullable List> essentialCosmeticsCapeResources; - @Unique - private Boolean serverSkinOverrideStatus = null; @Unique private final boolean[] armorRenderingSuppressed = new boolean[4]; @@ -85,7 +114,7 @@ public abstract class MixinAbstractClientPlayer implements AbstractClientPlayerE private boolean poseModified; @Unique - private float lastCosmeticsUpdateTime; + private PlayerPose renderedPose; // mixin needs this to be able to correctly identify field initializers public MixinAbstractClientPlayer() { @@ -103,10 +132,11 @@ public MixinAbstractClientPlayer() { //#endif @Override - public CosmeticsSource getCosmeticsSource() { - if (this.cosmeticsSource == null) { - // Lazily initialized in case a player entity is created before Essential is booted - CosmeticsManager cosmeticsManager = Essential.getInstance().getConnectionManager().getCosmeticsManager(); + public UUID getCosmeticsSourceUuid() { + return cosmeticsSourceUuid; + } + + private UUID computeCosmeticsSourceUuid() { AbstractClientPlayer self = (AbstractClientPlayer) (Object) this; UUID uuid = self.getUniqueID(); Collection properties = self.getGameProfile().getProperties().get("essential:real_uuid"); @@ -118,14 +148,17 @@ public CosmeticsSource getCosmeticsSource() { Essential.logger.warn("Failed to parse fake_player uuid \"" + value + "\" for " + self.getUniqueID(), e); } } - this.cosmeticsSource = new LiveCosmeticsSource(cosmeticsManager, uuid); - } + return uuid; + } + + @Override + public State> getCosmeticsSource() { return this.cosmeticsSource; } @Override - public void setCosmeticsSource(CosmeticsSource cosmeticsSource) { - this.cosmeticsSource = cosmeticsSource; + public void setCosmeticsSource(State> cosmeticsSource) { + this.cosmeticsSourceState.set(cosmeticsSource); } @Override @@ -170,7 +203,7 @@ public void setEssentialCosmeticsCape(@Nullable String cape, @Nullable Pair=12002 //$$ @ModifyReturnValue(method = "getSkinTextures", at = @At("RETURN")) //$$ private SkinTextures overrideCapeIfSelectedInEssential(SkinTextures skinTextures) { @@ -210,7 +232,7 @@ private void overrideCapeIfSelectedInEssential(CallbackInfoReturnable injectLocalChannel(Class original) throws IOException { ServerData serverData = ProxyPingServerKt.getTargetServerData().get(); if (serverData != null) { // PingProxy connection @@ -102,6 +103,6 @@ private static ChannelFuture injectLocalChannel(Bootstrap bootstrap, InetAddress } // regular connection - return bootstrap.connect(address, port); + return original.call(bootstrap, address, port); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRender.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRender.java index 0a8ba92..1c0b366 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRender.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRender.java @@ -22,6 +22,10 @@ public class MixinRender { @Inject(method = "renderLivingLabel", at = @At("RETURN")) private void setNametagEntity(CallbackInfo ci) { + //#if MC!=11202 + //$$ OnlineIndicator.currentlyDrawingEntityName.set(false); + //#else OnlineIndicator.nametagEntity = null; + //#endif } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRenderPlayer.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRenderPlayer.java index cec962a..953c058 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRenderPlayer.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/MixinRenderPlayer.java @@ -13,6 +13,7 @@ import com.llamalad7.mixinextras.sugar.Local; import dev.folomeev.kotgl.matrix.matrices.Mat4; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.cosmetics.EssentialModelRenderer; import gg.essential.gui.emotes.EmoteWheel; import gg.essential.handlers.OnlineIndicator; @@ -170,7 +171,8 @@ private void renderLeftArm(AbstractClientPlayer player, CallbackInfo ci) { //#if MC<12102 getMainModel().isChild = false; //#endif - essentialModelRenderer.render(matrixStack, vertexConsumerProvider, EnumSet.of(EnumPart.LEFT_ARM), player); + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); + essentialModelRenderer.render(matrixStack, vertexConsumerProvider, cState, EnumSet.of(EnumPart.LEFT_ARM)); EmoteWheel.isPlayerArmRendering = false; } @@ -198,17 +200,14 @@ private void renderRightArm(AbstractClientPlayer player, CallbackInfo ci) { //#if MC<12102 getMainModel().isChild = false; //#endif - essentialModelRenderer.render(matrixStack, vertexConsumerProvider, EnumSet.of(EnumPart.RIGHT_ARM), player); + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); + essentialModelRenderer.render(matrixStack, vertexConsumerProvider, cState, EnumSet.of(EnumPart.RIGHT_ARM)); EmoteWheel.isPlayerArmRendering = false; } //#if MC>=12102 //$$ @Inject(method = "renderLabelIfPresent(Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;Lnet/minecraft/text/Text;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/LivingEntityRenderer;renderLabelIfPresent(Lnet/minecraft/client/render/entity/state/EntityRenderState;Lnet/minecraft/text/Text;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", ordinal = 1)) - //$$ private void setNametagEntity(CallbackInfo ci, @Local(argsOnly = true) PlayerEntityRenderState state) { - //$$ OnlineIndicator.nametagEntity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); - //$$ } - //#else - //#if MC>=12005 + //#elseif MC>=12005 //$$ @Inject(method = "renderLabelIfPresent(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/text/Text;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/LivingEntityRenderer;renderLabelIfPresent(Lnet/minecraft/entity/Entity;Lnet/minecraft/text/Text;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IF)V", ordinal = 1)) //#elseif MC>=11600 //$$ @Inject(method = "renderName(Lnet/minecraft/client/entity/player/AbstractClientPlayerEntity;Lnet/minecraft/util/text/ITextComponent;Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/LivingRenderer;renderName(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/text/ITextComponent;Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;I)V", ordinal = 1)) @@ -217,6 +216,11 @@ private void renderRightArm(AbstractClientPlayer player, CallbackInfo ci) { //#else //$$ @Inject(method = "renderOffsetLivingLabel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderOffsetLivingLabel(Lnet/minecraft/entity/Entity;DDDLjava/lang/String;FD)V")) //#endif + //#if MC!=11202 + //$$ private void setNametagEntity(CallbackInfo ci) { + //$$ OnlineIndicator.currentlyDrawingEntityName.set(true); + //$$ } + //#else private void setNametagEntity(CallbackInfo ci, @Local(argsOnly = true) AbstractClientPlayer entityIn) { OnlineIndicator.nametagEntity = entityIn; } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform.java index 2fe0350..43fc076 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform.java @@ -12,9 +12,11 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.ModelBipedExt; import gg.essential.mixins.impl.client.model.ModelBipedUtil; import gg.essential.model.backend.PlayerPose; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelBiped; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -76,8 +78,11 @@ private void applyPoseTransform( ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ Entity entity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif - ModelBipedUtil.applyPoseTransform((ModelBiped) (Object) this, entity); + ModelBipedUtil.applyPoseTransform((ModelBiped) (Object) this, cState); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java index f57c3eb..9b7afb4 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java @@ -12,13 +12,12 @@ package gg.essential.mixins.transformers.client.renderer.entity; import dev.folomeev.kotgl.matrix.matrices.mutables.MutableMat4; -import gg.essential.config.EssentialConfig; -import gg.essential.gui.common.EmulatedUI3DPlayer; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.CapePoseSupplier; import gg.essential.mixins.transformers.client.model.ModelPlayerAccessor; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.PlayerPoseKt; +import gg.essential.model.util.PlayerPoseManager; import gg.essential.util.GLUtil; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelRenderer; @@ -103,7 +102,9 @@ private void isolateCapeMatrix( //#endif CallbackInfo ci ) { - if (emotesDisabled(player)) { + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager != null) { return; } // We want MC's cape transformations only, not any transformations applied outside of the renderer. @@ -136,13 +137,14 @@ private void applyPoseTransform( //#endif CallbackInfo ci ) { - if (emotesDisabled(player)) { + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager != null) { return; } //#if MC>=11600 //$$ float scale = 1f / 16f; //#endif - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; ModelRenderer capeModel = this.getCapeModel(); // Read the matrix which MC has constructed on our freshly cleared matrix stack @@ -175,7 +177,7 @@ private void applyPoseTransform( // Compute the proper cape pose from the model and the matrix which MC constructed PlayerPose basePose = PlayerPoseKt.withCapePose(PlayerPose.Companion.neutral(), capeModel, capeMatrix); // and optionally apply animations - PlayerPose transformedPose = playerExt.getPoseManager().computePose(playerExt.getWearablesManager(), basePose); + PlayerPose transformedPose = poseManager.computePose(cState.wearablesManager(), basePose); renderedPose = transformedPose.getCape(); @@ -218,11 +220,6 @@ private ModelRenderer getCapeModel() { //#endif } - @Unique - private Boolean emotesDisabled(AbstractClientPlayer player) { - return EssentialConfig.INSTANCE.getDisableEmotes() && !(player instanceof EmulatedUI3DPlayer.EmulatedPlayer); - } - @Override public @Nullable PlayerPose.Part getCapePose() { return renderedPose; diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Elytra.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Elytra.java index b9788c5..e392c9d 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Elytra.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Elytra.java @@ -12,13 +12,11 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.config.EssentialConfig; -import gg.essential.gui.common.EmulatedUI3DPlayer; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.ElytraPoseSupplier; -import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.PlayerPoseKt; +import gg.essential.model.util.PlayerPoseManager; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelElytra; import net.minecraft.client.model.ModelRenderer; @@ -70,16 +68,16 @@ private void resetPose( ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); //#else if (!(entity instanceof AbstractClientPlayer)) return; - AbstractClientPlayer player = (AbstractClientPlayer) entity; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif if (resetPose == null) { - resetPose = PlayerPoseKt.withElytraPose(PlayerPose.Companion.neutral(), this.leftWing, this.rightWing, player); + resetPose = PlayerPoseKt.withElytraPose(PlayerPose.Companion.neutral(), this.leftWing, this.rightWing, cState); } else { - PlayerPoseKt.applyElytraPose(resetPose, this.leftWing, this.rightWing, player); + PlayerPoseKt.applyElytraPose(resetPose, this.leftWing, this.rightWing, cState); } } @@ -96,24 +94,24 @@ private void applyPoseTransform( ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); //#else - if (!(entity instanceof AbstractClientPlayerExt)) return; - AbstractClientPlayer player = (AbstractClientPlayer) entity; + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif - if (EssentialConfig.INSTANCE.getDisableEmotes() && !(player instanceof EmulatedUI3DPlayer.EmulatedPlayer)) { + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager != null) { return; } - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - PlayerPose basePose = PlayerPoseKt.withElytraPose(PlayerPose.Companion.neutral(), this.leftWing, this.rightWing, player); - PlayerPose transformedPose = playerExt.getPoseManager().computePose(playerExt.getWearablesManager(), basePose); + PlayerPose basePose = PlayerPoseKt.withElytraPose(PlayerPose.Companion.neutral(), this.leftWing, this.rightWing, cState); + PlayerPose transformedPose = poseManager.computePose(cState.wearablesManager(), basePose); if (basePose.equals(transformedPose)) { return; } - PlayerPoseKt.applyElytraPose(transformedPose, this.leftWing, this.rightWing, player); + PlayerPoseKt.applyElytraPose(transformedPose, this.leftWing, this.rightWing, cState); } @Override diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_EntityOnShoulder.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_EntityOnShoulder.java index f692426..405ada6 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_EntityOnShoulder.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_EntityOnShoulder.java @@ -13,12 +13,12 @@ import com.llamalad7.mixinextras.sugar.Local; import dev.folomeev.kotgl.matrix.matrices.mutables.MutableMat4; -import gg.essential.config.EssentialConfig; -import gg.essential.gui.common.EmulatedUI3DPlayer; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.model.backend.PlayerPose; +import gg.essential.model.util.PlayerPoseManager; import gg.essential.model.util.UMatrixStack; import gg.essential.util.GLUtil; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.entity.layers.LayerEntityOnShoulder; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -51,7 +51,7 @@ public abstract class Mixin_ApplyPoseTransform_EntityOnShoulder { @Unique private void applyPoseTransform( - EntityPlayer player, + CosmeticsRenderState cState, boolean leftSide, //#if MC>=11600 //$$ com.mojang.blaze3d.matrix.MatrixStack matrixStack @@ -59,14 +59,13 @@ private void applyPoseTransform( float scale //#endif ) { - if (EssentialConfig.INSTANCE.getDisableEmotes() && !(player instanceof EmulatedUI3DPlayer.EmulatedPlayer)) { + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager == null) { return; } - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - PlayerPose basePose = PlayerPose.Companion.neutral(); - PlayerPose transformedPose = playerExt.getPoseManager().computePose(playerExt.getWearablesManager(), basePose); + PlayerPose transformedPose = poseManager.computePose(cState.wearablesManager(), basePose); if (basePose.equals(transformedPose)) { return; @@ -100,9 +99,9 @@ private void applyPoseTransform( //$$ @Local(argsOnly = true) PlayerEntityRenderState state, //$$ @Local(argsOnly = true) boolean leftSide //$$ ) { - //$$ PlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); - //$$ if (player == null) return; - //$$ applyPoseTransform(player, leftSide, matrixStack); + //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //$$ applyPoseTransform(cState, leftSide, matrixStack); //$$ } //#else //#if MC>=11600 @@ -173,7 +172,9 @@ private void applyPoseTransform( org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable ci //#endif ) { - applyPoseTransform(player, leftSide, + if (!(player instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) player); + applyPoseTransform(cState, leftSide, //#if MC>=11600 //$$ matrixStack //#else @@ -204,7 +205,9 @@ private void applyPoseTransform( //#endif //$$ org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci //$$ ) { - //$$ applyPoseTransform(player, leftSide, matrixStack); + //$$ if (!(player instanceof AbstractClientPlayerEntity)) return; + //$$ CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayerEntity) player); + //$$ applyPoseTransform(cState, leftSide, matrixStack); //$$ } //$$ //$$ @Dynamic("Optifine changes arguments") @@ -228,7 +231,9 @@ private void applyPoseTransform( //#endif //$$ org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci //$$ ) { - //$$ applyPoseTransform(player, leftSide, matrixStack); + //$$ if (!(player instanceof AbstractClientPlayerEntity)) return; + //$$ CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayerEntity) player); + //$$ applyPoseTransform(cState, leftSide, matrixStack); //$$ } //#endif //#endif diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_CosmeticHoverOutline_Cape.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_CosmeticHoverOutline_Cape.java index 1d6372e..8a18169 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_CosmeticHoverOutline_Cape.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_CosmeticHoverOutline_Cape.java @@ -11,10 +11,10 @@ */ package gg.essential.mixins.transformers.client.renderer.entity; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.cosmetics.CosmeticsState; import gg.essential.cosmetics.EquippedCosmetic; import gg.essential.gui.common.CosmeticHoverOutlineEffect; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; import gg.essential.mod.cosmetics.CosmeticSlot; import gg.essential.network.cosmetics.Cosmetic; import kotlin.Unit; @@ -91,11 +91,11 @@ private void renderIntoHoverOutlineFrameBuffer( } //#if MC>=12102 - //$$ AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); //#else - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); //#endif - CosmeticsState cosmeticsState = playerExt.getCosmeticsState(); + CosmeticsState cosmeticsState = cState.wearablesManager().getState(); EquippedCosmetic equippedCosmetic = cosmeticsState.getCosmetics().get(CosmeticSlot.CAPE); Cosmetic cosmetic = equippedCosmetic != null ? equippedCosmetic.getCosmetic() : null; if (cosmetic == null) { diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java index 5c0e1ea..4202494 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java @@ -12,7 +12,8 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; +import gg.essential.cosmetics.CosmeticsRenderState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.entity.layers.LayerArmorBase; import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; @@ -36,7 +37,9 @@ public class Mixin_DisableArmorRendering { //$$ private void essential$disableArmorRendering(EntityLivingBase entityLivingBaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale, int slotIn, CallbackInfo info) { //$$ int slotIndex = slotIn-1; //#endif - if (ArmorRenderingUtil.shouldDisableArmor(entityLivingBaseIn, slotIndex)) { + if (!(entityLivingBaseIn instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entityLivingBaseIn); + if (cState.blockedArmorSlots().contains(slotIndex)) { info.cancel(); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableElytraRendering.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableElytraRendering.java index d215fb6..9cb7013 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableElytraRendering.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableElytraRendering.java @@ -12,7 +12,8 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; +import gg.essential.cosmetics.CosmeticsRenderState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.entity.layers.LayerElytra; import net.minecraft.entity.EntityLivingBase; import net.minecraft.inventory.EntityEquipmentSlot; @@ -46,9 +47,12 @@ public class Mixin_DisableElytraRendering { ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ LivingEntity entity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif - if (ArmorRenderingUtil.shouldDisableArmor(entity, EntityEquipmentSlot.CHEST.getIndex())) { + if (cState.blockedArmorSlots().contains(EntityEquipmentSlot.CHEST.getIndex())) { info.cancel(); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisablePlayerSkullRendering.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisablePlayerSkullRendering.java index 97f88fb..e48b9a2 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisablePlayerSkullRendering.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisablePlayerSkullRendering.java @@ -12,7 +12,8 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; +import gg.essential.cosmetics.CosmeticsRenderState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.entity.layers.LayerCustomHead; import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; @@ -57,7 +58,10 @@ public abstract class Mixin_DisablePlayerSkullRendering { ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ LivingEntity entity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif //#if MC<=10809 //$$ int headSlotIndex = 2; // The slot for HEAD is 3, but we need to remove 1 to get the index. @@ -65,7 +69,7 @@ public abstract class Mixin_DisablePlayerSkullRendering { int headSlotIndex = EntityEquipmentSlot.HEAD.getIndex(); //#endif - if (ArmorRenderingUtil.shouldDisableArmor(entity, headSlotIndex)) { + if (cState.blockedArmorSlots().contains(headSlotIndex)) { ci.cancel(); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ElytraPoseSupplier.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ElytraPoseSupplier.java index a3918aa..15b6f04 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ElytraPoseSupplier.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ElytraPoseSupplier.java @@ -14,6 +14,7 @@ import com.llamalad7.mixinextras.sugar.Local; import dev.folomeev.kotgl.matrix.vectors.Vec3; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.ElytraPoseSupplier; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.PlayerPoseKt; @@ -30,6 +31,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=12104 +//$$ import net.minecraft.component.type.EquippableComponent; +//#endif + //#if MC>=12102 //$$ import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; //$$ import gg.essential.mixins.transformers.client.renderer.entity.equipment.EquipmentRendererAccessor; @@ -44,7 +49,11 @@ public abstract class Mixin_ElytraPoseSupplier implements ElytraPoseSupplier { //#if MC>=12102 //$$ private static final String RENDER_LAYER = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V"; + //#if MC>=12104 + //$$ private static final String MODEL_RENDER = "Lnet/minecraft/client/render/entity/equipment/EquipmentRenderer;render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V"; + //#else //$$ private static final String MODEL_RENDER = "Lnet/minecraft/client/render/entity/equipment/EquipmentRenderer;render(Lnet/minecraft/item/equipment/EquipmentModel$LayerType;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V"; + //#endif //#elseif MC>=11600 //$$ private static final String RENDER_LAYER = "render(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/entity/LivingEntity;FFFFFF)V"; //#if MC>=12100 @@ -79,10 +88,17 @@ private void unsetRenderedPose(CallbackInfo ci) { //$$ private void setRenderedPose( //$$ CallbackInfo ci, //$$ @Local(argsOnly = true) BipedEntityRenderState state, - //$$ @Local(ordinal = 1) Identifier modelId + //#if MC>=12104 + //$$ @Local(ordinal = 0) EquippableComponent component + //#else + //$$ @Local(ordinal = 1) Identifier modelId + //#endif //$$ ) { //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#if MC>=12104 + //$$ var modelId = component.assetId().get(); + //#endif //$$ //$$ boolean modelHasNoWings = ((EquipmentRendererAccessor) this.equipmentRenderer) //$$ .getEquipmentModelLoader() @@ -93,13 +109,13 @@ private void unsetRenderedPose(CallbackInfo ci) { //#else private void setRenderedPose(CallbackInfo ci, @Local(argsOnly = true) EntityLivingBase entity) { if (!(entity instanceof AbstractClientPlayer)) return; - AbstractClientPlayer player = (AbstractClientPlayer) entity; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); //#endif this.leftWingPose = ((ElytraPoseSupplier) this.modelElytra).getLeftWingPose(); this.rightWingPose = ((ElytraPoseSupplier) this.modelElytra).getRightWingPose(); - Vec3 offset = PlayerPoseKt.getElytraPoseOffset(player); + Vec3 offset = PlayerPoseKt.getElytraPoseOffset(cState); if (leftWingPose != null) leftWingPose = leftWingPose.offset(offset); if (rightWingPose != null) rightWingPose = rightWingPose.offset(offset); } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Cape.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Cape.java index 92efba4..9ca3daa 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Cape.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Cape.java @@ -14,20 +14,18 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.model.backend.minecraft.MinecraftRenderBackend; import gg.essential.universal.UGraphics; -import gg.essential.util.UIdentifier; import kotlin.Unit; import kotlin.jvm.functions.Function0; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelPlayer; import net.minecraft.client.renderer.entity.layers.LayerCape; +import net.minecraft.util.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import static gg.essential.util.UIdentifierKt.toMC; - //#if MC>=12102 //$$ import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; //$$ import net.minecraft.client.render.entity.model.BipedEntityModel; @@ -95,11 +93,11 @@ private void renderWithEmissiveLayer( // Emissive layer //#if MC>=12102 - //$$ AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); //#else - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; + CosmeticsRenderState cState = new CosmeticsRenderState.Live(player); //#endif - UIdentifier emissiveTexture = playerExt.getEmissiveCapeTexture(); + ResourceLocation emissiveTexture = cState.emissiveCapeTexture(); if (emissiveTexture == null) { return; } @@ -108,13 +106,13 @@ private void renderWithEmissiveLayer( //$$ original.call( //$$ model, //$$ matrixStack, - //$$ buffer.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveLayer(toMC(emissiveTexture))), + //$$ buffer.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveLayer(emissiveTexture)), //$$ light, //$$ overlay //$$ ); //#else Function0 cleanup = MinecraftRenderBackend.INSTANCE.setupEmissiveRendering(); - UGraphics.bindTexture(0, toMC(emissiveTexture)); + UGraphics.bindTexture(0, emissiveTexture); original.call(model, scale); cleanup.invoke(); //#endif diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Elytra.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Elytra.java index 9f94cf6..553626e 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Elytra.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_Emissive_Elytra.java @@ -13,19 +13,18 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.model.backend.minecraft.MinecraftRenderBackend; import gg.essential.universal.UGraphics; -import gg.essential.util.UIdentifier; import kotlin.Unit; import kotlin.jvm.functions.Function0; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelElytra; import net.minecraft.client.renderer.entity.layers.LayerElytra; +import net.minecraft.util.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import static gg.essential.util.UIdentifierKt.toMC; - //#if MC>=11600 //$$ import com.llamalad7.mixinextras.sugar.Local; //$$ import com.mojang.blaze3d.matrix.MatrixStack; @@ -107,11 +106,11 @@ private void renderWithEmissiveLayer( ); // Emissive layer - if (!(entity instanceof AbstractClientPlayerExt)) { + if (!(entity instanceof AbstractClientPlayer)) { return; } - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entity; - UIdentifier emissiveTexture = playerExt.getEmissiveCapeTexture(); + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); + ResourceLocation emissiveTexture = cState.emissiveCapeTexture(); if (emissiveTexture == null) { return; } @@ -120,7 +119,7 @@ private void renderWithEmissiveLayer( //$$ original.call( //$$ model, //$$ matrixStack, - //$$ buffer.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveArmorLayer(toMC(emissiveTexture))), + //$$ buffer.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveArmorLayer(emissiveTexture)), //$$ light, //$$ overlay //#if MC<12100 @@ -132,7 +131,7 @@ private void renderWithEmissiveLayer( //$$ ); //#else Function0 cleanup = MinecraftRenderBackend.INSTANCE.setupEmissiveRendering(); - UGraphics.bindTexture(0, toMC(emissiveTexture)); + UGraphics.bindTexture(0, emissiveTexture); original.call(model, entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); cleanup.invoke(); //#endif diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java index b97513b..3fd0306 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java @@ -11,8 +11,10 @@ */ package gg.essential.mixins.transformers.client.renderer.entity; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.handlers.OnlineIndicator; import gg.essential.universal.UMatrixStack; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.entity.Entity; @@ -26,8 +28,9 @@ public class Mixin_RenderNameplateIcon { @Inject(method = "drawNameplate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;enableLighting()V")) private static void addEssentialIndicator(FontRenderer fontRendererIn, String str, float x, float y, float z, int verticalShift, float viewerYaw, float viewerPitch, boolean isThirdPersonFrontal, boolean isSneaking, CallbackInfo ci) { Entity entity = OnlineIndicator.nametagEntity; - if (OnlineIndicator.currentlyDrawingEntityName()) { - OnlineIndicator.drawNametagIndicator(new UMatrixStack(), entity, str, entity.getBrightnessForRender()); + if (OnlineIndicator.currentlyDrawingEntityName() && entity instanceof AbstractClientPlayer) { + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); + OnlineIndicator.drawNametagIndicator(new UMatrixStack(), cState, str, entity.getBrightnessForRender()); } } diff --git a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java index 38710f2..3c41139 100644 --- a/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java +++ b/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java @@ -11,7 +11,9 @@ */ package gg.essential.mixins.transformers.client.renderer.entity; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import com.llamalad7.mixinextras.sugar.Local; +import gg.essential.cosmetics.CosmeticsRenderState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.entity.layers.LayerArmorBase; import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; @@ -19,33 +21,68 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC==11202 +//#if MC>=12102 +//$$ import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; +//$$ import net.minecraft.client.render.entity.state.BipedEntityRenderState; +//#endif + +//#if MC>=11202 import net.minecraft.inventory.EntityEquipmentSlot; //#endif @Mixin(value = LayerArmorBase.class, priority = 900) public class Mixin_StoreArmorRenderedState { - @Inject(method = "doRenderLayer", at = @At("HEAD")) - private void essential$assumeArmorRenderingSuppressed(EntityLivingBase entitylivingbaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale, CallbackInfo info) { - if (entitylivingbaseIn instanceof AbstractClientPlayerExt) { - final AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entitylivingbaseIn; - playerExt.assumeArmorRenderingSuppressed(); - } + //#if MC>=12102 + //$$ private static final String RENDER = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V"; + //#elseif MC>=11600 + //$$ private static final String RENDER = "render(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/entity/LivingEntity;FFFFFF)V"; + //#else + private static final String RENDER = "doRenderLayer"; + //#endif + + private static final ThreadLocal suppressedArmor = new ThreadLocal<>(); + + @Inject(method = RENDER, at = @At("HEAD")) + private void essential$beginObservingArmorRendering(CallbackInfo info) { + suppressedArmor.set(new boolean[]{ true, true, true, true }); + } + + @Inject(method = RENDER, at = @At("RETURN")) + private void essential$storeObservedArmorRendering( + CallbackInfo info, + //#if MC>=12102 + //$$ @Local(argsOnly = true) BipedEntityRenderState state + //#else + @Local(argsOnly = true) EntityLivingBase entitylivingbaseIn + //#endif + ) { + //#if MC>=12102 + //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entitylivingbaseIn instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entitylivingbaseIn); + //#endif + cState.setSuppressedArmor(suppressedArmor.get()); } - //#if MC==11202 @Inject(method = "renderArmorLayer", at = @At(value = "HEAD", shift = At.Shift.AFTER)) - private void essential$markRenderingNotSuppressed(EntityLivingBase entityLivingBaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale, EntityEquipmentSlot slotIn, CallbackInfo info) { + private void essential$markRenderingNotSuppressed( + CallbackInfo info, + //#if MC>=11200 + @Local(argsOnly = true) EntityEquipmentSlot slotIn + //#else + //$$ @Local(argsOnly = true) int slotIn + //#endif + ) { + //#if MC>=11200 int slotIndex = slotIn.getIndex(); - //#else if MC==10809 - //$$ @Inject(method = "renderLayer", at = @At(value = "HEAD", shift = At.Shift.AFTER)) - //$$ private void essential$markRenderingNotSuppressed(EntityLivingBase entityLivingBaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale, int slotIn, CallbackInfo info) { - //$$ int slotIndex = slotIn-1; - //#endif - if (entityLivingBaseIn instanceof AbstractClientPlayerExt) { - final AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entityLivingBaseIn; - playerExt.armorRenderingNotSuppressed(slotIndex); - } + //#else + //$$ int slotIndex = slotIn-1; + //#endif + boolean[] slots = suppressedArmor.get(); + if (slots == null) return; + slots[slotIndex] = false; } } diff --git a/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java b/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java index 475743e..3109bff 100644 --- a/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java +++ b/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java @@ -20,21 +20,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -//#if MC>=12102 -//$$ import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; -//$$ import net.minecraft.client.render.entity.state.PlayerEntityRenderState; -//#endif - @Mixin(RenderPlayer.class) public abstract class Mixin_ApplyToPlayerRenderer { - //#if MC>=12102 - //$$ @Inject(method = "getTexture(Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;)Lnet/minecraft/util/Identifier;", at = @At("RETURN"), cancellable = true) - //$$ private void applyCosmeticsSkinMask(PlayerEntityRenderState state, CallbackInfoReturnable ci) { - //$$ AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); - //#else @Inject(method = "getEntityTexture(Lnet/minecraft/client/entity/AbstractClientPlayer;)Lnet/minecraft/util/ResourceLocation;", at = @At("RETURN"), cancellable = true) private void applyCosmeticsSkinMask(AbstractClientPlayer player, CallbackInfoReturnable ci) { - //#endif ci.setReturnValue(((AbstractClientPlayerExt) player).applyEssentialCosmeticsMask(ci.getReturnValue())); } } diff --git a/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateCosmetics.java b/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateCosmetics.java new file mode 100644 index 0000000..6358f8e --- /dev/null +++ b/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateCosmetics.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 ModCore Inc. All rights reserved. + * + * This code is part of ModCore Inc.'s Essential Mod repository and is protected + * under copyright registration # TX0009138511. For the full license, see: + * https://github.com/EssentialGG/Essential/blob/main/LICENSE + * + * You may not use, copy, reproduce, modify, sell, license, distribute, + * commercialize, or otherwise exploit, or create derivative works based + * upon, this file or any other in this repository, all of which is reserved by Essential. + */ +package gg.essential.mixins.transformers.feature.cosmetics; + +import gg.essential.cosmetics.WearablesManager; +import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.entity.player.EntityPlayer; +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; + +import static gg.essential.cosmetics.events.CosmeticEventDispatcher.dispatchEvents; + +@Mixin(RenderGlobal.class) +public abstract class Mixin_UpdateCosmetics { + @Shadow + private WorldClient world; + + //#if MC>=12102 + //$$ @Inject(method = "method_62214", at = @At(value = "CONSTANT", args = "stringValue=entities")) + //#elseif MC>=11400 + //$$ @Inject(method = "updateCameraAndRender", at = @At(value = "CONSTANT", args = "stringValue=entities")) + //#else + @Inject(method = "renderEntities", at = @At("HEAD")) + //#endif + private void essential$updateCosmeticsPreRender(CallbackInfo ci) { + //#if MC>=11400 + //$$ for (PlayerEntity player : this.world.getPlayers()) { + //#else + for (EntityPlayer player : this.world.playerEntities) { + //#endif + if (!(player instanceof AbstractClientPlayerExt)) { + continue; + } + AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; + + WearablesManager wearablesManager = playerExt.getWearablesManager(); + wearablesManager.update(); + playerExt.getPoseManager().update(wearablesManager); + } + } + + //#if MC>=12102 + //$$ @Inject(method = "method_62214", at = @At(value = "CONSTANT", args = "stringValue=blockentities")) + //#elseif MC>=11400 + //$$ @Inject(method = "updateCameraAndRender", at = @At(value = "CONSTANT", args = "stringValue=blockentities")) + //#else + @Inject(method = "renderEntities", at = @At("RETURN")) + //#endif + private void essential$updateCosmeticsPostRender(CallbackInfo ci) { + //#if MC>=11400 + //$$ for (PlayerEntity player : this.world.getPlayers()) { + //#else + for (EntityPlayer player : this.world.playerEntities) { + //#endif + if (!(player instanceof AbstractClientPlayerExt)) { + continue; + } + AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; + + WearablesManager wearablesManager = playerExt.getWearablesManager(); + wearablesManager.updateLocators(playerExt.getRenderedPose()); + dispatchEvents((AbstractClientPlayer) player, wearablesManager); + } + } +} diff --git a/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateOffscreenPlayers.java b/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateOffscreenPlayers.java deleted file mode 100644 index ad9e166..0000000 --- a/src/main/java/gg/essential/mixins/transformers/feature/cosmetics/Mixin_UpdateOffscreenPlayers.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2024 ModCore Inc. All rights reserved. - * - * This code is part of ModCore Inc.'s Essential Mod repository and is protected - * under copyright registration # TX0009138511. For the full license, see: - * https://github.com/EssentialGG/Essential/blob/main/LICENSE - * - * You may not use, copy, reproduce, modify, sell, license, distribute, - * commercialize, or otherwise exploit, or create derivative works based - * upon, this file or any other in this repository, all of which is reserved by Essential. - */ -package gg.essential.mixins.transformers.feature.cosmetics; - -import gg.essential.handlers.EssentialSoundManager; -import gg.essential.mixins.ext.client.ParticleSystemHolder; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; -import gg.essential.model.ModelAnimationState; -import gg.essential.model.ModelInstance; -import gg.essential.model.ParticleSystem; -import gg.essential.model.PlayerMolangQuery; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.entity.player.EntityPlayer; -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; - -import java.util.List; - -/** - * Updates cosmetic animations/events/effects of players that are currently off-screen (that is, have not been rendered - * for some reason). - */ -@Mixin(RenderGlobal.class) -public abstract class Mixin_UpdateOffscreenPlayers { - @Shadow - private WorldClient world; - - // TODO 1.21.2 is this place still good? maybe separate update from render entirely - //#if MC>=12102 - //$$ @Inject(method = "method_62214", at = @At(value = "CONSTANT", args = "stringValue=blockentities")) - //#elseif MC>=11400 - //$$ @Inject(method = "updateCameraAndRender", at = @At(value = "CONSTANT", args = "stringValue=blockentities")) - //#else - @Inject(method = "renderEntities", at = @At("RETURN")) - //#endif - private void essential$updateCosmetics(CallbackInfo ci) { - ParticleSystem particleSystem = this.world instanceof ParticleSystemHolder - ? ((ParticleSystemHolder) this.world).getParticleSystem() - : null; - - //#if MC>=11400 - //$$ for (PlayerEntity player : this.world.getPlayers()) { - //#else - for (EntityPlayer player : this.world.playerEntities) { - //#endif - if (!(player instanceof AbstractClientPlayerExt)) { - continue; - } - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - - float lifeTime = new PlayerMolangQuery(player).getLifeTime(); - if (playerExt.getLastCosmeticsUpdateTime() >= lifeTime) { - continue; - } - - for (ModelInstance model : playerExt.getWearablesManager().getModels().values()) { - model.getEssentialAnimationSystem().updateAnimationState(); - model.updateEffects(); - - List pendingEvents = model.getAnimationState().getPendingEvents(); - if (!pendingEvents.isEmpty()) { - for (ModelAnimationState.Event event : pendingEvents) { - if (event instanceof ModelAnimationState.ParticleEvent) { - if (particleSystem != null) { - particleSystem.spawn((ModelAnimationState.ParticleEvent) event); - } - } else if (event instanceof ModelAnimationState.SoundEvent) { - EssentialSoundManager.INSTANCE.playSound((ModelAnimationState.SoundEvent) event); - } - } - pendingEvents.clear(); - } - } - } - } -} diff --git a/src/main/java/gg/essential/mixins/transformers/feature/particles/Mixin_RenderParticleSystemOfClientWorld.java b/src/main/java/gg/essential/mixins/transformers/feature/particles/Mixin_RenderParticleSystemOfClientWorld.java index eb07351..bf07901 100644 --- a/src/main/java/gg/essential/mixins/transformers/feature/particles/Mixin_RenderParticleSystemOfClientWorld.java +++ b/src/main/java/gg/essential/mixins/transformers/feature/particles/Mixin_RenderParticleSystemOfClientWorld.java @@ -35,6 +35,10 @@ import static dev.folomeev.kotgl.matrix.vectors.mutables.MutableVectors.times; import static gg.essential.util.HelpersKt.getPerspective; +//#if MC>=12104 +//$$ import com.mojang.blaze3d.systems.RenderSystem; +//#endif + //#if MC>=11600 //$$ import com.mojang.blaze3d.matrix.MatrixStack; //$$ import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -75,7 +79,9 @@ public abstract class Mixin_RenderParticleSystemOfClientWorld { //$$ "renderParticles", //#endif }, - //#if MC>=12005 + //#if MC>=12104 + //$$ at = @At("RETURN") + //#elseif MC>=12005 //$$ at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;depthMask(Z)V") //#elseif MC>=11700 //$$ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V") @@ -91,9 +97,14 @@ public abstract class Mixin_RenderParticleSystemOfClientWorld { //$$ MatrixStack matrixStackIn, //$$ IRenderTypeBuffer.Impl bufferIn, //#endif + //#if MC<12104 //$$ LightTexture lightTextureIn, + //#endif //$$ ActiveRenderInfo activeRenderInfoIn, //$$ float partialTicks, + //#if MC>=12104 + //$$ VertexConsumerProvider.Immediate bufferIn, + //#endif //#if FORGE //#if MC>=11700 //$$ net.minecraft.client.renderer.culling.Frustum frustum, @@ -180,8 +191,14 @@ public abstract class Mixin_RenderParticleSystemOfClientWorld { UUID cameraUuid = cameraEntity.getUniqueID(); //#endif + ParticleSystem.VertexConsumerProvider particleVertexConsumer = new MinecraftRenderBackend.ParticleVertexConsumerProvider( + //#if MC>=12104 + //$$ bufferIn + //#endif + ); + boolean isFirstPerson = getPerspective() == 0; - particleSystem.render(stack, cameraPos, cameraRot, new MinecraftRenderBackend.ParticleVertexConsumerProvider(), cameraUuid, isFirstPerson); + particleSystem.render(stack, cameraPos, cameraRot, particleVertexConsumer, cameraUuid, isFirstPerson); profiler.endSection(); } @@ -220,9 +237,14 @@ public abstract class Mixin_RenderParticleSystemOfClientWorld { //$$ matrixStackIn, //$$ bufferIn, //#endif - //$$ lightTextureIn, + //#if MC<12104 + //$$ lightTextureIn, + //#endif //$$ activeRenderInfoIn, //$$ partialTicks, + //#if MC>=12104 + //$$ bufferIn, + //#endif //$$ ci //$$ ); //$$ } diff --git a/src/main/java/gg/essential/network/connectionmanager/handler/cosmetics/ServerCosmeticAnimationTriggerPacketHandler.java b/src/main/java/gg/essential/network/connectionmanager/handler/cosmetics/ServerCosmeticAnimationTriggerPacketHandler.java index 655b464..f8ce929 100644 --- a/src/main/java/gg/essential/network/connectionmanager/handler/cosmetics/ServerCosmeticAnimationTriggerPacketHandler.java +++ b/src/main/java/gg/essential/network/connectionmanager/handler/cosmetics/ServerCosmeticAnimationTriggerPacketHandler.java @@ -32,7 +32,7 @@ protected void onHandle( CosmeticSlot slot = toMod(packet.getCosmeticSlot()); String triggerName = packet.getTriggerName(); - Essential.getInstance().getAnimationEffectHandler().triggerEvent(userId, slot, triggerName); + Essential.getInstance().getCosmeticEventEmitter().triggerEvent(userId, slot, triggerName); } } diff --git a/src/main/java/gg/essential/network/connectionmanager/notices/NoticesManager.java b/src/main/java/gg/essential/network/connectionmanager/notices/NoticesManager.java index 3a9c013..48f7ee6 100644 --- a/src/main/java/gg/essential/network/connectionmanager/notices/NoticesManager.java +++ b/src/main/java/gg/essential/network/connectionmanager/notices/NoticesManager.java @@ -158,7 +158,11 @@ public void populateNotices(@NotNull final Collection notices) for (@NotNull final Notice notice : notices) { this.notices.put(notice.getId(), notice); for (NoticeListener listener : listeners) { - listener.noticeAdded(notice); + try { + listener.noticeAdded(notice); + } catch (Exception e) { + Essential.logger.error("An error occurred within a notice listener for noticeAdded: {}", notice.getId(), e); + } } } } @@ -168,7 +172,11 @@ public void removeNotices(@Nullable final Set noticeIds) { if (noticeIds == null || noticeIds.isEmpty()) { for (Notice value : notices.values()) { for (NoticeListener listener : listeners) { - listener.noticeRemoved(value); + try { + listener.noticeRemoved(value); + } catch (Exception e) { + Essential.logger.error("An error occurred within a notice listener for noticeRemoved: {}", value.getId(), e); + } } } this.notices.clear(); @@ -181,7 +189,11 @@ public void removeNotices(@Nullable final Set noticeIds) { continue; } for (NoticeListener listener : listeners) { - listener.noticeRemoved(removed); + try { + listener.noticeRemoved(removed); + } catch (Exception e) { + Essential.logger.error("An error occurred within a notice listener for noticeRemoved: {}", removed.getId(), e); + } } } } @@ -207,14 +219,15 @@ public void flushDismissNotices() { Packet packet = maybePacket.get(); if (packet instanceof ServerNoticeBulkDismissPacket) { ServerNoticeBulkDismissPacket serverNoticeBulkDismissPacket = (ServerNoticeBulkDismissPacket) packet; - for (String noticeId : serverNoticeBulkDismissPacket.getNoticeIds()) { - this.notices.remove(noticeId); + Set noticeIds = serverNoticeBulkDismissPacket.getNoticeIds(); + if (!noticeIds.isEmpty()) { + removeNotices(noticeIds); } for (ServerNoticeBulkDismissPacket.ErrorDetails error : serverNoticeBulkDismissPacket.getErrors()) { switch (error.getReason()) { case "NOTICE_NOT_FOUND": case "NOTICE_ALREADY_DISMISSED": { - this.notices.remove(error.getNoticeId()); + removeNotices(SetsKt.setOf(error.getNoticeId())); break; } default: { diff --git a/src/main/kotlin/gg/essential/gui/common/CosmeticPreview.kt b/src/main/kotlin/gg/essential/gui/common/CosmeticPreview.kt index 6a97bd5..b536f6a 100644 --- a/src/main/kotlin/gg/essential/gui/common/CosmeticPreview.kt +++ b/src/main/kotlin/gg/essential/gui/common/CosmeticPreview.kt @@ -11,18 +11,16 @@ */ package gg.essential.gui.common -import com.google.common.collect.ImmutableMap import com.mojang.authlib.GameProfile import gg.essential.api.profile.wrapped import gg.essential.cosmetics.EquippedCosmetic -import gg.essential.cosmetics.source.ConfigurableCosmeticsSource import gg.essential.elementa.components.UIContainer import gg.essential.elementa.dsl.constrain import gg.essential.elementa.dsl.percent import gg.essential.elementa.effects.ScissorEffect import gg.essential.elementa.state.BasicState import gg.essential.gui.elementa.state.v2.State -import gg.essential.gui.elementa.state.v2.effect +import gg.essential.gui.elementa.state.v2.memo import gg.essential.gui.elementa.state.v2.mutableListStateOf import gg.essential.gui.elementa.state.v2.stateOf import gg.essential.handlers.GameProfileManager @@ -64,9 +62,9 @@ class CosmeticPreview(val cosmetic: Cosmetic, val settings: State().apply { + cosmeticsSource = + memo { + buildMap { if (emoteScheduler == null || emoteScheduler.emoteEquipped()) { put(slot, EquippedCosmetic(cosmetic, settings())) } @@ -74,12 +72,8 @@ class CosmeticPreview(val cosmetic: Cosmetic, val settings: State>? = null set(value) { field = value if (value != null) { @@ -438,11 +437,19 @@ open class UI3DPlayer( try { current = this + val player = player as? AbstractClientPlayer ?: return + val playerExt = player as? AbstractClientPlayerExt ?: return + + playerExt.wearablesManager.update() + playerExt.poseManager.update(playerExt.wearablesManager) + doDrawPlayer() + playerExt.wearablesManager.updateLocators(playerExt.renderedPose) + dispatchEvents(player, playerExt.wearablesManager) + // An emulated player has its own dedicated particle system which we need to manually update here (that is // after we have rendered the player, which updates any locators). - val player = player val dedicatedParticleSystem = (player as? EmulatedUI3DPlayer.EmulatedPlayer)?.particleSystem dedicatedParticleSystem?.update() @@ -651,7 +658,12 @@ open class UI3DPlayer( } private fun doDrawParticles(particleSystem: ParticleSystem) { + //#if MC>=12104 + //$$ val immediate = MinecraftClient.getInstance().bufferBuilders.entityVertexConsumers + //$$ val vertexConsumerProvider = MinecraftRenderBackend.ParticleVertexConsumerProvider(immediate) + //#else val vertexConsumerProvider = MinecraftRenderBackend.ParticleVertexConsumerProvider() + //#endif UGraphics.enableDepth() bindWhiteLightMapTexture() @@ -672,6 +684,10 @@ open class UI3DPlayer( val cameraPos = camera.camera.rotateBy(realRotation).plus(realPosition) particleSystem.render(stack, cameraPos, realRotation * camera.rotation, vertexConsumerProvider, UUID(0, 0), false) + //#if MC>=12104 + //$$ immediate.draw() + //#endif + UGraphics.disableDepth() } @@ -705,9 +721,9 @@ open class UI3DPlayer( private val poseManager = PlayerPoseManager(entity) val particleSystem = ParticleSystem(Random(0), PlaneCollisionProvider.PlaneXZ, LightProvider.FullBright, ::playSound) - private var liveCosmeticsSource: CosmeticsSource? = null - private val cosmeticsSource: CosmeticsSource - get() = this@UI3DPlayer.cosmeticsSource ?: liveCosmeticsSource ?: CosmeticsSource.EMPTY + private var liveCosmeticsSource: StateV2>? = null + private val cosmeticsSource: StateV2> + get() = this@UI3DPlayer.cosmeticsSource ?: liveCosmeticsSource ?: stateOf(emptyMap()) private var cosmetics: Map = emptyMap() val wearablesManager = WearablesManager(MinecraftRenderBackend, entity, subject.animationTargets) { _, _, -> } @@ -757,6 +773,9 @@ open class UI3DPlayer( private fun loadTextures(profile: GameProfile) { //#if MC>=12002 //$$ MinecraftClient.getInstance().skinProvider.fetchSkinTextures(profile).thenAcceptOnMainThread { skin -> + //#if MC>=12104 + //$$ val skin = skin.get() + //#endif //$$ currentSkin = skin.texture //$$ updateSkinType(Model.byTypeOrDefault(skin.model.getName())) //$$ currentCape = skin.capeTexture @@ -790,7 +809,7 @@ open class UI3DPlayer( currentProfile = null // UUID may have changed, need to update live cosmetic source accordingly - liveCosmeticsSource = LiveCosmeticsSource(cosmeticsManager, profileConfigured.id) + liveCosmeticsSource = cosmeticsManager.equippedCosmeticsManager.getVisibleCosmeticsState(profileConfigured.id) entity.uuid = profileConfigured.id } @@ -811,7 +830,8 @@ open class UI3DPlayer( } // Check if the equipped cosmetics or any of their settings have changed - val newCosmetics = cosmeticsSource.cosmetics + // FIXME should use State effect instead of checking every frame (though note that this field isn't a proper state yet!) + val newCosmetics = cosmeticsSource.getUntracked() if (cosmetics != newCosmetics) { cosmetics = newCosmetics updateCosmeticsState() @@ -836,6 +856,8 @@ open class UI3DPlayer( else -> Pair(getThirdPartyCape(), null) } + playerModel.update() + wearablesManager.update() poseManager.update(wearablesManager) var pose = PlayerPose.neutral() @@ -875,6 +897,7 @@ open class UI3DPlayer( wearablesManager.render(stack, vertexConsumerProvider, pose, skin) wearablesManager.renderForHoverOutline(stack, vertexConsumerProvider, pose, skin) + wearablesManager.updateLocators(pose) wearablesManager.collectEvents { event -> when (event) { is ModelAnimationState.ParticleEvent -> particleSystem.spawn(event) diff --git a/src/main/kotlin/gg/essential/gui/emotes/EmoteWheel.kt b/src/main/kotlin/gg/essential/gui/emotes/EmoteWheel.kt index 82ab569..0f1e938 100644 --- a/src/main/kotlin/gg/essential/gui/emotes/EmoteWheel.kt +++ b/src/main/kotlin/gg/essential/gui/emotes/EmoteWheel.kt @@ -374,7 +374,7 @@ class EmoteWheel : WindowScreen( emoteComing = false if (cosmeticManager.equippedCosmetics[slot] == emote.cosmetic.id) { - essential.animationEffectHandler.triggerEvent(UUIDUtil.getClientUUID(), slot, "reset") + essential.cosmeticEventEmitter.triggerEvent(UUIDUtil.getClientUUID(), slot, "reset") connectionManager.send(ClientCosmeticAnimationTriggerPacket(slot.toInfra(), "reset")) } else { val outfitId = outfitManager.selectedOutfitId.getUntracked() ?: return@scheduleOnMainThread diff --git a/src/main/kotlin/gg/essential/gui/multiplayer/EssentialMultiplayerGui.kt b/src/main/kotlin/gg/essential/gui/multiplayer/EssentialMultiplayerGui.kt index e0783fc..06598c1 100644 --- a/src/main/kotlin/gg/essential/gui/multiplayer/EssentialMultiplayerGui.kt +++ b/src/main/kotlin/gg/essential/gui/multiplayer/EssentialMultiplayerGui.kt @@ -286,7 +286,11 @@ class EssentialMultiplayerGui { //#if MC>=11600 //$$ val lastServer = newList.eventListeners.lastOrNull { it is NormalEntry } //$$ newScreen.func_214287_a(lastServer) + //#if MC>=12104 + //$$ newList.scrollY = Double.MAX_VALUE + //#else //$$ newList.scrollAmount = Double.MAX_VALUE + //#endif //#else val index = newScreen.serverList.countServers() - 1 newScreen.selectServer(index) diff --git a/src/main/kotlin/gg/essential/gui/screenshot/image/PixelBufferTexture.kt b/src/main/kotlin/gg/essential/gui/screenshot/image/PixelBufferTexture.kt index 29aa4a9..8acb1ac 100644 --- a/src/main/kotlin/gg/essential/gui/screenshot/image/PixelBufferTexture.kt +++ b/src/main/kotlin/gg/essential/gui/screenshot/image/PixelBufferTexture.kt @@ -19,13 +19,12 @@ import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.resources.IResourceManager import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL12 -import net.minecraft.util.ResourceLocation import java.nio.IntBuffer //#if MC<=11202 import net.minecraft.client.renderer.texture.AbstractTexture //#else -//$$ import net.minecraft.client.renderer.texture.SimpleTexture +//$$ import net.minecraft.client.renderer.texture.Texture //#endif //#if MC>=11600 @@ -35,11 +34,11 @@ import net.minecraft.client.renderer.texture.AbstractTexture /** * Uploads the contents of a PixelBuffer to OpenGL */ -class PixelBufferTexture(image: PixelBuffer, resourceLocation: ResourceLocation) : +class PixelBufferTexture(image: PixelBuffer) : //#if MC<=11202 AbstractTexture() { //#else - //$$ SimpleTexture(resourceLocation) { + //$$ Texture() { //#endif // Whether this texture's underlying image had an error during loading @@ -95,9 +94,11 @@ class PixelBufferTexture(image: PixelBuffer, resourceLocation: ResourceLocation) } } + //#if MC<12104 //Impl handled by constructor to avoid retaining complete image override fun loadTexture(resourceManager: IResourceManager) { } + //#endif } diff --git a/src/main/kotlin/gg/essential/gui/screenshot/providers/MinecraftWindowedTextureProvider.kt b/src/main/kotlin/gg/essential/gui/screenshot/providers/MinecraftWindowedTextureProvider.kt index 713e45c..17d8a5e 100644 --- a/src/main/kotlin/gg/essential/gui/screenshot/providers/MinecraftWindowedTextureProvider.kt +++ b/src/main/kotlin/gg/essential/gui/screenshot/providers/MinecraftWindowedTextureProvider.kt @@ -127,7 +127,7 @@ class MinecraftWindowedTextureProvider( loading[path] = nextResourceLocation image.retain() upload(path) { - val texture = PixelBufferTexture(image, nextResourceLocation) + val texture = PixelBufferTexture(image) image.release() texture to nextResourceLocation } diff --git a/src/main/kotlin/gg/essential/gui/wardrobe/components/previewWindow.kt b/src/main/kotlin/gg/essential/gui/wardrobe/components/previewWindow.kt index 5e13126..5d9d3f5 100644 --- a/src/main/kotlin/gg/essential/gui/wardrobe/components/previewWindow.kt +++ b/src/main/kotlin/gg/essential/gui/wardrobe/components/previewWindow.kt @@ -17,7 +17,6 @@ import gg.essential.api.gui.Slot import gg.essential.api.profile.wrapped import gg.essential.config.EssentialConfig import gg.essential.cosmetics.CosmeticId -import gg.essential.cosmetics.source.ConfigurableCosmeticsSource import gg.essential.elementa.UIComponent import gg.essential.elementa.components.Window import gg.essential.elementa.constraints.CenterConstraint @@ -48,7 +47,6 @@ import gg.essential.gui.elementa.state.v2.combinators.component2 import gg.essential.gui.elementa.state.v2.combinators.map import gg.essential.gui.elementa.state.v2.combinators.not import gg.essential.gui.elementa.state.v2.combinators.or -import gg.essential.gui.elementa.state.v2.effect import gg.essential.gui.elementa.state.v2.isNotEmpty import gg.essential.gui.elementa.state.v2.memo import gg.essential.gui.elementa.state.v2.mutableStateOf @@ -91,6 +89,7 @@ import gg.essential.util.GuiUtil import gg.essential.util.findChildOfTypeOrNull import gg.essential.util.onLeftClick import gg.essential.util.scrollGradient +import gg.essential.util.toState import java.util.UUID import kotlin.math.abs import kotlin.math.round @@ -119,6 +118,18 @@ fun LayoutScope.previewWindowTitleBar(state: WardrobeState, modifier: Modifier) } val text = textWithHoverability.map { it.first } val isOutfitMenuOpen = mutableStateOf(false) + val selectedEmoteHasSound = memo { + val emote = state.selectedEmote() ?: return@memo false + val variant = state.selectedPreviewingEquippedSettings()[emote.id]?.variant ?: emote.cosmetic.defaultVariantName + + val model = state.modelLoader.getModel( + emote.cosmetic, + variant, + AssetLoader.Priority.High, + ).toState()() ?: return@memo false + + model.soundData != null + } fun LayoutScope.titleBarButton(modifier: Modifier, block: LayoutScope.() -> Unit = {}): UIComponent { return box(modifier.width(17f).heightAspect(1f).shadow(EssentialPalette.BLACK), block) @@ -209,7 +220,7 @@ fun LayoutScope.previewWindowTitleBar(state: WardrobeState, modifier: Modifier) if_(!emoteSelected and !bundleSelected and !state.inEmoteWheel and regularContent) { outfitAddButton(state) } - if_(emoteSelected and !state.editingMenuOpen and !state.inEmoteWheel) { + if_(selectedEmoteHasSound and !state.editingMenuOpen and !state.inEmoteWheel) { titleBarButton(Modifier.color(EssentialPalette.GRAY_BUTTON).hoverColor(EssentialPalette.GRAY_BUTTON_HOVER).hoverScope()) { icon({ if (EssentialConfig.playEmoteSoundsInWardrobe()) EssentialPalette.UNMUTE_10X7 else EssentialPalette.MUTE_10X7 }, Modifier.color(EssentialPalette.TEXT).hoverColor(EssentialPalette.TEXT_HIGHLIGHT)) @@ -379,8 +390,8 @@ private fun LayoutScope.playerPreviewInner(state: WardrobeState, modifier: Modif memo { state.selectedEmote()?.cosmetic }, memo { state.selectedEmote()?.let { settings()[it.id] } }, ) - cosmeticsSource = ConfigurableCosmeticsSource().apply { - effect(stateScope) { + cosmeticsSource = + memo { val cosmeticIds = (state.selectedEmote()?.let { emote -> if (emoteScheduler.emoteEquipped()) mapOf(CosmeticSlot.EMOTE to emote.id) else emptyMap() } ?: state.selectedBundle()?.cosmetics ?: state.equippedCosmeticsState()).toMutableMap() @@ -389,10 +400,8 @@ private fun LayoutScope.playerPreviewInner(state: WardrobeState, modifier: Modif cosmeticIds[CosmeticSlot.EMOTE] = state.purchaseConfirmationEmoteId } - cosmetics = with(state) { resolveCosmeticIds(cosmeticIds, settings()) } + with(state) { resolveCosmeticIds(cosmeticIds, settings()) } } - shouldOverrideRenderCosmeticsCheck = true - } val dragging = mutableStateOf(false) val hovered = stateDelegatingTo(stateOf(null)) diff --git a/src/main/kotlin/gg/essential/mixins/ext/client/network/NetHandlerPlayClientExt.kt b/src/main/kotlin/gg/essential/mixins/ext/client/network/NetHandlerPlayClientExt.kt index dd209ee..97b518e 100644 --- a/src/main/kotlin/gg/essential/mixins/ext/client/network/NetHandlerPlayClientExt.kt +++ b/src/main/kotlin/gg/essential/mixins/ext/client/network/NetHandlerPlayClientExt.kt @@ -14,5 +14,6 @@ package gg.essential.mixins.ext.client.network import java.util.* interface NetHandlerPlayClientExt { + fun `essential$getNameIdCache`(): Map } \ No newline at end of file diff --git a/src/main/kotlin/gg/essential/model/backend/minecraft/MinecraftRenderBackend.kt b/src/main/kotlin/gg/essential/model/backend/minecraft/MinecraftRenderBackend.kt index eeb3c01..c944dd1 100644 --- a/src/main/kotlin/gg/essential/model/backend/minecraft/MinecraftRenderBackend.kt +++ b/src/main/kotlin/gg/essential/model/backend/minecraft/MinecraftRenderBackend.kt @@ -68,6 +68,8 @@ import org.lwjgl.BufferUtils //#endif object MinecraftRenderBackend : RenderBackend { + private val registeredTextures = mutableMapOf() + override fun createTexture(name: String, width: Int, height: Int): RenderBackend.Texture { return DynamicTexture(identifier("essential", name), ReleasedDynamicTexture(width, height)) } @@ -77,14 +79,8 @@ object MinecraftRenderBackend : RenderBackend { texture.texture.deleteGlTexture() - val textureManager = getMinecraft().textureManager - //#if MC>=11700 - //$$ val registeredTexture = textureManager.getOrDefault(identifier, null) as? ReleasedDynamicTexture - //#else - val registeredTexture = textureManager.getTexture(identifier) as? ReleasedDynamicTexture - //#endif - if (registeredTexture == texture.texture) { - textureManager.deleteTexture(identifier) + if (registeredTextures.remove(identifier, texture)) { + getMinecraft().textureManager.deleteTexture(identifier) } } @@ -124,6 +120,42 @@ object MinecraftRenderBackend : RenderBackend { if (prevScissor) GL11.glEnable(GL11.GL_SCISSOR_TEST) } + //#if MC>=12104 + //$$ // As of 1.21.4, MC itself now finally uses the RenderLayer system for its particles, so we'll do the same. + //$$ // Our particles have more blending modes though, so we need some custom layers. + //$$ private val particleLayers = mutableMapOf() + //$$ private fun getParticleLayer(renderPass: ParticleEffect.RenderPass) = particleLayers.getOrPut(renderPass) { + //$$ val texture = (renderPass.texture as MinecraftTexture).identifier + //$$ val inner = + //$$ if (renderPass.material == Cutout) RenderLayer.getOpaqueParticle(texture) + //$$ else RenderLayer.getTranslucentParticle(texture) + //$$ // Note: If this is turned into an anonymous class, Kotlin will generate the bridge for the protected + //$$ // field in the wrong class (MinecraftRenderBackend), which will then throw an IllegalAccessError. + //$$ class ParticleLayer : RenderLayer( + //$$ renderPass.material.name.lowercase() + "_particle", + //$$ inner.vertexFormat, + //$$ inner.drawMode, + //$$ inner.expectedBufferSize, + //$$ inner.hasCrumbling(), + //$$ inner.isTranslucent, + //$$ { + //$$ inner.startDrawing() + //$$ when (renderPass.material) { + //$$ Cutout -> {} // blending is disabled by default + //$$ Add -> BlendState(BlendState.Equation.ADD, BlendState.Param.SRC_ALPHA, BlendState.Param.ONE).activate() + //$$ Blend -> BlendState.NORMAL.activate() + //$$ } + //$$ }, + //$$ { + //$$ RenderSystem.disableBlend() + //$$ RenderSystem.defaultBlendFunc() + //$$ inner.endDrawing() + //$$ }, + //$$ ) + //$$ ParticleLayer() + //$$ } + //#endif + //#if MC>=12102 //$$ // MC no longer provides the CULL variant of ENTITY_TRANSLUCENT which we use to render our cosmetics, so we'll //$$ // have to build it ourselves. @@ -318,13 +350,9 @@ object MinecraftRenderBackend : RenderBackend { override val height: Int = texture.height override val identifier: ResourceLocation by lazy { - val textureManager = getMinecraft().textureManager - //#if MC>=11700 - //$$ (textureManager.getOrDefault(identifier, null) as? ReleasedDynamicTexture)?.clearGlId() - //#else - (textureManager.getTexture(identifier) as? ReleasedDynamicTexture)?.deleteGlTexture() - //#endif - textureManager.loadTexture(identifier, texture) + registeredTextures[identifier]?.let { deleteTexture(it) } + getMinecraft().textureManager.loadTexture(identifier, texture) + registeredTextures[identifier] = this identifier } } @@ -413,7 +441,11 @@ object MinecraftRenderBackend : RenderBackend { //#endif } + //#if MC>=12104 + //$$ class ParticleVertexConsumerProvider(val provider: net.minecraft.client.render.VertexConsumerProvider) : ParticleSystem.VertexConsumerProvider { + //#else class ParticleVertexConsumerProvider : ParticleSystem.VertexConsumerProvider { + //#endif override fun provide(renderPass: ParticleEffect.RenderPass, block: (CVertexConsumer) -> Unit) { val texture = renderPass.texture require(texture is MinecraftTexture) @@ -438,6 +470,11 @@ object MinecraftRenderBackend : RenderBackend { } override fun endVertex() = apply { inner.endVertex() } } + + //#if MC>=12104 + //$$ val buffer = provider.getBuffer(getParticleLayer(renderPass)) + //$$ block(VertexConsumerAdapter(UVertexConsumer.of(buffer))) + //#else //#if MC<11700 val prevAlphaTest = GL11.glGetBoolean(GL11.GL_ALPHA_TEST) val prevAlphaTestFunc = GL11.glGetInteger(GL11.GL_ALPHA_TEST_FUNC) @@ -475,6 +512,7 @@ object MinecraftRenderBackend : RenderBackend { GlStateManager.alphaFunc(prevAlphaTestFunc, prevAlphaTestRef) } //#endif + //#endif } } } \ No newline at end of file diff --git a/src/main/kotlin/gg/essential/model/backend/minecraft/playerPose.kt b/src/main/kotlin/gg/essential/model/backend/minecraft/playerPose.kt index dbb7114..f253f8c 100644 --- a/src/main/kotlin/gg/essential/model/backend/minecraft/playerPose.kt +++ b/src/main/kotlin/gg/essential/model/backend/minecraft/playerPose.kt @@ -16,6 +16,7 @@ import dev.folomeev.kotgl.matrix.vectors.Vec3 import dev.folomeev.kotgl.matrix.vectors.mutables.mutableVec3 import dev.folomeev.kotgl.matrix.vectors.mutables.negate import dev.folomeev.kotgl.matrix.vectors.vec4 +import gg.essential.cosmetics.CosmeticsRenderState import gg.essential.mixins.ext.client.model.geom.ExtraTransformHolder import gg.essential.mixins.impl.client.model.CapePoseSupplier import gg.essential.mixins.impl.client.model.ElytraPoseSupplier @@ -24,7 +25,6 @@ import gg.essential.mixins.transformers.client.model.ModelPlayerAccessor import gg.essential.model.backend.PlayerPose import gg.essential.model.util.getRotationEulerZYX import gg.essential.model.util.times -import net.minecraft.client.entity.AbstractClientPlayer import net.minecraft.client.model.ModelBiped import net.minecraft.client.model.ModelRenderer import net.minecraft.client.renderer.entity.RenderPlayer @@ -225,13 +225,13 @@ fun PlayerPose.withCapePose( } //#endif -fun getElytraPoseOffset(player: AbstractClientPlayer): Vec3 { +fun getElytraPoseOffset(cState: CosmeticsRenderState): Vec3 { val offset = mutableVec3() //#if MC<11400 // When sneaking, the Minecraft renderer shifts the entire model down, the elytra renderer has this assumption // baked in, however our Pose system does not and wants absolute coordinates. - if (player.isSneaking) { + if (cState.isSneaking()) { offset.y -= 0.2f /* from LayerCustomHead */ * 16 /* scale */ } //#endif @@ -245,18 +245,18 @@ fun getElytraPoseOffset(player: AbstractClientPlayer): Vec3 { fun PlayerPose.withElytraPose( leftWing: ModelRenderer, rightWing: ModelRenderer, - player: AbstractClientPlayer, + cState: CosmeticsRenderState, ): PlayerPose { - val offset = getElytraPoseOffset(player) + val offset = getElytraPoseOffset(cState) return copy(leftWing = leftWing.toPose().offset(offset), rightWing = rightWing.toPose().offset(offset)) } fun PlayerPose.applyElytraPose( leftWing: ModelRenderer, rightWing: ModelRenderer, - player: AbstractClientPlayer, + cState: CosmeticsRenderState, ) { - val offset = getElytraPoseOffset(player).negate() + val offset = getElytraPoseOffset(cState).negate() this.leftWing.offset(offset).applyTo(leftWing) this.rightWing.offset(offset).applyTo(rightWing) } diff --git a/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/connectionManager.kt b/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/connectionManager.kt index c0c4218..1e0990f 100644 --- a/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/connectionManager.kt +++ b/src/main/kotlin/gg/essential/network/connectionmanager/cosmetics/connectionManager.kt @@ -51,9 +51,28 @@ fun primeCache(modelLoader: ModelLoader, assetLoader: AssetLoader, cosmetic: Cos } fun ConnectionManager.unlockSpsCosmetics() { - // Current major version of Minecraft (e.g. 1.20) - val currentVersion = VersionData.getMinecraftVersion().split("-", ".").take(2).joinToString(".") - unlock { it.requiredVersion == null || it.requiredVersion == currentVersion } + // Current version of Minecraft (e.g. 1.21.4) as array of ints, [1, 21, 4] or [1, 20] + val currentVersionInts = VersionData.getMinecraftVersion().split("-", ".").map { + it.toIntOrNull() ?: run { + Essential.logger.warn("When unlocking SPS cosmetic the current version could not be parsed from {}", VersionData.getMinecraftVersion()) + return + } + }.take(3) + + unlock { joinSPSProperty -> + val requiredVersionInts = joinSPSProperty.requiredVersion?.split(".")?.map { + it.toIntOrNull() ?: run { + Essential.logger.warn("When unlocking SPS cosmetic the required version could not be parsed from {}", joinSPSProperty) + return@unlock false + } + }?.take(3) ?: return@unlock true + // Major version must match + if (currentVersionInts.take(2) != requiredVersionInts.take(2)) return@unlock false + // If no required minor version, that's it + if (requiredVersionInts.size <= 2) return@unlock true + // Otherwise, check minor version + return@unlock (currentVersionInts.getOrNull(2) ?: 0) >= requiredVersionInts[2] + } } fun ConnectionManager.unlockServerCosmetics(address: String) { diff --git a/src/main/kotlin/gg/essential/util/AutoUpdate.kt b/src/main/kotlin/gg/essential/util/AutoUpdate.kt index be98574..0b04c8f 100644 --- a/src/main/kotlin/gg/essential/util/AutoUpdate.kt +++ b/src/main/kotlin/gg/essential/util/AutoUpdate.kt @@ -13,7 +13,6 @@ package gg.essential.util import gg.essential.Essential import gg.essential.config.EssentialConfig -import gg.essential.connectionmanager.common.packet.mod.ClientModsAnnouncePacket import gg.essential.data.MenuData import gg.essential.data.VersionData import gg.essential.elementa.components.Window @@ -202,13 +201,16 @@ object AutoUpdate { } private fun getEssentialLoaderPlatform(): String { + //#if FABRIC + //$$ return "fabric" + //#else val version = VersionData.getMajorComponents(VersionData.getMinecraftVersion())[1].toInt() return when { - VersionData.getMinecraftPlatform() == ClientModsAnnouncePacket.Platform.FABRIC -> "fabric" version >= 17 -> "modlauncher9" version >= 14 -> "modlauncher8" else -> "launchwrapper" } + //#endif } private fun stage2GameVersion(): String { diff --git a/src/main/kotlin/gg/essential/util/extensions.kt b/src/main/kotlin/gg/essential/util/extensions.kt index f30d021..bf6f21c 100644 --- a/src/main/kotlin/gg/essential/util/extensions.kt +++ b/src/main/kotlin/gg/essential/util/extensions.kt @@ -409,3 +409,10 @@ val GuiScreen?.isMainMenu: Boolean } else { false } + +// Kotlin's `.let { ... }` but for Java +// Wrapped in an object to not accidentally shadow the original. +object Let { + @JvmStatic + fun let(obj: T, block: (T) -> R): R = block(obj) +} diff --git a/src/main/resources/assets/essential/commit.txt b/src/main/resources/assets/essential/commit.txt index 6a3d0fa..1fe4b85 100644 --- a/src/main/resources/assets/essential/commit.txt +++ b/src/main/resources/assets/essential/commit.txt @@ -1 +1 @@ -70b12d2f98 \ No newline at end of file +2cf128d701 \ No newline at end of file diff --git a/src/main/resources/mixins.essential.json b/src/main/resources/mixins.essential.json index f6725af..2c2ee2a 100644 --- a/src/main/resources/mixins.essential.json +++ b/src/main/resources/mixins.essential.json @@ -157,7 +157,7 @@ "events.Mixin_RenderTickEvent_LoadingScreen", "feature.chat.Mixin_ChatPeekScrolling", "feature.cosmetics.Mixin_CutoutCapeTextures", - "feature.cosmetics.Mixin_UpdateOffscreenPlayers", + "feature.cosmetics.Mixin_UpdateCosmetics", "feature.difficulty.client.Mixin_TrackClientDifficultyChanges", "feature.difficulty.server.Mixin_BroadcastServerDifficultyChanges", "feature.difficulty.server.Mixin_RemoveUnsafeDifficultyChecks", diff --git a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/cosmetics/WearablesManager.kt b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/cosmetics/WearablesManager.kt index 098ce11..1fafd79 100644 --- a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/cosmetics/WearablesManager.kt +++ b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/cosmetics/WearablesManager.kt @@ -79,6 +79,20 @@ class WearablesManager( updateState(state.copyWithout(slot)) } + /** @see ModelInstance.update */ + fun update() { + for ((_, model) in models) { + model.update() + } + } + + /** @see ModelInstance.updateLocators */ + fun updateLocators(renderedPose: PlayerPose?) { + for ((_, model) in models) { + model.updateLocators(renderedPose) + } + } + fun render( matrixStack: UMatrixStack, vertexConsumerProvider: RenderBackend.VertexConsumerProvider, diff --git a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/ModelInstance.kt b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/ModelInstance.kt index 481528a..e576dc0 100644 --- a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/ModelInstance.kt +++ b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/ModelInstance.kt @@ -59,25 +59,45 @@ class ModelInstance( return model.computePose(basePose, animationState, entity) } + private var lastUpdateTime = Float.NEGATIVE_INFINITY + /** - * Emits new effects and updates all locators bound to this model instance. + * Updates the state of this model for the current frame prior to rendering. * - * This method needs to be called for models that were not rendered as part of the normal render pass (e.g. because - * the corresponding player was frustum culled), so that particles bound to locators (which may be visible even - * when the player entity that spawned them is not) are update correctly. - * It is safe to call on all models and will simply return without any changes if the model has already been - * rendered this frame. + * Note that new animation events are emitted into [ModelAnimationState.pendingEvents] and the caller needs to + * collect them from there and forward them to the actual particle/sound/etc system at the appropriate time. * - * Note that new effects are merely emitted into [ModelAnimationState.pendingParticles]. - * The caller needs to collect them from there and forward them to the actual particle system. + * Also note that this does **not** yet update the locators bound to this model instance. For that one must call + * [updateLocators] after rendering. + * This is because the position and rotation of locators depends on the final rendered player pose, which is only + * available after rendering. + * Because particle events may depend on the position of locators, they should however ideally be updated before + * particles are updated, rendered, and/or spawned. */ - fun updateEffects() { + fun update() { + val now = entity.lifeTime + if (lastUpdateTime == now) return // was already updated this frame + lastUpdateTime = now + + essentialAnimationSystem.maybeFireTextureAnimationStartEvent() + essentialAnimationSystem.updateAnimationState() animationState.updateEffects() + } + /** + * Updates all locators bound to this model instance. + * + * Note that this method must called for all models, even those that were not actually rendered (e.g. because + * the corresponding player was frustum culled), so that particles bound to locators (which may be visible even + * when the player entity that spawned them is not) are update correctly. + * In such cases where no reliable pose information is available, pass `null`. + */ + fun updateLocators(renderedPose: PlayerPose?) { // Locators are fairly expensive to update, so only do it if we need to if (animationState.locatorsNeedUpdating()) { - val pose = PlayerPose.neutral() // no way for us to get the real pose if we didn't actually render - .copy( + val pose = renderedPose + // No way for us to get the real pose if we didn't actually render, let's just use the neutral pose + ?: PlayerPose.neutral().copy( // Also no way to know if cape/elytra/etc. are visible (not if you consider modded items anyway), // so we'll move those far away so any events they spawn won't be visible. rightShoulderEntity = PlayerPose.Part.MISSING, @@ -99,8 +119,6 @@ class ModelInstance( rootBone: Bone, renderMetadata: RenderMetadata, ) { - essentialAnimationSystem.maybeFireTextureAnimationStartEvent() - essentialAnimationSystem.updateAnimationState() animationState.apply(rootBone, false) for (bone in model.getBones(rootBone)) { @@ -119,8 +137,5 @@ class ModelInstance( renderMetadata, textureAnimationSync.getAdjustedLifetime(entity.lifeTime), ) - - animationState.updateEffects() - animationState.updateLocators(rootBone, renderMetadata.scale) } } \ No newline at end of file diff --git a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/util/PlayerPoseManager.kt b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/util/PlayerPoseManager.kt index e2ee1ae..9813146 100644 --- a/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/util/PlayerPoseManager.kt +++ b/subprojects/cosmetics/src/commonMain/kotlin/gg/essential/model/util/PlayerPoseManager.kt @@ -97,14 +97,14 @@ class PlayerPoseManager( * Computes the final pose for the player based on their vanilla [basePose], equipped cosmetics, * the current emote and, if not yet fully transitioned, the previous emote. */ - fun computePose(wearablesManager: WearablesManager, basePose: PlayerPose): PlayerPose { + fun computePose(wearablesManager: WearablesManager?, basePose: PlayerPose): PlayerPose { var transformedPose = basePose // Apply interpolated emote pose transformedPose = computePose(transformedPose) // Apply pose animations from all other cosmetics (if any) - for ((cosmetic, model) in wearablesManager.models) { + for ((cosmetic, model) in wearablesManager?.models ?: emptyMap()) { if (cosmetic.type.slot == CosmeticSlot.EMOTE) { continue // already handled separately before the loop } diff --git a/subprojects/infra/src/main/kotlin/gg/essential/network/Call.kt b/subprojects/infra/src/main/kotlin/gg/essential/network/Call.kt index fb1c3bd..758be88 100644 --- a/subprojects/infra/src/main/kotlin/gg/essential/network/Call.kt +++ b/subprojects/infra/src/main/kotlin/gg/essential/network/Call.kt @@ -68,7 +68,7 @@ class Call( LOGGER.error("Got unexpected reply $response for $packet") cont.resume(null) } else { - cont.resumeWithException(UnexpectedResponseException(response)) + cont.resumeWithException(UnexpectedResponseException(packet, response)) } } } @@ -100,4 +100,4 @@ class CallWithRetry( } } -class UnexpectedResponseException(val response: Packet) : Exception() +class UnexpectedResponseException(val request: Packet, val response: Packet) : Exception("Unexpected response $response for $request") diff --git a/versions/1.12.2-1.8.9.txt b/versions/1.12.2-1.8.9.txt index 94530bf..36913d6 100644 --- a/versions/1.12.2-1.8.9.txt +++ b/versions/1.12.2-1.8.9.txt @@ -1,3 +1,4 @@ +net.minecraft.client.renderer.entity.layers.LayerArmorBase renderArmorLayer() renderLayer() net.minecraft.util.text.TextFormatting net.minecraft.util.EnumChatFormatting net.minecraft.client.renderer.ItemRenderer renderArm() renderPlayerArm() net.minecraft.client.renderer.ItemRenderer renderArmFirstPerson() renderPlayerArms() diff --git a/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java b/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java index 4695291..b9d3933 100644 --- a/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java +++ b/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java @@ -13,9 +13,11 @@ import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.matrix.MatrixStack; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.handlers.OnlineIndicator; import gg.essential.universal.UMatrixStack; import gg.essential.universal.wrappers.message.UTextComponent; +import net.minecraft.client.entity.player.AbstractClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.entity.Entity; @@ -44,7 +46,10 @@ public class Mixin_RenderNameplateIcon { ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ Entity entity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entity instanceof AbstractClientPlayerEntity)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayerEntity) entity); //#endif } @@ -66,10 +71,13 @@ private void renderEssentialIndicator( ) { //#if MC>=12102 //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ Entity entity = ((PlayerEntityRenderStateExt) state).essential$getEntity(); + //$$ CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + //#else + if (!(entity instanceof AbstractClientPlayerEntity)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayerEntity) entity); //#endif if (OnlineIndicator.currentlyDrawingEntityName()) { - OnlineIndicator.drawNametagIndicator(new UMatrixStack(vMatrixStack), bufferIn, entity, new UTextComponent(name.deepCopy()).getFormattedText(), packedLightIn); + OnlineIndicator.drawNametagIndicator(new UMatrixStack(vMatrixStack), bufferIn, cState, new UTextComponent(name.deepCopy()).getFormattedText(), packedLightIn); } } } diff --git a/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java b/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java deleted file mode 100644 index 7d4ac89..0000000 --- a/versions/1.16.2-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_StoreArmorRenderedState.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2024 ModCore Inc. All rights reserved. - * - * This code is part of ModCore Inc.'s Essential Mod repository and is protected - * under copyright registration # TX0009138511. For the full license, see: - * https://github.com/EssentialGG/Essential/blob/main/LICENSE - * - * You may not use, copy, reproduce, modify, sell, license, distribute, - * commercialize, or otherwise exploit, or create derivative works based - * upon, this file or any other in this repository, all of which is reserved by Essential. - */ -package gg.essential.mixins.transformers.client.renderer.entity; - -import com.llamalad7.mixinextras.sugar.Local; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; -import net.minecraft.client.renderer.entity.layers.BipedArmorLayer; -import net.minecraft.entity.LivingEntity; -import net.minecraft.inventory.EquipmentSlotType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -//#if MC>=12102 -//$$ import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; -//$$ import net.minecraft.client.render.entity.state.BipedEntityRenderState; -//#endif - -@Mixin(BipedArmorLayer.class) -public abstract class Mixin_StoreArmorRenderedState { - - private static final ThreadLocal playerThreadLocal = new ThreadLocal<>(); - - //#if MC>=12102 - //$$ private static final String RENDER = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V"; - //#else - private static final String RENDER = "render(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/entity/LivingEntity;FFFFFF)V"; - //#endif - - @Inject(method = RENDER, at = @At("HEAD")) - private void essential$assumeArmorRenderingSuppressed( - CallbackInfo ci, - //#if MC>=12102 - //$$ @Local(argsOnly = true) BipedEntityRenderState state - //#else - @Local(argsOnly = true) LivingEntity entitylivingbaseIn - //#endif - ) { - //#if MC>=12102 - //$$ if (!(state instanceof PlayerEntityRenderStateExt)) return; - //$$ LivingEntity entitylivingbaseIn = ((PlayerEntityRenderStateExt) state).essential$getEntity(); - //#endif - if (entitylivingbaseIn instanceof AbstractClientPlayerExt) { - final AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) entitylivingbaseIn; - playerThreadLocal.set(playerExt); - playerExt.assumeArmorRenderingSuppressed(); - } - } - - @Inject(method = RENDER, at = @At("RETURN")) - private void resetThreadLocal(CallbackInfo ci) { - playerThreadLocal.remove(); - } - - @Inject(method = "func_241739_a_", at = @At(value = "HEAD", shift = At.Shift.AFTER)) - private void essential$markRenderingNotSuppressed( - CallbackInfo ci, - @Local(argsOnly = true) EquipmentSlotType arg4 - ) { - AbstractClientPlayerExt playerExt = playerThreadLocal.get(); - if (playerExt != null) { - if (arg4.getSlotType() == EquipmentSlotType.Group.ARMOR) { - playerExt.armorRenderingNotSuppressed(arg4.getIndex()); - } - } - } -} diff --git a/versions/1.20.2-fabric/src/main/java/gg/essential/mixins/transformers/client/resources/Mixin_InstantSkinLoad.java b/versions/1.20.2-fabric/src/main/java/gg/essential/mixins/transformers/client/resources/Mixin_InstantSkinLoad.java index 3af6e3a..397c616 100644 --- a/versions/1.20.2-fabric/src/main/java/gg/essential/mixins/transformers/client/resources/Mixin_InstantSkinLoad.java +++ b/versions/1.20.2-fabric/src/main/java/gg/essential/mixins/transformers/client/resources/Mixin_InstantSkinLoad.java @@ -30,7 +30,7 @@ public class Mixin_InstantSkinLoad { // expiry time is the SkinTextures and a wrapper CompletableFuture. // As such, there should not be much harm in substantially increasing this value to prevent already loaded skins // from taking a frame (or more) to actually show up on newly created (UI3D)players. - //#if MC>12102 + //#if MC>12104 //$$ TODO verify above is still the case / if this is still necessary //#endif @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lcom/google/common/cache/CacheBuilder;expireAfterAccess(Ljava/time/Duration;)Lcom/google/common/cache/CacheBuilder;")) diff --git a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt.java b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt.java index 8ef6a42..7e0ac62 100644 --- a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt.java +++ b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt.java @@ -11,8 +11,8 @@ */ package gg.essential.mixins.transformers.client.model; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; -import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -20,27 +20,10 @@ @Mixin(PlayerEntityRenderState.class) public abstract class Mixin_PlayerEntityRenderStateExt implements PlayerEntityRenderStateExt { @Unique - private AbstractClientPlayerEntity entity; - @Unique - private float tickDelta; - - @Override - public AbstractClientPlayerEntity essential$getEntity() { - return this.entity; - } - - @Override - public void essential$setEntity(AbstractClientPlayerEntity entity) { - this.entity = entity; - } - - @Override - public float essential$getTickDelta() { - return this.tickDelta; - } + private final CosmeticsRenderState.Snapshot cosmeticsRenderState = new CosmeticsRenderState.Snapshot(); @Override - public void essential$setTickDelta(float tickDelta) { - this.tickDelta = tickDelta; + public CosmeticsRenderState.Snapshot essential$getCosmetics() { + return cosmeticsRenderState; } } diff --git a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt_UpdateRenderState.java b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt_UpdateRenderState.java index e02360e..d9105ad 100644 --- a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt_UpdateRenderState.java +++ b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/model/Mixin_PlayerEntityRenderStateExt_UpdateRenderState.java @@ -25,7 +25,6 @@ public abstract class Mixin_PlayerEntityRenderStateExt_UpdateRenderState { @Inject(method = "updateRenderState(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;F)V", at = @At("HEAD")) private void updateEssentialRenderState(AbstractClientPlayerEntity entity, PlayerEntityRenderState state, float tickDelta, CallbackInfo ci) { PlayerEntityRenderStateExt stateExt = (PlayerEntityRenderStateExt) state; - stateExt.essential$setEntity(entity); - stateExt.essential$setTickDelta(tickDelta); + stateExt.essential$getCosmetics().update(entity); } } diff --git a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java index f8da7b7..6cec974 100644 --- a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java +++ b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_ApplyPoseTransform_Cape.java @@ -16,14 +16,12 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import dev.folomeev.kotgl.matrix.vectors.Vec3; -import gg.essential.config.EssentialConfig; -import gg.essential.gui.common.EmulatedUI3DPlayer; -import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.CapePoseSupplier; import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; import gg.essential.model.backend.PlayerPose; import gg.essential.model.backend.minecraft.PlayerPoseKt; -import net.minecraft.client.network.AbstractClientPlayerEntity; +import gg.essential.model.util.PlayerPoseManager; import net.minecraft.client.model.ModelPart; import net.minecraft.client.render.entity.feature.CapeFeatureRenderer; import net.minecraft.client.render.entity.model.BipedEntityModel; @@ -68,10 +66,9 @@ private void applyPoseTransform( @Local(argsOnly = true) PlayerEntityRenderState state, @Share("offset") LocalRef offset ) { - AbstractClientPlayerEntity player = ((PlayerEntityRenderStateExt) state).essential$getEntity(); - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) player; - - if (EssentialConfig.INSTANCE.getDisableEmotes() && !(player instanceof EmulatedUI3DPlayer.EmulatedPlayer)) { + CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + PlayerPoseManager poseManager = cState.poseManager(); + if (poseManager == null) { return; } @@ -84,7 +81,7 @@ private void applyPoseTransform( } PlayerPose basePose = PlayerPoseKt.withCapePose(PlayerPose.Companion.neutral(), extraOffset, bodyModel, capeModel); - PlayerPose transformedPose = playerExt.getPoseManager().computePose(playerExt.getWearablesManager(), basePose); + PlayerPose transformedPose = poseManager.computePose(cState.wearablesManager(), basePose); renderedPose = transformedPose.getCape(); diff --git a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java index 3fcec4d..4993073 100644 --- a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java +++ b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_DisableArmorRendering.java @@ -13,11 +13,10 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.PlayerEntityRenderStateExt; -import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.render.entity.state.BipedEntityRenderState; import net.minecraft.client.util.math.MatrixStack; -import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; import net.minecraft.client.render.entity.model.BipedEntityModel; @@ -37,7 +36,7 @@ public abstract class Mixin_DisableArmorRendering=12104 +//$$ import net.minecraft.item.equipment.EquipmentAsset; +//$$ import net.minecraft.registry.RegistryKey; +//#endif @Mixin(ElytraFeatureRenderer.class) public abstract class Mixin_Emissive_Elytra { private static final String RENDER_LAYER = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V"; + //#if MC>=12104 + //$$ private static final String RENDER_ELYTRA = "Lnet/minecraft/client/render/entity/equipment/EquipmentRenderer;render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V"; + //#else private static final String RENDER_ELYTRA = "Lnet/minecraft/client/render/entity/equipment/EquipmentRenderer;render(Lnet/minecraft/item/equipment/EquipmentModel$LayerType;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V"; + //#endif @WrapOperation(method = RENDER_LAYER, at = @At(value = "INVOKE", target = RENDER_ELYTRA)) private void renderWithEmissiveLayer( EquipmentRenderer equipmentRenderer, EquipmentModel.LayerType layerType, + //#if MC>=12104 + //$$ RegistryKey modelId, + //#else Identifier modelId, + //#endif Model model, ItemStack stack, MatrixStack matrices, @@ -71,14 +81,13 @@ private void renderWithEmissiveLayer( if (!(state instanceof PlayerEntityRenderStateExt)) { return; } - AbstractClientPlayerExt playerExt = (AbstractClientPlayerExt) ((PlayerEntityRenderStateExt) state).essential$getEntity(); - UIdentifier emissiveTexture = playerExt.getEmissiveCapeTexture(); + CosmeticsRenderState cState = ((PlayerEntityRenderStateExt) state).essential$getCosmetics(); + Identifier emissiveTexture = cState.emissiveCapeTexture(); if (emissiveTexture == null) { return; } - Identifier emissiveTextureMc = toMC(emissiveTexture); - RenderLayer vanillaLayer = RenderLayer.getArmorCutoutNoCull(emissiveTextureMc); + RenderLayer vanillaLayer = RenderLayer.getArmorCutoutNoCull(emissiveTexture); original.call( equipmentRenderer, @@ -89,13 +98,13 @@ private void renderWithEmissiveLayer( matrices, (VertexConsumerProvider) layer -> { if (layer == vanillaLayer) { - return vertexConsumers.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveArmorLayer(emissiveTextureMc)); + return vertexConsumers.getBuffer(MinecraftRenderBackend.INSTANCE.getEmissiveArmorLayer(emissiveTexture)); } else { return MinecraftRenderBackend.NullMcVertexConsumer.INSTANCE; } }, light, - emissiveTextureMc + emissiveTexture ); } } diff --git a/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java new file mode 100644 index 0000000..ff33755 --- /dev/null +++ b/versions/1.21.2-fabric/src/main/java/gg/essential/mixins/transformers/cosmetics/skinmask/Mixin_ApplyToPlayerRenderer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 ModCore Inc. All rights reserved. + * + * This code is part of ModCore Inc.'s Essential Mod repository and is protected + * under copyright registration # TX0009138511. For the full license, see: + * https://github.com/EssentialGG/Essential/blob/main/LICENSE + * + * You may not use, copy, reproduce, modify, sell, license, distribute, + * commercialize, or otherwise exploit, or create derivative works based + * upon, this file or any other in this repository, all of which is reserved by Essential. + */ +package gg.essential.mixins.transformers.cosmetics.skinmask; + +import gg.essential.mixins.impl.client.entity.AbstractClientPlayerExt; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.entity.PlayerEntityRenderer; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.client.util.SkinTextures; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerEntityRenderer.class) +public abstract class Mixin_ApplyToPlayerRenderer { + @Inject(method = "updateRenderState(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;F)V", at = @At("RETURN")) + private void applyCosmeticsSkinMask(AbstractClientPlayerEntity entity, PlayerEntityRenderState state, float partialTicks, CallbackInfo ci) { + SkinTextures textures = state.skinTextures; + Identifier orgTexture = textures.texture(); + Identifier newTexture = ((AbstractClientPlayerExt) entity).applyEssentialCosmeticsMask(orgTexture); + if (orgTexture != newTexture) { + state.skinTextures = new SkinTextures(newTexture, textures.textureUrl(), textures.capeTexture(), textures.elytraTexture(), textures.model(), textures.secure()); + } + } +} diff --git a/versions/1.21.4-1.21.2.txt b/versions/1.21.4-1.21.2.txt new file mode 100644 index 0000000..742599c --- /dev/null +++ b/versions/1.21.4-1.21.2.txt @@ -0,0 +1,2 @@ +net.minecraft.resource.metadata.ResourceMetadataSerializer net.minecraft.resource.metadata.ResourceMetadataReader +net.minecraft.client.gui.widget.EntryListWidget getContentsHeightWithPadding() getMaxPosition() diff --git a/versions/1.21.4-fabric/gradle.properties b/versions/1.21.4-fabric/gradle.properties new file mode 100644 index 0000000..4fa1f0d --- /dev/null +++ b/versions/1.21.4-fabric/gradle.properties @@ -0,0 +1,2 @@ +essential.defaults.loom.minecraft=com.mojang:minecraft:1.21.4-rc3 +essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.4-rc3+build.3:v2 diff --git a/src/main/java/gg/essential/cosmetics/source/CosmeticsSource.java b/versions/1.21.4-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/MixinPlayerSkinTexture.java similarity index 53% rename from src/main/java/gg/essential/cosmetics/source/CosmeticsSource.java rename to versions/1.21.4-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/MixinPlayerSkinTexture.java index 7475a4d..da0df3f 100644 --- a/src/main/java/gg/essential/cosmetics/source/CosmeticsSource.java +++ b/versions/1.21.4-fabric/src/main/java/gg/essential/mixins/transformers/client/renderer/MixinPlayerSkinTexture.java @@ -9,18 +9,11 @@ * commercialize, or otherwise exploit, or create derivative works based * upon, this file or any other in this repository, all of which is reserved by Essential. */ -package gg.essential.cosmetics.source; +package gg.essential.mixins.transformers.client.renderer; -import com.google.common.collect.ImmutableMap; -import gg.essential.mod.cosmetics.CosmeticSlot; -import gg.essential.cosmetics.EquippedCosmetic; -import org.jetbrains.annotations.NotNull; +import gg.essential.mixins.DummyTarget; +import org.spongepowered.asm.mixin.Mixin; -public interface CosmeticsSource { - @NotNull - ImmutableMap getCosmetics(); - - boolean getShouldOverrideRenderCosmeticsCheck(); - - CosmeticsSource EMPTY = new ConfigurableCosmeticsSource(); +@Mixin(DummyTarget.class) +public class MixinPlayerSkinTexture { } diff --git a/versions/1.21.4-fabric/src/main/kotlin/gg/essential/mixins/ext/client/renderer/PlayerSkinTextureExt.kt b/versions/1.21.4-fabric/src/main/kotlin/gg/essential/mixins/ext/client/renderer/PlayerSkinTextureExt.kt new file mode 100644 index 0000000..f758f42 --- /dev/null +++ b/versions/1.21.4-fabric/src/main/kotlin/gg/essential/mixins/ext/client/renderer/PlayerSkinTextureExt.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 ModCore Inc. All rights reserved. + * + * This code is part of ModCore Inc.'s Essential Mod repository and is protected + * under copyright registration # TX0009138511. For the full license, see: + * https://github.com/EssentialGG/Essential/blob/main/LICENSE + * + * You may not use, copy, reproduce, modify, sell, license, distribute, + * commercialize, or otherwise exploit, or create derivative works based + * upon, this file or any other in this repository, all of which is reserved by Essential. + */ +package gg.essential.mixins.ext.client.renderer + diff --git a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinCustomLayerBipedArmor.java b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinCustomLayerBipedArmor.java index 44c7df5..f45ec27 100644 --- a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinCustomLayerBipedArmor.java +++ b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinCustomLayerBipedArmor.java @@ -11,7 +11,8 @@ */ package gg.essential.mixins.modcompat.transformers.oldanimationsmod; -import gg.essential.mixins.impl.client.renderer.entity.ArmorRenderingUtil; +import gg.essential.cosmetics.CosmeticsRenderState; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; @@ -26,7 +27,7 @@ public class MixinCustomLayerBipedArmor { @Inject(method = "renderLayer", at = @At(value = "HEAD"), cancellable = true) private void essential$disableArmorRendering( - EntityLivingBase entityLivingBaseIn, + EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, @@ -37,8 +38,10 @@ public class MixinCustomLayerBipedArmor { int slotIn, CallbackInfo info ) { + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); int slotIndex = slotIn - 1; - if (ArmorRenderingUtil.shouldDisableArmor(entityLivingBaseIn, slotIndex)) { + if (cState.blockedArmorSlots().contains(slotIndex)) { info.cancel(); } } diff --git a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinModelMethods.java b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinModelMethods.java index 6e6596c..bda05dd 100644 --- a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinModelMethods.java +++ b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/modcompat/transformers/oldanimationsmod/MixinModelMethods.java @@ -11,7 +11,9 @@ */ package gg.essential.mixins.modcompat.transformers.oldanimationsmod; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.mixins.impl.client.model.ModelBipedUtil; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.model.ModelBiped; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -52,6 +54,8 @@ private static void applyPoseTransform( Entity entity, CallbackInfo ci ) { - ModelBipedUtil.applyPoseTransform(model, entity); + if (!(entity instanceof AbstractClientPlayer)) return; + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entity); + ModelBipedUtil.applyPoseTransform(model, cState); } } diff --git a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java index 1e4ae77..4e2dbc5 100644 --- a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java +++ b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon.java @@ -12,8 +12,10 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.handlers.OnlineIndicator; import gg.essential.universal.UMatrixStack; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.entity.Entity; @@ -30,9 +32,10 @@ public class Mixin_RenderNameplateIcon { @Inject(method = "renderLivingLabel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;enableLighting()V")) private void renderEssentialIndicator(T entityIn, String str, double x, double y, double z, int maxDistance, CallbackInfo ci) { - if (OnlineIndicator.currentlyDrawingEntityName()) { + if (OnlineIndicator.currentlyDrawingEntityName() && entityIn instanceof AbstractClientPlayer) { + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entityIn); int light = (((int) OpenGlHelper.lastBrightnessY) << 16) + (int) OpenGlHelper.lastBrightnessX; - OnlineIndicator.drawNametagIndicator(new UMatrixStack(), entityIn, str, light); + OnlineIndicator.drawNametagIndicator(new UMatrixStack(), cState, str, light); } } } diff --git a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon_Sneaking.java b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon_Sneaking.java index 9df5f35..47f88c4 100644 --- a/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon_Sneaking.java +++ b/versions/1.8.9-forge/src/main/java/gg/essential/mixins/transformers/client/renderer/entity/Mixin_RenderNameplateIcon_Sneaking.java @@ -12,12 +12,13 @@ package gg.essential.mixins.transformers.client.renderer.entity; import com.llamalad7.mixinextras.sugar.Local; +import gg.essential.cosmetics.CosmeticsRenderState; import gg.essential.handlers.OnlineIndicator; import gg.essential.universal.UMatrixStack; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.entity.RendererLivingEntity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -32,9 +33,10 @@ public class Mixin_RenderNameplateIcon_Sneaking { @Inject(method = "renderName(Lnet/minecraft/entity/EntityLivingBase;DDD)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;enableLighting()V")) private void renderEssentialIndicator(T entityIn, double x, double y, double z, CallbackInfo ci, @Local String str) { - if (entityIn instanceof EntityPlayer) { + if (entityIn instanceof AbstractClientPlayer) { + CosmeticsRenderState cState = new CosmeticsRenderState.Live((AbstractClientPlayer) entityIn); int light = (((int) OpenGlHelper.lastBrightnessY) << 16) + (int) OpenGlHelper.lastBrightnessX; - OnlineIndicator.drawNametagIndicator(new UMatrixStack(), entityIn, str, light); + OnlineIndicator.drawNametagIndicator(new UMatrixStack(), cState, str, light); } } } diff --git a/versions/api/1.21.4-fabric/gradle.properties b/versions/api/1.21.4-fabric/gradle.properties new file mode 100644 index 0000000..4fa1f0d --- /dev/null +++ b/versions/api/1.21.4-fabric/gradle.properties @@ -0,0 +1,2 @@ +essential.defaults.loom.minecraft=com.mojang:minecraft:1.21.4-rc3 +essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.4-rc3+build.3:v2