138 lines
7.8 KiB
Java
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);
|
|
}
|
|
}
|
|
|