minecraft-src/net/minecraft/client/renderer/special/SkullSpecialRenderer.java
2025-07-04 03:15:13 +03:00

87 lines
3.4 KiB
Java

package net.minecraft.client.renderer.special;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
import java.util.function.UnaryOperator;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
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.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
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.Type;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class SkullSpecialRenderer implements SpecialModelRenderer<ResolvableProfile> {
private final Type skullType;
private final SkullModelBase model;
@Nullable
private final ResourceLocation textureOverride;
private final float animation;
public SkullSpecialRenderer(Type skullType, SkullModelBase model, @Nullable ResourceLocation textureOverride, float animation) {
this.skullType = skullType;
this.model = model;
this.textureOverride = textureOverride;
this.animation = animation;
}
@Nullable
public ResolvableProfile extractArgument(ItemStack itemStack) {
return itemStack.get(DataComponents.PROFILE);
}
public void render(
@Nullable ResolvableProfile resolvableProfile,
ItemDisplayContext itemDisplayContext,
PoseStack poseStack,
MultiBufferSource multiBufferSource,
int i,
int j,
boolean bl
) {
RenderType renderType = SkullBlockRenderer.getRenderType(this.skullType, resolvableProfile, this.textureOverride);
SkullBlockRenderer.renderSkull(null, 180.0F, this.animation, poseStack, multiBufferSource, i, this.model, renderType);
}
@Environment(EnvType.CLIENT)
public record Unbaked(Type kind, Optional<ResourceLocation> textureOverride, float animation) implements SpecialModelRenderer.Unbaked {
public static final MapCodec<SkullSpecialRenderer.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
Type.CODEC.fieldOf("kind").forGetter(SkullSpecialRenderer.Unbaked::kind),
ResourceLocation.CODEC.optionalFieldOf("texture").forGetter(SkullSpecialRenderer.Unbaked::textureOverride),
Codec.FLOAT.optionalFieldOf("animation", 0.0F).forGetter(SkullSpecialRenderer.Unbaked::animation)
)
.apply(instance, SkullSpecialRenderer.Unbaked::new)
);
public Unbaked(Type type) {
this(type, Optional.empty(), 0.0F);
}
@Override
public MapCodec<SkullSpecialRenderer.Unbaked> type() {
return MAP_CODEC;
}
@Nullable
@Override
public SpecialModelRenderer<?> bake(EntityModelSet modelSet) {
SkullModelBase skullModelBase = SkullBlockRenderer.createModel(modelSet, this.kind);
ResourceLocation resourceLocation = (ResourceLocation)this.textureOverride
.map(resourceLocationx -> resourceLocationx.withPath((UnaryOperator<String>)(string -> "textures/entity/" + string + ".png")))
.orElse(null);
return skullModelBase != null ? new SkullSpecialRenderer(this.kind, skullModelBase, resourceLocation, this.animation) : null;
}
}
}