minecraft-src/net/minecraft/client/renderer/entity/player/PlayerRenderer.java
2025-07-04 03:45:38 +03:00

301 lines
14 KiB
Java

package net.minecraft.client.renderer.entity.player;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.model.HumanoidArmorModel;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.HumanoidModel.ArmPose;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.HumanoidMobRenderer;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider.Context;
import net.minecraft.client.renderer.entity.layers.ArrowLayer;
import net.minecraft.client.renderer.entity.layers.BeeStingerLayer;
import net.minecraft.client.renderer.entity.layers.CapeLayer;
import net.minecraft.client.renderer.entity.layers.CustomHeadLayer;
import net.minecraft.client.renderer.entity.layers.Deadmau5EarsLayer;
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
import net.minecraft.client.renderer.entity.layers.ParrotOnShoulderLayer;
import net.minecraft.client.renderer.entity.layers.PlayerItemInHandLayer;
import net.minecraft.client.renderer.entity.layers.SpinAttackEffectLayer;
import net.minecraft.client.renderer.entity.layers.WingsLayer;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.numbers.StyledFormat;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.animal.Parrot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.player.PlayerModelPart;
import net.minecraft.world.item.CrossbowItem;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemUseAnimation;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.DisplaySlot;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.ReadOnlyScoreInfo;
import net.minecraft.world.scores.Scoreboard;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class PlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerRenderState, PlayerModel> {
public PlayerRenderer(Context context, boolean useSlimModel) {
super(context, new PlayerModel(context.bakeLayer(useSlimModel ? ModelLayers.PLAYER_SLIM : ModelLayers.PLAYER), useSlimModel), 0.5F);
this.addLayer(
new HumanoidArmorLayer<>(
this,
new HumanoidArmorModel(context.bakeLayer(useSlimModel ? ModelLayers.PLAYER_SLIM_INNER_ARMOR : ModelLayers.PLAYER_INNER_ARMOR)),
new HumanoidArmorModel(context.bakeLayer(useSlimModel ? ModelLayers.PLAYER_SLIM_OUTER_ARMOR : ModelLayers.PLAYER_OUTER_ARMOR)),
context.getEquipmentRenderer()
)
);
this.addLayer(new PlayerItemInHandLayer<>(this));
this.addLayer(new ArrowLayer<>(this, context));
this.addLayer(new Deadmau5EarsLayer(this, context.getModelSet()));
this.addLayer(new CapeLayer(this, context.getModelSet(), context.getEquipmentAssets()));
this.addLayer(new CustomHeadLayer<>(this, context.getModelSet()));
this.addLayer(new WingsLayer<>(this, context.getModelSet(), context.getEquipmentRenderer()));
this.addLayer(new ParrotOnShoulderLayer(this, context.getModelSet()));
this.addLayer(new SpinAttackEffectLayer(this, context.getModelSet()));
this.addLayer(new BeeStingerLayer<>(this, context));
}
protected boolean shouldRenderLayers(PlayerRenderState playerRenderState) {
return !playerRenderState.isSpectator;
}
public Vec3 getRenderOffset(PlayerRenderState playerRenderState) {
Vec3 vec3 = super.getRenderOffset(playerRenderState);
return playerRenderState.isCrouching ? vec3.add(0.0, playerRenderState.scale * -2.0F / 16.0, 0.0) : vec3;
}
private static ArmPose getArmPose(AbstractClientPlayer player, HumanoidArm arm) {
ItemStack itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
ItemStack itemStack2 = player.getItemInHand(InteractionHand.OFF_HAND);
ArmPose armPose = getArmPose(player, itemStack, InteractionHand.MAIN_HAND);
ArmPose armPose2 = getArmPose(player, itemStack2, InteractionHand.OFF_HAND);
if (armPose.isTwoHanded()) {
armPose2 = itemStack2.isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM;
}
return player.getMainArm() == arm ? armPose : armPose2;
}
private static ArmPose getArmPose(Player player, ItemStack stack, InteractionHand hand) {
if (stack.isEmpty()) {
return ArmPose.EMPTY;
} else if (!player.swinging && stack.is(Items.CROSSBOW) && CrossbowItem.isCharged(stack)) {
return ArmPose.CROSSBOW_HOLD;
} else {
if (player.getUsedItemHand() == hand && player.getUseItemRemainingTicks() > 0) {
ItemUseAnimation itemUseAnimation = stack.getUseAnimation();
if (itemUseAnimation == ItemUseAnimation.BLOCK) {
return ArmPose.BLOCK;
}
if (itemUseAnimation == ItemUseAnimation.BOW) {
return ArmPose.BOW_AND_ARROW;
}
if (itemUseAnimation == ItemUseAnimation.SPEAR) {
return ArmPose.THROW_SPEAR;
}
if (itemUseAnimation == ItemUseAnimation.CROSSBOW) {
return ArmPose.CROSSBOW_CHARGE;
}
if (itemUseAnimation == ItemUseAnimation.SPYGLASS) {
return ArmPose.SPYGLASS;
}
if (itemUseAnimation == ItemUseAnimation.TOOT_HORN) {
return ArmPose.TOOT_HORN;
}
if (itemUseAnimation == ItemUseAnimation.BRUSH) {
return ArmPose.BRUSH;
}
}
return ArmPose.ITEM;
}
}
public ResourceLocation getTextureLocation(PlayerRenderState playerRenderState) {
return playerRenderState.skin.texture();
}
protected void scale(PlayerRenderState playerRenderState, PoseStack poseStack) {
float f = 0.9375F;
poseStack.scale(0.9375F, 0.9375F, 0.9375F);
}
protected void renderNameTag(PlayerRenderState playerRenderState, Component component, PoseStack poseStack, MultiBufferSource multiBufferSource, int i) {
poseStack.pushPose();
if (playerRenderState.scoreText != null) {
super.renderNameTag(playerRenderState, playerRenderState.scoreText, poseStack, multiBufferSource, i);
poseStack.translate(0.0F, 9.0F * 1.15F * 0.025F, 0.0F);
}
super.renderNameTag(playerRenderState, component, poseStack, multiBufferSource, i);
poseStack.popPose();
}
public PlayerRenderState createRenderState() {
return new PlayerRenderState();
}
public void extractRenderState(AbstractClientPlayer abstractClientPlayer, PlayerRenderState playerRenderState, float f) {
super.extractRenderState(abstractClientPlayer, playerRenderState, f);
HumanoidMobRenderer.extractHumanoidRenderState(abstractClientPlayer, playerRenderState, f, this.itemModelResolver);
playerRenderState.leftArmPose = getArmPose(abstractClientPlayer, HumanoidArm.LEFT);
playerRenderState.rightArmPose = getArmPose(abstractClientPlayer, HumanoidArm.RIGHT);
playerRenderState.skin = abstractClientPlayer.getSkin();
playerRenderState.arrowCount = abstractClientPlayer.getArrowCount();
playerRenderState.stingerCount = abstractClientPlayer.getStingerCount();
playerRenderState.useItemRemainingTicks = abstractClientPlayer.getUseItemRemainingTicks();
playerRenderState.swinging = abstractClientPlayer.swinging;
playerRenderState.isSpectator = abstractClientPlayer.isSpectator();
playerRenderState.showHat = abstractClientPlayer.isModelPartShown(PlayerModelPart.HAT);
playerRenderState.showJacket = abstractClientPlayer.isModelPartShown(PlayerModelPart.JACKET);
playerRenderState.showLeftPants = abstractClientPlayer.isModelPartShown(PlayerModelPart.LEFT_PANTS_LEG);
playerRenderState.showRightPants = abstractClientPlayer.isModelPartShown(PlayerModelPart.RIGHT_PANTS_LEG);
playerRenderState.showLeftSleeve = abstractClientPlayer.isModelPartShown(PlayerModelPart.LEFT_SLEEVE);
playerRenderState.showRightSleeve = abstractClientPlayer.isModelPartShown(PlayerModelPart.RIGHT_SLEEVE);
playerRenderState.showCape = abstractClientPlayer.isModelPartShown(PlayerModelPart.CAPE);
extractFlightData(abstractClientPlayer, playerRenderState, f);
extractCapeState(abstractClientPlayer, playerRenderState, f);
if (playerRenderState.distanceToCameraSq < 100.0) {
Scoreboard scoreboard = abstractClientPlayer.getScoreboard();
Objective objective = scoreboard.getDisplayObjective(DisplaySlot.BELOW_NAME);
if (objective != null) {
ReadOnlyScoreInfo readOnlyScoreInfo = scoreboard.getPlayerScoreInfo(abstractClientPlayer, objective);
Component component = ReadOnlyScoreInfo.safeFormatValue(readOnlyScoreInfo, objective.numberFormatOrDefault(StyledFormat.NO_STYLE));
playerRenderState.scoreText = Component.empty().append(component).append(CommonComponents.SPACE).append(objective.getDisplayName());
} else {
playerRenderState.scoreText = null;
}
} else {
playerRenderState.scoreText = null;
}
playerRenderState.parrotOnLeftShoulder = getParrotOnShoulder(abstractClientPlayer, true);
playerRenderState.parrotOnRightShoulder = getParrotOnShoulder(abstractClientPlayer, false);
playerRenderState.id = abstractClientPlayer.getId();
playerRenderState.name = abstractClientPlayer.getGameProfile().getName();
playerRenderState.heldOnHead.clear();
if (playerRenderState.isUsingItem) {
ItemStack itemStack = abstractClientPlayer.getItemInHand(playerRenderState.useItemHand);
if (itemStack.is(Items.SPYGLASS)) {
this.itemModelResolver.updateForLiving(playerRenderState.heldOnHead, itemStack, ItemDisplayContext.HEAD, abstractClientPlayer);
}
}
}
private static void extractFlightData(AbstractClientPlayer player, PlayerRenderState renderState, float partialTick) {
renderState.fallFlyingTimeInTicks = player.getFallFlyingTicks() + partialTick;
Vec3 vec3 = player.getViewVector(partialTick);
Vec3 vec32 = player.getDeltaMovementLerped(partialTick);
if (vec32.horizontalDistanceSqr() > 1.0E-5F && vec3.horizontalDistanceSqr() > 1.0E-5F) {
renderState.shouldApplyFlyingYRot = true;
double d = vec32.horizontal().normalize().dot(vec3.horizontal().normalize());
double e = vec32.x * vec3.z - vec32.z * vec3.x;
renderState.flyingYRot = (float)(Math.signum(e) * Math.acos(Math.min(1.0, Math.abs(d))));
} else {
renderState.shouldApplyFlyingYRot = false;
renderState.flyingYRot = 0.0F;
}
}
private static void extractCapeState(AbstractClientPlayer player, PlayerRenderState renderState, float partialTick) {
double d = Mth.lerp((double)partialTick, player.xCloakO, player.xCloak) - Mth.lerp((double)partialTick, player.xo, player.getX());
double e = Mth.lerp((double)partialTick, player.yCloakO, player.yCloak) - Mth.lerp((double)partialTick, player.yo, player.getY());
double f = Mth.lerp((double)partialTick, player.zCloakO, player.zCloak) - Mth.lerp((double)partialTick, player.zo, player.getZ());
float g = Mth.rotLerp(partialTick, player.yBodyRotO, player.yBodyRot);
double h = Mth.sin(g * (float) (Math.PI / 180.0));
double i = -Mth.cos(g * (float) (Math.PI / 180.0));
renderState.capeFlap = (float)e * 10.0F;
renderState.capeFlap = Mth.clamp(renderState.capeFlap, -6.0F, 32.0F);
renderState.capeLean = (float)(d * h + f * i) * 100.0F;
renderState.capeLean = renderState.capeLean * (1.0F - renderState.fallFlyingScale());
renderState.capeLean = Mth.clamp(renderState.capeLean, 0.0F, 150.0F);
renderState.capeLean2 = (float)(d * i - f * h) * 100.0F;
renderState.capeLean2 = Mth.clamp(renderState.capeLean2, -20.0F, 20.0F);
float j = Mth.lerp(partialTick, player.oBob, player.bob);
float k = Mth.lerp(partialTick, player.walkDistO, player.walkDist);
renderState.capeFlap = renderState.capeFlap + Mth.sin(k * 6.0F) * 32.0F * j;
}
@Nullable
private static Parrot.Variant getParrotOnShoulder(AbstractClientPlayer player, boolean leftShoulder) {
CompoundTag compoundTag = leftShoulder ? player.getShoulderEntityLeft() : player.getShoulderEntityRight();
if (compoundTag.isEmpty()) {
return null;
} else {
EntityType<?> entityType = (EntityType<?>)compoundTag.read("id", EntityType.CODEC).orElse(null);
return entityType == EntityType.PARROT ? (Parrot.Variant)compoundTag.read("Variant", Parrot.Variant.LEGACY_CODEC).orElse(Parrot.Variant.RED_BLUE) : null;
}
}
public void renderRightHand(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, ResourceLocation skinTexture, boolean isSleeveVisible) {
this.renderHand(poseStack, bufferSource, packedLight, skinTexture, this.model.rightArm, isSleeveVisible);
}
public void renderLeftHand(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, ResourceLocation skinTexture, boolean isSleeveVisible) {
this.renderHand(poseStack, bufferSource, packedLight, skinTexture, this.model.leftArm, isSleeveVisible);
}
private void renderHand(
PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, ResourceLocation skinTexture, ModelPart arm, boolean isSleeveVisible
) {
PlayerModel playerModel = this.getModel();
arm.resetPose();
arm.visible = true;
playerModel.leftSleeve.visible = isSleeveVisible;
playerModel.rightSleeve.visible = isSleeveVisible;
playerModel.leftArm.zRot = -0.1F;
playerModel.rightArm.zRot = 0.1F;
arm.render(poseStack, bufferSource.getBuffer(RenderType.entityTranslucent(skinTexture)), packedLight, OverlayTexture.NO_OVERLAY);
}
protected void setupRotations(PlayerRenderState playerRenderState, PoseStack poseStack, float f, float g) {
float h = playerRenderState.swimAmount;
float i = playerRenderState.xRot;
if (playerRenderState.isFallFlying) {
super.setupRotations(playerRenderState, poseStack, f, g);
float j = playerRenderState.fallFlyingScale();
if (!playerRenderState.isAutoSpinAttack) {
poseStack.mulPose(Axis.XP.rotationDegrees(j * (-90.0F - i)));
}
if (playerRenderState.shouldApplyFlyingYRot) {
poseStack.mulPose(Axis.YP.rotation(playerRenderState.flyingYRot));
}
} else if (h > 0.0F) {
super.setupRotations(playerRenderState, poseStack, f, g);
float jx = playerRenderState.isInWater ? -90.0F - i : -90.0F;
float k = Mth.lerp(h, 0.0F, jx);
poseStack.mulPose(Axis.XP.rotationDegrees(k));
if (playerRenderState.isVisuallySwimming) {
poseStack.translate(0.0F, -1.0F, 0.3F);
}
} else {
super.setupRotations(playerRenderState, poseStack, f, g);
}
}
}