minecraft-src/net/minecraft/client/renderer/entity/player/PlayerRenderer.java
2025-07-04 02:49:36 +03:00

297 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.HumanoidModel;
import net.minecraft.client.model.PlayerModel;
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.EntityRendererProvider;
import net.minecraft.client.renderer.entity.HumanoidMobRenderer;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
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.entity.state.PlayerRenderState.HandState;
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.PlayerModelPart;
import net.minecraft.world.item.CrossbowItem;
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(EntityRendererProvider.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, context.getItemRenderer()));
this.addLayer(new ArrowLayer<>(this, context));
this.addLayer(new Deadmau5EarsLayer(this, context.getModelSet()));
this.addLayer(new CapeLayer(this, context.getModelSet(), context.getEquipmentModels()));
this.addLayer(new CustomHeadLayer<>(this, context.getModelSet(), context.getItemRenderer()));
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 renderState) {
return !renderState.isSpectator;
}
public Vec3 getRenderOffset(PlayerRenderState renderState) {
Vec3 vec3 = super.getRenderOffset(renderState);
return renderState.isCrouching ? vec3.add(0.0, renderState.scale * -2.0F / 16.0, 0.0) : vec3;
}
public static HumanoidModel.ArmPose getArmPose(PlayerRenderState renderState, HumanoidArm arm) {
HumanoidModel.ArmPose armPose = getArmPose(renderState, renderState.mainHandState, InteractionHand.MAIN_HAND);
HumanoidModel.ArmPose armPose2 = getArmPose(renderState, renderState.offhandState, InteractionHand.OFF_HAND);
if (armPose.isTwoHanded()) {
armPose2 = renderState.offhandState.isEmpty ? HumanoidModel.ArmPose.EMPTY : HumanoidModel.ArmPose.ITEM;
}
return renderState.mainArm == arm ? armPose : armPose2;
}
private static HumanoidModel.ArmPose getArmPose(PlayerRenderState renderState, HandState handState, InteractionHand hand) {
if (handState.isEmpty) {
return HumanoidModel.ArmPose.EMPTY;
} else {
if (renderState.useItemHand == hand && renderState.useItemRemainingTicks > 0) {
ItemUseAnimation itemUseAnimation = handState.useAnimation;
if (itemUseAnimation == ItemUseAnimation.BLOCK) {
return HumanoidModel.ArmPose.BLOCK;
}
if (itemUseAnimation == ItemUseAnimation.BOW) {
return HumanoidModel.ArmPose.BOW_AND_ARROW;
}
if (itemUseAnimation == ItemUseAnimation.SPEAR) {
return HumanoidModel.ArmPose.THROW_SPEAR;
}
if (itemUseAnimation == ItemUseAnimation.CROSSBOW) {
return HumanoidModel.ArmPose.CROSSBOW_CHARGE;
}
if (itemUseAnimation == ItemUseAnimation.SPYGLASS) {
return HumanoidModel.ArmPose.SPYGLASS;
}
if (itemUseAnimation == ItemUseAnimation.TOOT_HORN) {
return HumanoidModel.ArmPose.TOOT_HORN;
}
if (itemUseAnimation == ItemUseAnimation.BRUSH) {
return HumanoidModel.ArmPose.BRUSH;
}
} else if (!renderState.swinging && handState.holdsChargedCrossbow) {
return HumanoidModel.ArmPose.CROSSBOW_HOLD;
}
return HumanoidModel.ArmPose.ITEM;
}
}
public ResourceLocation getTextureLocation(PlayerRenderState renderState) {
return renderState.skin.texture();
}
protected void scale(PlayerRenderState renderState, PoseStack poseStack) {
float f = 0.9375F;
poseStack.scale(0.9375F, 0.9375F, 0.9375F);
}
protected void renderNameTag(PlayerRenderState renderState, Component displayName, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
poseStack.pushPose();
if (renderState.scoreText != null) {
super.renderNameTag(renderState, renderState.scoreText, poseStack, bufferSource, packedLight);
poseStack.translate(0.0F, 9.0F * 1.15F * 0.025F, 0.0F);
}
super.renderNameTag(renderState, displayName, poseStack, bufferSource, packedLight);
poseStack.popPose();
}
public PlayerRenderState createRenderState() {
return new PlayerRenderState();
}
public void extractRenderState(AbstractClientPlayer entity, PlayerRenderState reusedState, float partialTick) {
super.extractRenderState(entity, reusedState, partialTick);
HumanoidMobRenderer.extractHumanoidRenderState(entity, reusedState, partialTick);
reusedState.skin = entity.getSkin();
reusedState.arrowCount = entity.getArrowCount();
reusedState.stingerCount = entity.getStingerCount();
reusedState.useItemRemainingTicks = entity.getUseItemRemainingTicks();
reusedState.swinging = entity.swinging;
reusedState.isSpectator = entity.isSpectator();
reusedState.showHat = entity.isModelPartShown(PlayerModelPart.HAT);
reusedState.showJacket = entity.isModelPartShown(PlayerModelPart.JACKET);
reusedState.showLeftPants = entity.isModelPartShown(PlayerModelPart.LEFT_PANTS_LEG);
reusedState.showRightPants = entity.isModelPartShown(PlayerModelPart.RIGHT_PANTS_LEG);
reusedState.showLeftSleeve = entity.isModelPartShown(PlayerModelPart.LEFT_SLEEVE);
reusedState.showRightSleeve = entity.isModelPartShown(PlayerModelPart.RIGHT_SLEEVE);
reusedState.showCape = entity.isModelPartShown(PlayerModelPart.CAPE);
extractFlightData(entity, reusedState, partialTick);
this.extractHandState(entity, reusedState.mainHandState, InteractionHand.MAIN_HAND);
this.extractHandState(entity, reusedState.offhandState, InteractionHand.OFF_HAND);
extractCapeState(entity, reusedState, partialTick);
if (reusedState.distanceToCameraSq < 100.0) {
Scoreboard scoreboard = entity.getScoreboard();
Objective objective = scoreboard.getDisplayObjective(DisplaySlot.BELOW_NAME);
if (objective != null) {
ReadOnlyScoreInfo readOnlyScoreInfo = scoreboard.getPlayerScoreInfo(entity, objective);
Component component = ReadOnlyScoreInfo.safeFormatValue(readOnlyScoreInfo, objective.numberFormatOrDefault(StyledFormat.NO_STYLE));
reusedState.scoreText = Component.empty().append(component).append(CommonComponents.SPACE).append(objective.getDisplayName());
} else {
reusedState.scoreText = null;
}
} else {
reusedState.scoreText = null;
}
reusedState.parrotOnLeftShoulder = getParrotOnShoulder(entity, true);
reusedState.parrotOnRightShoulder = getParrotOnShoulder(entity, false);
reusedState.id = entity.getId();
reusedState.name = entity.getGameProfile().getName();
}
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);
double d = vec32.horizontalDistanceSqr();
double e = vec3.horizontalDistanceSqr();
if (d > 0.0 && e > 0.0) {
renderState.shouldApplyFlyingYRot = true;
double f = (vec32.x * vec3.x + vec32.z * vec3.z) / Math.sqrt(d * e);
double g = vec32.x * vec3.z - vec32.z * vec3.x;
renderState.flyingYRot = (float)(Math.signum(g) * Math.acos(f));
} else {
renderState.shouldApplyFlyingYRot = false;
renderState.flyingYRot = 0.0F;
}
}
private void extractHandState(AbstractClientPlayer player, HandState reusedState, InteractionHand hand) {
ItemStack itemStack = player.getItemInHand(hand);
reusedState.isEmpty = itemStack.isEmpty();
reusedState.useAnimation = !itemStack.isEmpty() ? itemStack.getUseAnimation() : null;
reusedState.holdsChargedCrossbow = itemStack.is(Items.CROSSBOW) && CrossbowItem.isCharged(itemStack);
}
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();
return EntityType.byString(compoundTag.getString("id")).filter(entityType -> entityType == EntityType.PARROT).isPresent()
? Parrot.Variant.byId(compoundTag.getInt("Variant"))
: 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 renderState, PoseStack poseStack, float bodyRot, float scale) {
float f = renderState.swimAmount;
float g = renderState.xRot;
if (renderState.isFallFlying) {
super.setupRotations(renderState, poseStack, bodyRot, scale);
float h = renderState.fallFlyingScale();
if (!renderState.isAutoSpinAttack) {
poseStack.mulPose(Axis.XP.rotationDegrees(h * (-90.0F - g)));
}
if (renderState.shouldApplyFlyingYRot) {
poseStack.mulPose(Axis.YP.rotation(renderState.flyingYRot));
}
} else if (f > 0.0F) {
super.setupRotations(renderState, poseStack, bodyRot, scale);
float hx = renderState.isInWater ? -90.0F - g : -90.0F;
float i = Mth.lerp(f, 0.0F, hx);
poseStack.mulPose(Axis.XP.rotationDegrees(i));
if (renderState.isVisuallySwimming) {
poseStack.translate(0.0F, -1.0F, 0.3F);
}
} else {
super.setupRotations(renderState, poseStack, bodyRot, scale);
}
}
}