/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.annotations.VisibleForTesting * com.google.common.base.MoreObjects * org.joml.Quaternionfc */ package net.minecraft.client.renderer; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import net.minecraft.client.Minecraft; import net.minecraft.client.model.SpearAnimations; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.MapRenderer; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.renderer.entity.player.AvatarRenderer; import net.minecraft.client.renderer.item.ItemModelResolver; import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.client.renderer.state.MapRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.LivingEntity; 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.item.MapItem; import net.minecraft.world.item.ShieldItem; import net.minecraft.world.level.Level; import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import org.joml.Quaternionfc; public class ItemInHandRenderer { private static final RenderType MAP_BACKGROUND = RenderTypes.text(Identifier.withDefaultNamespace("textures/map/map_background.png")); private static final RenderType MAP_BACKGROUND_CHECKERBOARD = RenderTypes.text(Identifier.withDefaultNamespace("textures/map/map_background_checkerboard.png")); private static final float ITEM_SWING_X_POS_SCALE = -0.4f; private static final float ITEM_SWING_Y_POS_SCALE = 0.2f; private static final float ITEM_SWING_Z_POS_SCALE = -0.2f; private static final float ITEM_HEIGHT_SCALE = -0.6f; private static final float ITEM_POS_X = 0.56f; private static final float ITEM_POS_Y = -0.52f; private static final float ITEM_POS_Z = -0.72f; private static final float ITEM_PRESWING_ROT_Y = 45.0f; private static final float ITEM_SWING_X_ROT_AMOUNT = -80.0f; private static final float ITEM_SWING_Y_ROT_AMOUNT = -20.0f; private static final float ITEM_SWING_Z_ROT_AMOUNT = -20.0f; private static final float EAT_JIGGLE_X_ROT_AMOUNT = 10.0f; private static final float EAT_JIGGLE_Y_ROT_AMOUNT = 90.0f; private static final float EAT_JIGGLE_Z_ROT_AMOUNT = 30.0f; private static final float EAT_JIGGLE_X_POS_SCALE = 0.6f; private static final float EAT_JIGGLE_Y_POS_SCALE = -0.5f; private static final float EAT_JIGGLE_Z_POS_SCALE = 0.0f; private static final double EAT_JIGGLE_EXPONENT = 27.0; private static final float EAT_EXTRA_JIGGLE_CUTOFF = 0.8f; private static final float EAT_EXTRA_JIGGLE_SCALE = 0.1f; private static final float ARM_SWING_X_POS_SCALE = -0.3f; private static final float ARM_SWING_Y_POS_SCALE = 0.4f; private static final float ARM_SWING_Z_POS_SCALE = -0.4f; private static final float ARM_SWING_Y_ROT_AMOUNT = 70.0f; private static final float ARM_SWING_Z_ROT_AMOUNT = -20.0f; private static final float ARM_HEIGHT_SCALE = -0.6f; private static final float ARM_POS_SCALE = 0.8f; private static final float ARM_POS_X = 0.8f; private static final float ARM_POS_Y = -0.75f; private static final float ARM_POS_Z = -0.9f; private static final float ARM_PRESWING_ROT_Y = 45.0f; private static final float ARM_PREROTATION_X_OFFSET = -1.0f; private static final float ARM_PREROTATION_Y_OFFSET = 3.6f; private static final float ARM_PREROTATION_Z_OFFSET = 3.5f; private static final float ARM_POSTROTATION_X_OFFSET = 5.6f; private static final int ARM_ROT_X = 200; private static final int ARM_ROT_Y = -135; private static final int ARM_ROT_Z = 120; private static final float MAP_SWING_X_POS_SCALE = -0.4f; private static final float MAP_SWING_Z_POS_SCALE = -0.2f; private static final float MAP_HANDS_POS_X = 0.0f; private static final float MAP_HANDS_POS_Y = 0.04f; private static final float MAP_HANDS_POS_Z = -0.72f; private static final float MAP_HANDS_HEIGHT_SCALE = -1.2f; private static final float MAP_HANDS_TILT_SCALE = -0.5f; private static final float MAP_PLAYER_PITCH_SCALE = 45.0f; private static final float MAP_HANDS_Z_ROT_AMOUNT = -85.0f; private static final float MAPHAND_X_ROT_AMOUNT = 45.0f; private static final float MAPHAND_Y_ROT_AMOUNT = 92.0f; private static final float MAPHAND_Z_ROT_AMOUNT = -41.0f; private static final float MAP_HAND_X_POS = 0.3f; private static final float MAP_HAND_Y_POS = -1.1f; private static final float MAP_HAND_Z_POS = 0.45f; private static final float MAP_SWING_X_ROT_AMOUNT = 20.0f; private static final float MAP_PRE_ROT_SCALE = 0.38f; private static final float MAP_GLOBAL_X_POS = -0.5f; private static final float MAP_GLOBAL_Y_POS = -0.5f; private static final float MAP_GLOBAL_Z_POS = 0.0f; private static final float MAP_FINAL_SCALE = 0.0078125f; private static final int MAP_BORDER = 7; private static final int MAP_HEIGHT = 128; private static final int MAP_WIDTH = 128; private static final float BOW_CHARGE_X_POS_SCALE = 0.0f; private static final float BOW_CHARGE_Y_POS_SCALE = 0.0f; private static final float BOW_CHARGE_Z_POS_SCALE = 0.04f; private static final float BOW_CHARGE_SHAKE_X_SCALE = 0.0f; private static final float BOW_CHARGE_SHAKE_Y_SCALE = 0.004f; private static final float BOW_CHARGE_SHAKE_Z_SCALE = 0.0f; private static final float BOW_CHARGE_Z_SCALE = 0.2f; private static final float BOW_MIN_SHAKE_CHARGE = 0.1f; private final Minecraft minecraft; private final MapRenderState mapRenderState = new MapRenderState(); private ItemStack mainHandItem = ItemStack.EMPTY; private ItemStack offHandItem = ItemStack.EMPTY; private float mainHandHeight; private float oMainHandHeight; private float offHandHeight; private float oOffHandHeight; private final EntityRenderDispatcher entityRenderDispatcher; private final ItemRenderer itemRenderer; private final ItemModelResolver itemModelResolver; public ItemInHandRenderer(Minecraft minecraft, EntityRenderDispatcher entityRenderDispatcher, ItemRenderer itemRenderer, ItemModelResolver itemModelResolver) { this.minecraft = minecraft; this.entityRenderDispatcher = entityRenderDispatcher; this.itemRenderer = itemRenderer; this.itemModelResolver = itemModelResolver; } public void renderItem(LivingEntity mob, ItemStack itemStack, ItemDisplayContext type, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords) { if (itemStack.isEmpty()) { return; } ItemStackRenderState renderState = new ItemStackRenderState(); this.itemModelResolver.updateForTopItem(renderState, itemStack, type, mob.level(), mob, mob.getId() + type.ordinal()); renderState.submit(poseStack, submitNodeCollector, lightCoords, OverlayTexture.NO_OVERLAY, 0); } private float calculateMapTilt(float xRot) { float tilt = 1.0f - xRot / 45.0f + 0.1f; tilt = Mth.clamp(tilt, 0.0f, 1.0f); tilt = -Mth.cos(tilt * (float)Math.PI) * 0.5f + 0.5f; return tilt; } private void renderMapHand(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, HumanoidArm arm) { AvatarRenderer avatarRenderer = this.entityRenderDispatcher.getPlayerRenderer(this.minecraft.player); poseStack.pushPose(); float invert = arm == HumanoidArm.RIGHT ? 1.0f : -1.0f; poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(92.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(45.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(invert * -41.0f)); poseStack.translate(invert * 0.3f, -1.1f, 0.45f); Identifier skinTexture = this.minecraft.player.getSkin().body().texturePath(); if (arm == HumanoidArm.RIGHT) { avatarRenderer.renderRightHand(poseStack, submitNodeCollector, lightCoords, skinTexture, this.minecraft.player.isModelPartShown(PlayerModelPart.RIGHT_SLEEVE)); } else { avatarRenderer.renderLeftHand(poseStack, submitNodeCollector, lightCoords, skinTexture, this.minecraft.player.isModelPartShown(PlayerModelPart.LEFT_SLEEVE)); } poseStack.popPose(); } private void renderOneHandedMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float inverseArmHeight, HumanoidArm arm, float attackValue, ItemStack map) { float invert = arm == HumanoidArm.RIGHT ? 1.0f : -1.0f; poseStack.translate(invert * 0.125f, -0.125f, 0.0f); if (!this.minecraft.player.isInvisible()) { poseStack.pushPose(); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(invert * 10.0f)); this.renderPlayerArm(poseStack, submitNodeCollector, lightCoords, inverseArmHeight, attackValue, arm); poseStack.popPose(); } poseStack.pushPose(); poseStack.translate(invert * 0.51f, -0.08f + inverseArmHeight * -1.2f, -0.75f); float sqrtAttackValue = Mth.sqrt(attackValue); float xSwing = Mth.sin(sqrtAttackValue * (float)Math.PI); float xSwingPosition = -0.5f * xSwing; float ySwingPosition = 0.4f * Mth.sin(sqrtAttackValue * ((float)Math.PI * 2)); float zSwingPosition = -0.3f * Mth.sin(attackValue * (float)Math.PI); poseStack.translate(invert * xSwingPosition, ySwingPosition - 0.3f * xSwing, zSwingPosition); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(xSwing * -45.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(invert * xSwing * -30.0f)); this.renderMap(poseStack, submitNodeCollector, lightCoords, map); poseStack.popPose(); } private void renderTwoHandedMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float xRot, float inverseArmHeight, float attackValue) { float sqrtAttackValue = Mth.sqrt(attackValue); float ySwingPosition = -0.2f * Mth.sin(attackValue * (float)Math.PI); float zSwingPosition = -0.4f * Mth.sin(sqrtAttackValue * (float)Math.PI); poseStack.translate(0.0f, -ySwingPosition / 2.0f, zSwingPosition); float mapTilt = this.calculateMapTilt(xRot); poseStack.translate(0.0f, 0.04f + inverseArmHeight * -1.2f + mapTilt * -0.5f, -0.72f); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(mapTilt * -85.0f)); if (!this.minecraft.player.isInvisible()) { poseStack.pushPose(); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(90.0f)); this.renderMapHand(poseStack, submitNodeCollector, lightCoords, HumanoidArm.RIGHT); this.renderMapHand(poseStack, submitNodeCollector, lightCoords, HumanoidArm.LEFT); poseStack.popPose(); } float xzSwingRotation = Mth.sin(sqrtAttackValue * (float)Math.PI); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(xzSwingRotation * 20.0f)); poseStack.scale(2.0f, 2.0f, 2.0f); this.renderMap(poseStack, submitNodeCollector, lightCoords, this.mainHandItem); } private void renderMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, ItemStack itemStack) { poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(180.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(180.0f)); poseStack.scale(0.38f, 0.38f, 0.38f); poseStack.translate(-0.5f, -0.5f, 0.0f); poseStack.scale(0.0078125f, 0.0078125f, 0.0078125f); MapId id = itemStack.get(DataComponents.MAP_ID); MapItemSavedData data = MapItem.getSavedData(id, (Level)this.minecraft.level); RenderType renderType = data == null ? MAP_BACKGROUND : MAP_BACKGROUND_CHECKERBOARD; submitNodeCollector.submitCustomGeometry(poseStack, renderType, (pose, buffer) -> { buffer.addVertex(pose, -7.0f, 135.0f, 0.0f).setColor(-1).setUv(0.0f, 1.0f).setLight(lightCoords); buffer.addVertex(pose, 135.0f, 135.0f, 0.0f).setColor(-1).setUv(1.0f, 1.0f).setLight(lightCoords); buffer.addVertex(pose, 135.0f, -7.0f, 0.0f).setColor(-1).setUv(1.0f, 0.0f).setLight(lightCoords); buffer.addVertex(pose, -7.0f, -7.0f, 0.0f).setColor(-1).setUv(0.0f, 0.0f).setLight(lightCoords); }); if (data != null) { MapRenderer mapRenderer = this.minecraft.getMapRenderer(); mapRenderer.extractRenderState(id, data, this.mapRenderState); mapRenderer.render(this.mapRenderState, poseStack, submitNodeCollector, false, lightCoords); } } private void renderPlayerArm(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float inverseArmHeight, float attackValue, HumanoidArm arm) { boolean isRightArm = arm != HumanoidArm.LEFT; float invert = isRightArm ? 1.0f : -1.0f; float sqrtAttackValue = Mth.sqrt(attackValue); float xSwingPosition = -0.3f * Mth.sin(sqrtAttackValue * (float)Math.PI); float ySwingPosition = 0.4f * Mth.sin(sqrtAttackValue * ((float)Math.PI * 2)); float zSwingPosition = -0.4f * Mth.sin(attackValue * (float)Math.PI); poseStack.translate(invert * (xSwingPosition + 0.64000005f), ySwingPosition + -0.6f + inverseArmHeight * -0.6f, zSwingPosition + -0.71999997f); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(invert * 45.0f)); float zSwingRotation = Mth.sin(attackValue * attackValue * (float)Math.PI); float ySwingRotation = Mth.sin(sqrtAttackValue * (float)Math.PI); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(invert * ySwingRotation * 70.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(invert * zSwingRotation * -20.0f)); LocalPlayer player = this.minecraft.player; poseStack.translate(invert * -1.0f, 3.6f, 3.5f); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(invert * 120.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(200.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(invert * -135.0f)); poseStack.translate(invert * 5.6f, 0.0f, 0.0f); AvatarRenderer avatarRenderer = this.entityRenderDispatcher.getPlayerRenderer(player); Identifier skinTexture = player.getSkin().body().texturePath(); if (isRightArm) { avatarRenderer.renderRightHand(poseStack, submitNodeCollector, lightCoords, skinTexture, player.isModelPartShown(PlayerModelPart.RIGHT_SLEEVE)); } else { avatarRenderer.renderLeftHand(poseStack, submitNodeCollector, lightCoords, skinTexture, player.isModelPartShown(PlayerModelPart.LEFT_SLEEVE)); } } private void applyEatTransform(PoseStack poseStack, float frameInterp, HumanoidArm arm, ItemStack itemStack, Player player) { float currUsageTime = (float)player.getUseItemRemainingTicks() - frameInterp + 1.0f; float scaledUsageTime = currUsageTime / (float)itemStack.getUseDuration(player); if (scaledUsageTime < 0.8f) { float extraHeightOffset = Mth.abs(Mth.cos(currUsageTime / 4.0f * (float)Math.PI) * 0.1f); poseStack.translate(0.0f, extraHeightOffset, 0.0f); } float eatJiggle = 1.0f - (float)Math.pow(scaledUsageTime, 27.0); int invert = arm == HumanoidArm.RIGHT ? 1 : -1; poseStack.translate(eatJiggle * 0.6f * (float)invert, eatJiggle * -0.5f, eatJiggle * 0.0f); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * eatJiggle * 90.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(eatJiggle * 10.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * eatJiggle * 30.0f)); } private void applyBrushTransform(PoseStack poseStack, float frameInterp, HumanoidArm arm, Player player) { float brushAnimationRemainingTicks = player.getUseItemRemainingTicks() % 10; float deltaSinceLastUpdate = brushAnimationRemainingTicks - frameInterp + 1.0f; float scaledUsageTime = 1.0f - deltaSinceLastUpdate / 10.0f; float minSwipeAngle = -90.0f; float maxSwipeAngle = 60.0f; float swipeRange = 150.0f; float swipeCenter = -15.0f; int swipeSpeed = 2; float currentSwipeAngle = -15.0f + 75.0f * Mth.cos(scaledUsageTime * 2.0f * (float)Math.PI); if (arm != HumanoidArm.RIGHT) { poseStack.translate(0.1, 0.83, 0.35); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-80.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(-90.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(currentSwipeAngle)); poseStack.translate(-0.3, 0.22, 0.35); } else { poseStack.translate(-0.25, 0.22, 0.35); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-80.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees(90.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees(0.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(currentSwipeAngle)); } } private void applyItemArmAttackTransform(PoseStack poseStack, HumanoidArm arm, float attackValue) { int invert = arm == HumanoidArm.RIGHT ? 1 : -1; float ySwingRotation = Mth.sin(attackValue * attackValue * (float)Math.PI); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * (45.0f + ySwingRotation * -20.0f))); float xzSwingRotation = Mth.sin(Mth.sqrt(attackValue) * (float)Math.PI); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * xzSwingRotation * -20.0f)); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(xzSwingRotation * -80.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * -45.0f)); } private void applyItemArmTransform(PoseStack poseStack, HumanoidArm arm, float inverseArmHeight) { int invert = arm == HumanoidArm.RIGHT ? 1 : -1; poseStack.translate((float)invert * 0.56f, -0.52f + inverseArmHeight * -0.6f, -0.72f); } public void renderHandsWithItems(float frameInterp, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, LocalPlayer player, int lightCoords) { float attackValue = player.getAttackAnim(frameInterp); InteractionHand attackHand = (InteractionHand)((Object)MoreObjects.firstNonNull((Object)((Object)player.swingingArm), (Object)((Object)InteractionHand.MAIN_HAND))); float xRot = player.getXRot(frameInterp); HandRenderSelection handRenderSelection = ItemInHandRenderer.evaluateWhichHandsToRender(player); float xBob = Mth.lerp(frameInterp, player.xBobO, player.xBob); float yBob = Mth.lerp(frameInterp, player.yBobO, player.yBob); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees((player.getViewXRot(frameInterp) - xBob) * 0.1f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((player.getViewYRot(frameInterp) - yBob) * 0.1f)); if (handRenderSelection.renderMainHand) { float mainHandAttack = attackHand == InteractionHand.MAIN_HAND ? attackValue : 0.0f; float mainhandInverseArmHeight = this.itemModelResolver.swapAnimationScale(this.mainHandItem) * (1.0f - Mth.lerp(frameInterp, this.oMainHandHeight, this.mainHandHeight)); this.renderArmWithItem(player, frameInterp, xRot, InteractionHand.MAIN_HAND, mainHandAttack, this.mainHandItem, mainhandInverseArmHeight, poseStack, submitNodeCollector, lightCoords); } if (handRenderSelection.renderOffHand) { float offHandAttack = attackHand == InteractionHand.OFF_HAND ? attackValue : 0.0f; float offhandInverseArmHeight = this.itemModelResolver.swapAnimationScale(this.offHandItem) * (1.0f - Mth.lerp(frameInterp, this.oOffHandHeight, this.offHandHeight)); this.renderArmWithItem(player, frameInterp, xRot, InteractionHand.OFF_HAND, offHandAttack, this.offHandItem, offhandInverseArmHeight, poseStack, submitNodeCollector, lightCoords); } this.minecraft.gameRenderer.getFeatureRenderDispatcher().renderAllFeatures(); this.minecraft.renderBuffers().bufferSource().endBatch(); } @VisibleForTesting static HandRenderSelection evaluateWhichHandsToRender(LocalPlayer player) { boolean holdsCrossbow; ItemStack mainHandItem = player.getMainHandItem(); ItemStack offhandItem = player.getOffhandItem(); boolean holdsBow = mainHandItem.is(Items.BOW) || offhandItem.is(Items.BOW); boolean bl = holdsCrossbow = mainHandItem.is(Items.CROSSBOW) || offhandItem.is(Items.CROSSBOW); if (!holdsBow && !holdsCrossbow) { return HandRenderSelection.RENDER_BOTH_HANDS; } if (player.isUsingItem()) { return ItemInHandRenderer.selectionUsingItemWhileHoldingBowLike(player); } if (ItemInHandRenderer.isChargedCrossbow(mainHandItem)) { return HandRenderSelection.RENDER_MAIN_HAND_ONLY; } return HandRenderSelection.RENDER_BOTH_HANDS; } private static HandRenderSelection selectionUsingItemWhileHoldingBowLike(LocalPlayer player) { ItemStack usedItemStack = player.getUseItem(); InteractionHand usedHand = player.getUsedItemHand(); if (usedItemStack.is(Items.BOW) || usedItemStack.is(Items.CROSSBOW)) { return HandRenderSelection.onlyForHand(usedHand); } return usedHand == InteractionHand.MAIN_HAND && ItemInHandRenderer.isChargedCrossbow(player.getOffhandItem()) ? HandRenderSelection.RENDER_MAIN_HAND_ONLY : HandRenderSelection.RENDER_BOTH_HANDS; } private static boolean isChargedCrossbow(ItemStack item) { return item.is(Items.CROSSBOW) && CrossbowItem.isCharged(item); } private void renderArmWithItem(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords) { if (player.isScoping()) { return; } boolean isMainHand = hand == InteractionHand.MAIN_HAND; HumanoidArm arm = isMainHand ? player.getMainArm() : player.getMainArm().getOpposite(); poseStack.pushPose(); if (itemStack.isEmpty()) { if (isMainHand && !player.isInvisible()) { this.renderPlayerArm(poseStack, submitNodeCollector, lightCoords, inverseArmHeight, attack, arm); } } else if (itemStack.has(DataComponents.MAP_ID)) { if (isMainHand && this.offHandItem.isEmpty()) { this.renderTwoHandedMap(poseStack, submitNodeCollector, lightCoords, xRot, inverseArmHeight, attack); } else { this.renderOneHandedMap(poseStack, submitNodeCollector, lightCoords, inverseArmHeight, arm, attack, itemStack); } } else if (itemStack.is(Items.CROSSBOW)) { int invert; this.applyItemArmTransform(poseStack, arm, inverseArmHeight); boolean charged = CrossbowItem.isCharged(itemStack); boolean isRightArm = arm == HumanoidArm.RIGHT; int n = invert = isRightArm ? 1 : -1; if (player.isUsingItem() && player.getUseItemRemainingTicks() > 0 && player.getUsedItemHand() == hand && !charged) { poseStack.translate((float)invert * -0.4785682f, -0.094387f, 0.05731531f); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-11.935f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 65.3f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * -9.785f)); float timeHeld = (float)itemStack.getUseDuration(player) - ((float)player.getUseItemRemainingTicks() - frameInterp + 1.0f); float power = timeHeld / (float)CrossbowItem.getChargeDuration(itemStack, player); if (power > 1.0f) { power = 1.0f; } if (power > 0.1f) { float shakeOffset = Mth.sin((timeHeld - 0.1f) * 1.3f); float shakeIntensity = power - 0.1f; float shake = shakeOffset * shakeIntensity; poseStack.translate(shake * 0.0f, shake * 0.004f, shake * 0.0f); } poseStack.translate(power * 0.0f, power * 0.0f, power * 0.04f); poseStack.scale(1.0f, 1.0f, 1.0f + power * 0.2f); poseStack.mulPose((Quaternionfc)Axis.YN.rotationDegrees((float)invert * 45.0f)); } else { this.swingArm(attack, poseStack, invert, arm); if (charged && attack < 0.001f && isMainHand) { poseStack.translate((float)invert * -0.641864f, 0.0f, 0.0f); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 10.0f)); } } this.renderItem(player, itemStack, isRightArm ? ItemDisplayContext.FIRST_PERSON_RIGHT_HAND : ItemDisplayContext.FIRST_PERSON_LEFT_HAND, poseStack, submitNodeCollector, lightCoords); } else { int invert; boolean isRightArm = arm == HumanoidArm.RIGHT; int n = invert = isRightArm ? 1 : -1; if (player.isUsingItem() && player.getUseItemRemainingTicks() > 0 && player.getUsedItemHand() == hand) { ItemUseAnimation useAnimation = itemStack.getUseAnimation(); if (!useAnimation.hasCustomArmTransform()) { this.applyItemArmTransform(poseStack, arm, inverseArmHeight); } switch (useAnimation) { case NONE: { break; } case EAT: case DRINK: { this.applyEatTransform(poseStack, frameInterp, arm, itemStack, player); this.applyItemArmTransform(poseStack, arm, inverseArmHeight); break; } case BLOCK: { if (itemStack.getItem() instanceof ShieldItem) break; poseStack.translate((float)invert * -0.14142136f, 0.08f, 0.14142136f); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-102.25f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 13.365f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * 78.05f)); break; } case BOW: { poseStack.translate((float)invert * -0.2785682f, 0.18344387f, 0.15731531f); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-13.935f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 35.3f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * -9.785f)); float timeHeld = (float)itemStack.getUseDuration(player) - ((float)player.getUseItemRemainingTicks() - frameInterp + 1.0f); float power = timeHeld / 20.0f; power = (power * power + power * 2.0f) / 3.0f; if (power > 1.0f) { power = 1.0f; } if (power > 0.1f) { float shakeOffset = Mth.sin((timeHeld - 0.1f) * 1.3f); float shakeIntensity = power - 0.1f; float shake = shakeOffset * shakeIntensity; poseStack.translate(shake * 0.0f, shake * 0.004f, shake * 0.0f); } poseStack.translate(power * 0.0f, power * 0.0f, power * 0.04f); poseStack.scale(1.0f, 1.0f, 1.0f + power * 0.2f); poseStack.mulPose((Quaternionfc)Axis.YN.rotationDegrees((float)invert * 45.0f)); break; } case TRIDENT: { poseStack.translate((float)invert * -0.5f, 0.7f, 0.1f); poseStack.mulPose((Quaternionfc)Axis.XP.rotationDegrees(-55.0f)); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 35.3f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * -9.785f)); float timeHeld = (float)itemStack.getUseDuration(player) - ((float)player.getUseItemRemainingTicks() - frameInterp + 1.0f); float power = timeHeld / 10.0f; if (power > 1.0f) { power = 1.0f; } if (power > 0.1f) { float shakeOffset = Mth.sin((timeHeld - 0.1f) * 1.3f); float shakeIntensity = power - 0.1f; float shake = shakeOffset * shakeIntensity; poseStack.translate(shake * 0.0f, shake * 0.004f, shake * 0.0f); } poseStack.translate(0.0f, 0.0f, power * 0.2f); poseStack.scale(1.0f, 1.0f, 1.0f + power * 0.2f); poseStack.mulPose((Quaternionfc)Axis.YN.rotationDegrees((float)invert * 45.0f)); break; } case BRUSH: { this.applyBrushTransform(poseStack, frameInterp, arm, player); break; } case BUNDLE: { this.swingArm(attack, poseStack, invert, arm); break; } case SPEAR: { poseStack.translate((float)invert * 0.56f, -0.52f, -0.72f); float timeHeld = (float)itemStack.getUseDuration(player) - ((float)player.getUseItemRemainingTicks() - frameInterp + 1.0f); SpearAnimations.firstPersonUse(player.getTicksSinceEnemyHit(frameInterp), poseStack, timeHeld, arm, itemStack); break; } } } else if (player.isAutoSpinAttack()) { this.applyItemArmTransform(poseStack, arm, inverseArmHeight); poseStack.translate((float)invert * -0.4f, 0.8f, 0.3f); poseStack.mulPose((Quaternionfc)Axis.YP.rotationDegrees((float)invert * 65.0f)); poseStack.mulPose((Quaternionfc)Axis.ZP.rotationDegrees((float)invert * -85.0f)); } else { this.applyItemArmTransform(poseStack, arm, inverseArmHeight); switch (itemStack.getSwingAnimation().type()) { case NONE: { break; } case WHACK: { this.swingArm(attack, poseStack, invert, arm); break; } case STAB: { SpearAnimations.firstPersonAttack(attack, poseStack, invert, arm); } } } this.renderItem(player, itemStack, isRightArm ? ItemDisplayContext.FIRST_PERSON_RIGHT_HAND : ItemDisplayContext.FIRST_PERSON_LEFT_HAND, poseStack, submitNodeCollector, lightCoords); } poseStack.popPose(); } private void swingArm(float attack, PoseStack poseStack, int invert, HumanoidArm arm) { float xSwingPosition = -0.4f * Mth.sin(Mth.sqrt(attack) * (float)Math.PI); float ySwingPosition = 0.2f * Mth.sin(Mth.sqrt(attack) * ((float)Math.PI * 2)); float zSwingPosition = -0.2f * Mth.sin(attack * (float)Math.PI); poseStack.translate((float)invert * xSwingPosition, ySwingPosition, zSwingPosition); this.applyItemArmAttackTransform(poseStack, arm, attack); } private boolean shouldInstantlyReplaceVisibleItem(ItemStack currentlyVisibleItem, ItemStack expectedItem) { if (ItemStack.matchesIgnoringComponents(currentlyVisibleItem, expectedItem, DataComponentType::ignoreSwapAnimation)) { return true; } return !this.itemModelResolver.shouldPlaySwapAnimation(expectedItem); } public void tick() { this.oMainHandHeight = this.mainHandHeight; this.oOffHandHeight = this.offHandHeight; LocalPlayer player = this.minecraft.player; ItemStack nextMainHand = player.getMainHandItem(); ItemStack nextOffHand = player.getOffhandItem(); if (this.shouldInstantlyReplaceVisibleItem(this.mainHandItem, nextMainHand)) { this.mainHandItem = nextMainHand; } if (this.shouldInstantlyReplaceVisibleItem(this.offHandItem, nextOffHand)) { this.offHandItem = nextOffHand; } if (player.isHandsBusy()) { this.mainHandHeight = Mth.clamp(this.mainHandHeight - 0.4f, 0.0f, 1.0f); this.offHandHeight = Mth.clamp(this.offHandHeight - 0.4f, 0.0f, 1.0f); } else { float attackAnim = player.getItemSwapScale(1.0f); float mainHandTargetHeight = this.mainHandItem != nextMainHand ? 0.0f : attackAnim * attackAnim * attackAnim; float offHandTargetHeight = this.offHandItem != nextOffHand ? 0.0f : 1.0f; this.mainHandHeight += Mth.clamp(mainHandTargetHeight - this.mainHandHeight, -0.4f, 0.4f); this.offHandHeight += Mth.clamp(offHandTargetHeight - this.offHandHeight, -0.4f, 0.4f); } if (this.mainHandHeight < 0.1f) { this.mainHandItem = nextMainHand; } if (this.offHandHeight < 0.1f) { this.offHandItem = nextOffHand; } } public void itemUsed(InteractionHand hand) { if (hand == InteractionHand.MAIN_HAND) { this.mainHandHeight = 0.0f; } else { this.offHandHeight = 0.0f; } } @VisibleForTesting static enum HandRenderSelection { RENDER_BOTH_HANDS(true, true), RENDER_MAIN_HAND_ONLY(true, false), RENDER_OFF_HAND_ONLY(false, true); final boolean renderMainHand; final boolean renderOffHand; private HandRenderSelection(boolean renderMainHand, boolean renderOffHand) { this.renderMainHand = renderMainHand; this.renderOffHand = renderOffHand; } public static HandRenderSelection onlyForHand(InteractionHand hand) { return hand == InteractionHand.MAIN_HAND ? RENDER_MAIN_HAND_ONLY : RENDER_OFF_HAND_ONLY; } } }