119 lines
6 KiB
Java
119 lines
6 KiB
Java
package net.minecraft.client.renderer.blockentity;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
import java.util.Map;
|
|
import java.util.function.Function;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.Minecraft;
|
|
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.MultiBufferSource;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
|
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
|
import net.minecraft.client.resources.DefaultPlayerSkin;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
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.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class SkullBlockRenderer implements BlockEntityRenderer<SkullBlockEntity> {
|
|
private final Function<SkullBlock.Type, SkullModelBase> modelByType;
|
|
private static final Map<SkullBlock.Type, ResourceLocation> SKIN_BY_TYPE = Util.make(Maps.<SkullBlock.Type, ResourceLocation>newHashMap(), hashMap -> {
|
|
hashMap.put(SkullBlock.Types.SKELETON, ResourceLocation.withDefaultNamespace("textures/entity/skeleton/skeleton.png"));
|
|
hashMap.put(SkullBlock.Types.WITHER_SKELETON, ResourceLocation.withDefaultNamespace("textures/entity/skeleton/wither_skeleton.png"));
|
|
hashMap.put(SkullBlock.Types.ZOMBIE, ResourceLocation.withDefaultNamespace("textures/entity/zombie/zombie.png"));
|
|
hashMap.put(SkullBlock.Types.CREEPER, ResourceLocation.withDefaultNamespace("textures/entity/creeper/creeper.png"));
|
|
hashMap.put(SkullBlock.Types.DRAGON, ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon.png"));
|
|
hashMap.put(SkullBlock.Types.PIGLIN, ResourceLocation.withDefaultNamespace("textures/entity/piglin/piglin.png"));
|
|
hashMap.put(SkullBlock.Types.PLAYER, DefaultPlayerSkin.getDefaultTexture());
|
|
});
|
|
|
|
@Nullable
|
|
public static SkullModelBase createModel(EntityModelSet modelSet, SkullBlock.Type type) {
|
|
if (type instanceof SkullBlock.Types types) {
|
|
return (SkullModelBase)(switch (types) {
|
|
case SKELETON -> new SkullModel(modelSet.bakeLayer(ModelLayers.SKELETON_SKULL));
|
|
case WITHER_SKELETON -> new SkullModel(modelSet.bakeLayer(ModelLayers.WITHER_SKELETON_SKULL));
|
|
case PLAYER -> new SkullModel(modelSet.bakeLayer(ModelLayers.PLAYER_HEAD));
|
|
case ZOMBIE -> new SkullModel(modelSet.bakeLayer(ModelLayers.ZOMBIE_HEAD));
|
|
case CREEPER -> new SkullModel(modelSet.bakeLayer(ModelLayers.CREEPER_HEAD));
|
|
case DRAGON -> new DragonHeadModel(modelSet.bakeLayer(ModelLayers.DRAGON_SKULL));
|
|
case PIGLIN -> new PiglinHeadModel(modelSet.bakeLayer(ModelLayers.PIGLIN_HEAD));
|
|
});
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public SkullBlockRenderer(Context context) {
|
|
EntityModelSet entityModelSet = context.getModelSet();
|
|
this.modelByType = Util.memoize((Function<SkullBlock.Type, SkullModelBase>)(type -> createModel(entityModelSet, type)));
|
|
}
|
|
|
|
public void render(SkullBlockEntity skullBlockEntity, float f, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, int j, Vec3 vec3) {
|
|
float g = skullBlockEntity.getAnimation(f);
|
|
BlockState blockState = skullBlockEntity.getBlockState();
|
|
boolean bl = blockState.getBlock() instanceof WallSkullBlock;
|
|
Direction direction = bl ? blockState.getValue(WallSkullBlock.FACING) : null;
|
|
int k = bl ? RotationSegment.convertToSegment(direction.getOpposite()) : (Integer)blockState.getValue(SkullBlock.ROTATION);
|
|
float h = RotationSegment.convertToDegrees(k);
|
|
SkullBlock.Type type = ((AbstractSkullBlock)blockState.getBlock()).getType();
|
|
SkullModelBase skullModelBase = (SkullModelBase)this.modelByType.apply(type);
|
|
RenderType renderType = getRenderType(type, skullBlockEntity.getOwnerProfile());
|
|
renderSkull(direction, h, g, poseStack, multiBufferSource, i, skullModelBase, renderType);
|
|
}
|
|
|
|
public static void renderSkull(
|
|
@Nullable Direction direction,
|
|
float yRot,
|
|
float mouthAnimation,
|
|
PoseStack poseStack,
|
|
MultiBufferSource bufferSource,
|
|
int packedLight,
|
|
SkullModelBase model,
|
|
RenderType renderType
|
|
) {
|
|
poseStack.pushPose();
|
|
if (direction == null) {
|
|
poseStack.translate(0.5F, 0.0F, 0.5F);
|
|
} else {
|
|
float f = 0.25F;
|
|
poseStack.translate(0.5F - direction.getStepX() * 0.25F, 0.25F, 0.5F - direction.getStepZ() * 0.25F);
|
|
}
|
|
|
|
poseStack.scale(-1.0F, -1.0F, 1.0F);
|
|
VertexConsumer vertexConsumer = bufferSource.getBuffer(renderType);
|
|
model.setupAnim(mouthAnimation, yRot, 0.0F);
|
|
model.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY);
|
|
poseStack.popPose();
|
|
}
|
|
|
|
public static RenderType getRenderType(SkullBlock.Type type, @Nullable ResolvableProfile profile) {
|
|
return getRenderType(type, profile, null);
|
|
}
|
|
|
|
public static RenderType getRenderType(SkullBlock.Type type, @Nullable ResolvableProfile profile, @Nullable ResourceLocation textureOverride) {
|
|
return type == SkullBlock.Types.PLAYER && profile != null
|
|
? RenderType.entityTranslucent(
|
|
textureOverride != null ? textureOverride : Minecraft.getInstance().getSkinManager().getInsecureSkin(profile.gameProfile()).texture()
|
|
)
|
|
: RenderType.entityCutoutNoCullZOffset(textureOverride != null ? textureOverride : (ResourceLocation)SKIN_BY_TYPE.get(type));
|
|
}
|
|
}
|