package net.minecraft.client.renderer.special; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.serialization.MapCodec; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.model.SkullModelBase; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.client.resources.PlayerSkin; import net.minecraft.client.resources.SkinManager; import net.minecraft.core.component.DataComponents; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.block.SkullBlock; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; @Environment(EnvType.CLIENT) public class PlayerHeadSpecialRenderer implements SpecialModelRenderer { private final Map updatedResolvableProfiles = new HashMap(); private final SkinManager skinManager; private final SkullModelBase modelBase; private final PlayerHeadSpecialRenderer.PlayerHeadRenderInfo defaultPlayerHeadRenderInfo; PlayerHeadSpecialRenderer(SkinManager skinManager, SkullModelBase modelBase, PlayerHeadSpecialRenderer.PlayerHeadRenderInfo defaultPlayerHeadRenderInfo) { this.skinManager = skinManager; this.modelBase = modelBase; this.defaultPlayerHeadRenderInfo = defaultPlayerHeadRenderInfo; } public void render( @Nullable PlayerHeadSpecialRenderer.PlayerHeadRenderInfo patterns, ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, boolean hasFoilType ) { PlayerHeadSpecialRenderer.PlayerHeadRenderInfo playerHeadRenderInfo = (PlayerHeadSpecialRenderer.PlayerHeadRenderInfo)Objects.requireNonNullElse( patterns, this.defaultPlayerHeadRenderInfo ); RenderType renderType = playerHeadRenderInfo.renderType(); SkullBlockRenderer.renderSkull(null, 180.0F, 0.0F, poseStack, bufferSource, packedLight, this.modelBase, renderType); } @Override public void getExtents(Set output) { PoseStack poseStack = new PoseStack(); poseStack.translate(0.5F, 0.0F, 0.5F); poseStack.scale(-1.0F, -1.0F, 1.0F); this.modelBase.root().getExtentsForGui(poseStack, output); } @Nullable public PlayerHeadSpecialRenderer.PlayerHeadRenderInfo extractArgument(ItemStack stack) { ResolvableProfile resolvableProfile = stack.get(DataComponents.PROFILE); if (resolvableProfile == null) { return null; } else { PlayerHeadSpecialRenderer.PlayerHeadRenderInfo playerHeadRenderInfo = (PlayerHeadSpecialRenderer.PlayerHeadRenderInfo)this.updatedResolvableProfiles .get(resolvableProfile); if (playerHeadRenderInfo != null) { return playerHeadRenderInfo; } else { ResolvableProfile resolvableProfile2 = resolvableProfile.pollResolve(); return resolvableProfile2 != null ? this.createAndCacheIfTextureIsUnpacked(resolvableProfile2) : null; } } } @Nullable private PlayerHeadSpecialRenderer.PlayerHeadRenderInfo createAndCacheIfTextureIsUnpacked(ResolvableProfile profile) { PlayerSkin playerSkin = this.skinManager.getInsecureSkin(profile.gameProfile(), null); if (playerSkin != null) { PlayerHeadSpecialRenderer.PlayerHeadRenderInfo playerHeadRenderInfo = PlayerHeadSpecialRenderer.PlayerHeadRenderInfo.create(playerSkin); this.updatedResolvableProfiles.put(profile, playerHeadRenderInfo); return playerHeadRenderInfo; } else { return null; } } @Environment(EnvType.CLIENT) public record PlayerHeadRenderInfo(RenderType renderType) { static PlayerHeadSpecialRenderer.PlayerHeadRenderInfo create(PlayerSkin skin) { return new PlayerHeadSpecialRenderer.PlayerHeadRenderInfo(SkullBlockRenderer.getPlayerSkinRenderType(skin.texture())); } } @Environment(EnvType.CLIENT) public record Unbaked() implements SpecialModelRenderer.Unbaked { public static final MapCodec MAP_CODEC = MapCodec.unit(PlayerHeadSpecialRenderer.Unbaked::new); @Override public MapCodec type() { return MAP_CODEC; } @Nullable @Override public SpecialModelRenderer bake(EntityModelSet modelSet) { SkullModelBase skullModelBase = SkullBlockRenderer.createModel(modelSet, SkullBlock.Types.PLAYER); return skullModelBase == null ? null : new PlayerHeadSpecialRenderer( Minecraft.getInstance().getSkinManager(), skullModelBase, PlayerHeadSpecialRenderer.PlayerHeadRenderInfo.create(DefaultPlayerSkin.getDefaultSkin()) ); } } }