2025-11-24 22:52:51 +03:00

138 lines
7.8 KiB
Java

/*
* 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<SkullBlockEntity, SkullBlockRenderState> {
private final Function<SkullBlock.Type, SkullModelBase> modelByType;
private static final Map<SkullBlock.Type, Identifier> 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);
}
}