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 { 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); } } }