301 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			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.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.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(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));
 | |
| 		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 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;
 | |
| 	}
 | |
| 
 | |
| 	private static HumanoidModel.ArmPose getArmPose(AbstractClientPlayer player, HumanoidArm arm) {
 | |
| 		ItemStack itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
 | |
| 		ItemStack itemStack2 = player.getItemInHand(InteractionHand.OFF_HAND);
 | |
| 		HumanoidModel.ArmPose armPose = getArmPose(player, itemStack, InteractionHand.MAIN_HAND);
 | |
| 		HumanoidModel.ArmPose armPose2 = getArmPose(player, itemStack2, InteractionHand.OFF_HAND);
 | |
| 		if (armPose.isTwoHanded()) {
 | |
| 			armPose2 = itemStack2.isEmpty() ? HumanoidModel.ArmPose.EMPTY : HumanoidModel.ArmPose.ITEM;
 | |
| 		}
 | |
| 
 | |
| 		return player.getMainArm() == arm ? armPose : armPose2;
 | |
| 	}
 | |
| 
 | |
| 	private static HumanoidModel.ArmPose getArmPose(Player player, ItemStack stack, InteractionHand hand) {
 | |
| 		if (stack.isEmpty()) {
 | |
| 			return HumanoidModel.ArmPose.EMPTY;
 | |
| 		} else if (!player.swinging && stack.is(Items.CROSSBOW) && CrossbowItem.isCharged(stack)) {
 | |
| 			return HumanoidModel.ArmPose.CROSSBOW_HOLD;
 | |
| 		} else {
 | |
| 			if (player.getUsedItemHand() == hand && player.getUseItemRemainingTicks() > 0) {
 | |
| 				ItemUseAnimation itemUseAnimation = stack.getUseAnimation();
 | |
| 				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;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			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, this.itemModelResolver);
 | |
| 		reusedState.leftArmPose = getArmPose(entity, HumanoidArm.LEFT);
 | |
| 		reusedState.rightArmPose = getArmPose(entity, HumanoidArm.RIGHT);
 | |
| 		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);
 | |
| 		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();
 | |
| 		reusedState.heldOnHead.clear();
 | |
| 		if (reusedState.isUsingItem) {
 | |
| 			ItemStack itemStack = entity.getItemInHand(reusedState.useItemHand);
 | |
| 			if (itemStack.is(Items.SPYGLASS)) {
 | |
| 				this.itemModelResolver.updateForLiving(reusedState.heldOnHead, itemStack, ItemDisplayContext.HEAD, entity);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	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 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);
 | |
| 		}
 | |
| 	}
 | |
| }
 |