297 lines
14 KiB
Java
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);
|
|
}
|
|
}
|
|
}
|