/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.Maps * org.jspecify.annotations.Nullable */ package net.minecraft.client.renderer.blockentity; import com.google.common.collect.Maps; import com.mojang.blaze3d.vertex.PoseStack; import java.util.Map; import java.util.function.Function; import net.minecraft.client.model.PiglinHeadModel; import net.minecraft.client.model.SkullModel; import net.minecraft.client.model.SkullModelBase; import net.minecraft.client.model.dragon.DragonHeadModel; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.renderer.PlayerSkinRenderCache; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.state.SkullBlockRenderState; import net.minecraft.client.renderer.feature.ModelFeatureRenderer; import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.client.renderer.state.CameraRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; import net.minecraft.util.Util; import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.block.AbstractSkullBlock; import net.minecraft.world.level.block.SkullBlock; import net.minecraft.world.level.block.WallSkullBlock; import net.minecraft.world.level.block.entity.SkullBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.RotationSegment; import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; public class SkullBlockRenderer implements BlockEntityRenderer { private final Function modelByType; private static final Map SKIN_BY_TYPE = Util.make(Maps.newHashMap(), map -> { map.put(SkullBlock.Types.SKELETON, Identifier.withDefaultNamespace("textures/entity/skeleton/skeleton.png")); map.put(SkullBlock.Types.WITHER_SKELETON, Identifier.withDefaultNamespace("textures/entity/skeleton/wither_skeleton.png")); map.put(SkullBlock.Types.ZOMBIE, Identifier.withDefaultNamespace("textures/entity/zombie/zombie.png")); map.put(SkullBlock.Types.CREEPER, Identifier.withDefaultNamespace("textures/entity/creeper/creeper.png")); map.put(SkullBlock.Types.DRAGON, Identifier.withDefaultNamespace("textures/entity/enderdragon/dragon.png")); map.put(SkullBlock.Types.PIGLIN, Identifier.withDefaultNamespace("textures/entity/piglin/piglin.png")); map.put(SkullBlock.Types.PLAYER, DefaultPlayerSkin.getDefaultTexture()); }); private final PlayerSkinRenderCache playerSkinRenderCache; public static @Nullable SkullModelBase createModel(EntityModelSet modelSet, SkullBlock.Type type) { if (type instanceof SkullBlock.Types) { SkullBlock.Types vanillaType = (SkullBlock.Types)type; return switch (vanillaType) { default -> throw new MatchException(null, null); case SkullBlock.Types.SKELETON -> new SkullModel(modelSet.bakeLayer(ModelLayers.SKELETON_SKULL)); case SkullBlock.Types.WITHER_SKELETON -> new SkullModel(modelSet.bakeLayer(ModelLayers.WITHER_SKELETON_SKULL)); case SkullBlock.Types.PLAYER -> new SkullModel(modelSet.bakeLayer(ModelLayers.PLAYER_HEAD)); case SkullBlock.Types.ZOMBIE -> new SkullModel(modelSet.bakeLayer(ModelLayers.ZOMBIE_HEAD)); case SkullBlock.Types.CREEPER -> new SkullModel(modelSet.bakeLayer(ModelLayers.CREEPER_HEAD)); case SkullBlock.Types.DRAGON -> new DragonHeadModel(modelSet.bakeLayer(ModelLayers.DRAGON_SKULL)); case SkullBlock.Types.PIGLIN -> new PiglinHeadModel(modelSet.bakeLayer(ModelLayers.PIGLIN_HEAD)); }; } return null; } public SkullBlockRenderer(BlockEntityRendererProvider.Context context) { EntityModelSet modelSet = context.entityModelSet(); this.playerSkinRenderCache = context.playerSkinRenderCache(); this.modelByType = Util.memoize(type -> SkullBlockRenderer.createModel(modelSet, type)); } @Override public SkullBlockRenderState createRenderState() { return new SkullBlockRenderState(); } @Override public void extractRenderState(SkullBlockEntity blockEntity, SkullBlockRenderState state, float partialTicks, Vec3 cameraPosition, @Nullable ModelFeatureRenderer.CrumblingOverlay breakProgress) { BlockEntityRenderer.super.extractRenderState(blockEntity, state, partialTicks, cameraPosition, breakProgress); state.animationProgress = blockEntity.getAnimation(partialTicks); BlockState blockState = blockEntity.getBlockState(); boolean isWallSkull = blockState.getBlock() instanceof WallSkullBlock; state.direction = isWallSkull ? blockState.getValue(WallSkullBlock.FACING) : null; int rotationSegment = isWallSkull ? RotationSegment.convertToSegment(state.direction.getOpposite()) : blockState.getValue(SkullBlock.ROTATION); state.rotationDegrees = RotationSegment.convertToDegrees(rotationSegment); state.skullType = ((AbstractSkullBlock)blockState.getBlock()).getType(); state.renderType = this.resolveSkullRenderType(state.skullType, blockEntity); } @Override public void submit(SkullBlockRenderState state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) { SkullModelBase model = this.modelByType.apply(state.skullType); SkullBlockRenderer.submitSkull(state.direction, state.rotationDegrees, state.animationProgress, poseStack, submitNodeCollector, state.lightCoords, model, state.renderType, 0, state.breakProgress); } public static void submitSkull(@Nullable Direction direction, float rot, float animationValue, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, SkullModelBase model, RenderType renderType, int outlineColor, @Nullable ModelFeatureRenderer.CrumblingOverlay breakProgress) { poseStack.pushPose(); if (direction == null) { poseStack.translate(0.5f, 0.0f, 0.5f); } else { float offset = 0.25f; poseStack.translate(0.5f - (float)direction.getStepX() * 0.25f, 0.25f, 0.5f - (float)direction.getStepZ() * 0.25f); } poseStack.scale(-1.0f, -1.0f, 1.0f); SkullModelBase.State modelState = new SkullModelBase.State(); modelState.animationPos = animationValue; modelState.yRot = rot; submitNodeCollector.submitModel(model, modelState, poseStack, renderType, lightCoords, OverlayTexture.NO_OVERLAY, outlineColor, breakProgress); poseStack.popPose(); } private RenderType resolveSkullRenderType(SkullBlock.Type type, SkullBlockEntity entity) { ResolvableProfile ownerProfile; if (type == SkullBlock.Types.PLAYER && (ownerProfile = entity.getOwnerProfile()) != null) { return this.playerSkinRenderCache.getOrDefault(ownerProfile).renderType(); } return SkullBlockRenderer.getSkullRenderType(type, null); } public static RenderType getSkullRenderType(SkullBlock.Type type, @Nullable Identifier texture) { return RenderTypes.entityCutoutNoCullZOffset(texture != null ? texture : SKIN_BY_TYPE.get(type)); } public static RenderType getPlayerSkinRenderType(Identifier texture) { return RenderTypes.entityTranslucent(texture); } }