ItemInHandRenderer.java

net.minecraft.client.renderer.ItemInHandRenderer

信息

  • 全限定名:net.minecraft.client.renderer.ItemInHandRenderer
  • 类型:public class
  • 包:net.minecraft.client.renderer
  • 源码路径:src/main/java/net/minecraft/client/renderer/ItemInHandRenderer.java
  • 起始行号:L41
  • 职责:

    TODO

字段/常量

  • MAP_BACKGROUND

    • 类型: RenderType
    • 修饰符: private static final
    • 源码定位: L42
    • 说明:

      TODO

  • MAP_BACKGROUND_CHECKERBOARD

    • 类型: RenderType
    • 修饰符: private static final
    • 源码定位: L43
    • 说明:

      TODO

  • ITEM_SWING_X_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L46
    • 说明:

      TODO

  • ITEM_SWING_Y_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L47
    • 说明:

      TODO

  • ITEM_SWING_Z_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L48
    • 说明:

      TODO

  • ITEM_HEIGHT_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L49
    • 说明:

      TODO

  • ITEM_POS_X

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • ITEM_POS_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L51
    • 说明:

      TODO

  • ITEM_POS_Z

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L52
    • 说明:

      TODO

  • ITEM_PRESWING_ROT_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L53
    • 说明:

      TODO

  • ITEM_SWING_X_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L54
    • 说明:

      TODO

  • ITEM_SWING_Y_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L55
    • 说明:

      TODO

  • ITEM_SWING_Z_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L56
    • 说明:

      TODO

  • EAT_JIGGLE_X_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L57
    • 说明:

      TODO

  • EAT_JIGGLE_Y_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L58
    • 说明:

      TODO

  • EAT_JIGGLE_Z_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L59
    • 说明:

      TODO

  • EAT_JIGGLE_X_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L60
    • 说明:

      TODO

  • EAT_JIGGLE_Y_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L61
    • 说明:

      TODO

  • EAT_JIGGLE_Z_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L62
    • 说明:

      TODO

  • EAT_JIGGLE_EXPONENT

    • 类型: double
    • 修饰符: private static final
    • 源码定位: L63
    • 说明:

      TODO

  • EAT_EXTRA_JIGGLE_CUTOFF

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L64
    • 说明:

      TODO

  • EAT_EXTRA_JIGGLE_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L65
    • 说明:

      TODO

  • ARM_SWING_X_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L66
    • 说明:

      TODO

  • ARM_SWING_Y_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L67
    • 说明:

      TODO

  • ARM_SWING_Z_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L68
    • 说明:

      TODO

  • ARM_SWING_Y_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L69
    • 说明:

      TODO

  • ARM_SWING_Z_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L70
    • 说明:

      TODO

  • ARM_HEIGHT_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L71
    • 说明:

      TODO

  • ARM_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L72
    • 说明:

      TODO

  • ARM_POS_X

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L73
    • 说明:

      TODO

  • ARM_POS_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L74
    • 说明:

      TODO

  • ARM_POS_Z

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L75
    • 说明:

      TODO

  • ARM_PRESWING_ROT_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L76
    • 说明:

      TODO

  • ARM_PREROTATION_X_OFFSET

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L77
    • 说明:

      TODO

  • ARM_PREROTATION_Y_OFFSET

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L78
    • 说明:

      TODO

  • ARM_PREROTATION_Z_OFFSET

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L79
    • 说明:

      TODO

  • ARM_POSTROTATION_X_OFFSET

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L80
    • 说明:

      TODO

  • ARM_ROT_X

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L81
    • 说明:

      TODO

  • ARM_ROT_Y

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L82
    • 说明:

      TODO

  • ARM_ROT_Z

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L83
    • 说明:

      TODO

  • MAP_SWING_X_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L84
    • 说明:

      TODO

  • MAP_SWING_Z_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L85
    • 说明:

      TODO

  • MAP_HANDS_POS_X

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L86
    • 说明:

      TODO

  • MAP_HANDS_POS_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L87
    • 说明:

      TODO

  • MAP_HANDS_POS_Z

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L88
    • 说明:

      TODO

  • MAP_HANDS_HEIGHT_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L89
    • 说明:

      TODO

  • MAP_HANDS_TILT_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L90
    • 说明:

      TODO

  • MAP_PLAYER_PITCH_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L91
    • 说明:

      TODO

  • MAP_HANDS_Z_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L92
    • 说明:

      TODO

  • MAPHAND_X_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L93
    • 说明:

      TODO

  • MAPHAND_Y_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L94
    • 说明:

      TODO

  • MAPHAND_Z_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L95
    • 说明:

      TODO

  • MAP_HAND_X_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L96
    • 说明:

      TODO

  • MAP_HAND_Y_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L97
    • 说明:

      TODO

  • MAP_HAND_Z_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L98
    • 说明:

      TODO

  • MAP_SWING_X_ROT_AMOUNT

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L99
    • 说明:

      TODO

  • MAP_PRE_ROT_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L100
    • 说明:

      TODO

  • MAP_GLOBAL_X_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L101
    • 说明:

      TODO

  • MAP_GLOBAL_Y_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L102
    • 说明:

      TODO

  • MAP_GLOBAL_Z_POS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L103
    • 说明:

      TODO

  • MAP_FINAL_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L104
    • 说明:

      TODO

  • MAP_BORDER

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L105
    • 说明:

      TODO

  • MAP_HEIGHT

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L106
    • 说明:

      TODO

  • MAP_WIDTH

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L107
    • 说明:

      TODO

  • BOW_CHARGE_X_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L108
    • 说明:

      TODO

  • BOW_CHARGE_Y_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L109
    • 说明:

      TODO

  • BOW_CHARGE_Z_POS_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L110
    • 说明:

      TODO

  • BOW_CHARGE_SHAKE_X_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L111
    • 说明:

      TODO

  • BOW_CHARGE_SHAKE_Y_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L112
    • 说明:

      TODO

  • BOW_CHARGE_SHAKE_Z_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L113
    • 说明:

      TODO

  • BOW_CHARGE_Z_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L114
    • 说明:

      TODO

  • BOW_MIN_SHAKE_CHARGE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L115
    • 说明:

      TODO

  • minecraft

    • 类型: Minecraft
    • 修饰符: private final
    • 源码定位: L116
    • 说明:

      TODO

  • mapRenderState

    • 类型: MapRenderState
    • 修饰符: private final
    • 源码定位: L117
    • 说明:

      TODO

  • mainHandItem

    • 类型: ItemStack
    • 修饰符: private
    • 源码定位: L118
    • 说明:

      TODO

  • offHandItem

    • 类型: ItemStack
    • 修饰符: private
    • 源码定位: L119
    • 说明:

      TODO

  • mainHandHeight

    • 类型: float
    • 修饰符: private
    • 源码定位: L120
    • 说明:

      TODO

  • oMainHandHeight

    • 类型: float
    • 修饰符: private
    • 源码定位: L121
    • 说明:

      TODO

  • offHandHeight

    • 类型: float
    • 修饰符: private
    • 源码定位: L122
    • 说明:

      TODO

  • oOffHandHeight

    • 类型: float
    • 修饰符: private
    • 源码定位: L123
    • 说明:

      TODO

  • entityRenderDispatcher

    • 类型: EntityRenderDispatcher
    • 修饰符: private final
    • 源码定位: L124
    • 说明:

      TODO

  • itemModelResolver

    • 类型: ItemModelResolver
    • 修饰符: private final
    • 源码定位: L125
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.renderer.ItemInHandRenderer.HandRenderSelection
    • 类型: enum
    • 修饰符: static
    • 源码定位: L658
    • 说明:

      TODO

构造器

public ItemInHandRenderer(Minecraft minecraft, EntityRenderDispatcher entityRenderDispatcher, ItemModelResolver itemModelResolver) @ L127

  • 构造器名:ItemInHandRenderer
  • 源码定位:L127
  • 修饰符:public

参数:

  • minecraft: Minecraft
  • entityRenderDispatcher: EntityRenderDispatcher
  • itemModelResolver: ItemModelResolver

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void renderItem(LivingEntity mob, ItemStack itemStack, ItemDisplayContext type, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords) @ L133

  • 方法名:renderItem
  • 源码定位:L133
  • 返回类型:void
  • 修饰符:public

参数:

  • mob: LivingEntity
  • itemStack: ItemStack
  • type: ItemDisplayContext
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int

说明:

TODO

private float calculateMapTilt(float xRot) @ L143

  • 方法名:calculateMapTilt
  • 源码定位:L143
  • 返回类型:float
  • 修饰符:private

参数:

  • xRot: float

说明:

TODO

private void renderMapHand(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, HumanoidArm arm) @ L149

  • 方法名:renderMapHand
  • 源码定位:L149
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int
  • arm: HumanoidArm

说明:

TODO

private void renderOneHandedMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float inverseArmHeight, HumanoidArm arm, float attackValue, ItemStack map) @ L171

  • 方法名:renderOneHandedMap
  • 源码定位:L171
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int
  • inverseArmHeight: float
  • arm: HumanoidArm
  • attackValue: float
  • map: ItemStack

说明:

TODO

private void renderTwoHandedMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float xRot, float inverseArmHeight, float attackValue) @ L203

  • 方法名:renderTwoHandedMap
  • 源码定位:L203
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int
  • xRot: float
  • inverseArmHeight: float
  • attackValue: float

说明:

TODO

private void renderMap(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, ItemStack itemStack) @ L227

  • 方法名:renderMap
  • 源码定位:L227
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int
  • itemStack: ItemStack

说明:

TODO

private void renderPlayerArm(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, float inverseArmHeight, float attackValue, HumanoidArm arm) @ L249

  • 方法名:renderPlayerArm
  • 源码定位:L249
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int
  • inverseArmHeight: float
  • attackValue: float
  • arm: HumanoidArm

说明:

TODO

private void applyEatTransform(PoseStack poseStack, float frameInterp, HumanoidArm arm, ItemStack itemStack, Player player) @ L279

  • 方法名:applyEatTransform
  • 源码定位:L279
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • frameInterp: float
  • arm: HumanoidArm
  • itemStack: ItemStack
  • player: Player

说明:

TODO

private void applyBrushTransform(PoseStack poseStack, float frameInterp, HumanoidArm arm, Player player) @ L295

  • 方法名:applyBrushTransform
  • 源码定位:L295
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • frameInterp: float
  • arm: HumanoidArm
  • player: Player

说明:

TODO

private void applyItemArmAttackTransform(PoseStack poseStack, HumanoidArm arm, float attackValue) @ L320

  • 方法名:applyItemArmAttackTransform
  • 源码定位:L320
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • arm: HumanoidArm
  • attackValue: float

说明:

TODO

private void applyItemArmTransform(PoseStack poseStack, HumanoidArm arm, float inverseArmHeight) @ L330

  • 方法名:applyItemArmTransform
  • 源码定位:L330
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • arm: HumanoidArm
  • inverseArmHeight: float

说明:

TODO

public void renderHandsWithItems(float frameInterp, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, LocalPlayer player, int lightCoords) @ L335

  • 方法名:renderHandsWithItems
  • 源码定位:L335
  • 返回类型:void
  • 修饰符:public

参数:

  • frameInterp: float
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • player: LocalPlayer
  • lightCoords: int

说明:

TODO

static ItemInHandRenderer.HandRenderSelection evaluateWhichHandsToRender(LocalPlayer player) @ L384

  • 方法名:evaluateWhichHandsToRender
  • 源码定位:L384
  • 返回类型:ItemInHandRenderer.HandRenderSelection
  • 修饰符:static

参数:

  • player: LocalPlayer

说明:

TODO

private static ItemInHandRenderer.HandRenderSelection selectionUsingItemWhileHoldingBowLike(LocalPlayer player) @ L401

  • 方法名:selectionUsingItemWhileHoldingBowLike
  • 源码定位:L401
  • 返回类型:ItemInHandRenderer.HandRenderSelection
  • 修饰符:private static

参数:

  • player: LocalPlayer

说明:

TODO

private static boolean isChargedCrossbow(ItemStack item) @ L413

  • 方法名:isChargedCrossbow
  • 源码定位:L413
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • item: ItemStack

说明:

TODO

private void renderArmWithItem(AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords) @ L417

  • 方法名:renderArmWithItem
  • 源码定位:L417
  • 返回类型:void
  • 修饰符:private

参数:

  • player: AbstractClientPlayer
  • frameInterp: float
  • xRot: float
  • hand: InteractionHand
  • attack: float
  • itemStack: ItemStack
  • inverseArmHeight: float
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • lightCoords: int

说明:

TODO

private void swingArm(float attack, PoseStack poseStack, int invert, HumanoidArm arm) @ L600

  • 方法名:swingArm
  • 源码定位:L600
  • 返回类型:void
  • 修饰符:private

参数:

  • attack: float
  • poseStack: PoseStack
  • invert: int
  • arm: HumanoidArm

说明:

TODO

private boolean shouldInstantlyReplaceVisibleItem(ItemStack currentlyVisibleItem, ItemStack expectedItem) @ L608

  • 方法名:shouldInstantlyReplaceVisibleItem
  • 源码定位:L608
  • 返回类型:boolean
  • 修饰符:private

参数:

  • currentlyVisibleItem: ItemStack
  • expectedItem: ItemStack

说明:

TODO

public void tick() @ L614

  • 方法名:tick
  • 源码定位:L614
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void itemUsed(InteractionHand hand) @ L648

  • 方法名:itemUsed
  • 源码定位:L648
  • 返回类型:void
  • 修饰符:public

参数:

  • hand: InteractionHand

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
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 ItemModelResolver itemModelResolver;
 
    public ItemInHandRenderer(Minecraft minecraft, EntityRenderDispatcher entityRenderDispatcher, ItemModelResolver itemModelResolver) {
        this.minecraft = minecraft;
        this.entityRenderDispatcher = entityRenderDispatcher;
        this.itemModelResolver = itemModelResolver;
    }
 
    public void renderItem(
        LivingEntity mob, ItemStack itemStack, ItemDisplayContext type, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords
    ) {
        if (!itemStack.isEmpty()) {
            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);
        return -Mth.cos(tilt * (float) Math.PI) * 0.5F + 0.5F;
    }
 
    private void renderMapHand(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, HumanoidArm arm) {
        AvatarRenderer<AbstractClientPlayer> avatarRenderer = this.entityRenderDispatcher.getPlayerRenderer(this.minecraft.player);
        poseStack.pushPose();
        float invert = arm == HumanoidArm.RIGHT ? 1.0F : -1.0F;
        poseStack.mulPose(Axis.YP.rotationDegrees(92.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(45.0F));
        poseStack.mulPose(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(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(Axis.XP.rotationDegrees(xSwing * -45.0F));
        poseStack.mulPose(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(Axis.XP.rotationDegrees(mapTilt * -85.0F));
        if (!this.minecraft.player.isInvisible()) {
            poseStack.pushPose();
            poseStack.mulPose(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(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(Axis.YP.rotationDegrees(180.0F));
        poseStack.mulPose(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, 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(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(Axis.YP.rotationDegrees(invert * ySwingRotation * 70.0F));
        poseStack.mulPose(Axis.ZP.rotationDegrees(invert * zSwingRotation * -20.0F));
        AbstractClientPlayer player = this.minecraft.player;
        poseStack.translate(invert * -1.0F, 3.6F, 3.5F);
        poseStack.mulPose(Axis.ZP.rotationDegrees(invert * 120.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(200.0F));
        poseStack.mulPose(Axis.YP.rotationDegrees(invert * -135.0F));
        poseStack.translate(invert * 5.6F, 0.0F, 0.0F);
        AvatarRenderer<AbstractClientPlayer> 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 = player.getUseItemRemainingTicks() - frameInterp + 1.0F;
        float scaledUsageTime = currUsageTime / 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 * invert, eatJiggle * -0.5F, eatJiggle * 0.0F);
        poseStack.mulPose(Axis.YP.rotationDegrees(invert * eatJiggle * 90.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(eatJiggle * 10.0F));
        poseStack.mulPose(Axis.ZP.rotationDegrees(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(Axis.XP.rotationDegrees(-80.0F));
            poseStack.mulPose(Axis.YP.rotationDegrees(-90.0F));
            poseStack.mulPose(Axis.XP.rotationDegrees(currentSwipeAngle));
            poseStack.translate(-0.3, 0.22, 0.35);
        } else {
            poseStack.translate(-0.25, 0.22, 0.35);
            poseStack.mulPose(Axis.XP.rotationDegrees(-80.0F));
            poseStack.mulPose(Axis.YP.rotationDegrees(90.0F));
            poseStack.mulPose(Axis.ZP.rotationDegrees(0.0F));
            poseStack.mulPose(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(Axis.YP.rotationDegrees(invert * (45.0F + ySwingRotation * -20.0F)));
        float xzSwingRotation = Mth.sin(Mth.sqrt(attackValue) * (float) Math.PI);
        poseStack.mulPose(Axis.ZP.rotationDegrees(invert * xzSwingRotation * -20.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(xzSwingRotation * -80.0F));
        poseStack.mulPose(Axis.YP.rotationDegrees(invert * -45.0F));
    }
 
    private void applyItemArmTransform(PoseStack poseStack, HumanoidArm arm, float inverseArmHeight) {
        int invert = arm == HumanoidArm.RIGHT ? 1 : -1;
        poseStack.translate(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 = MoreObjects.firstNonNull(player.swingingArm, InteractionHand.MAIN_HAND);
        float xRot = player.getXRot(frameInterp);
        ItemInHandRenderer.HandRenderSelection handRenderSelection = evaluateWhichHandsToRender(player);
        float xBob = Mth.lerp(frameInterp, player.xBobO, player.xBob);
        float yBob = Mth.lerp(frameInterp, player.yBobO, player.yBob);
        poseStack.mulPose(Axis.XP.rotationDegrees((player.getViewXRot(frameInterp) - xBob) * 0.1F));
        poseStack.mulPose(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 ItemInHandRenderer.HandRenderSelection evaluateWhichHandsToRender(LocalPlayer player) {
        ItemStack mainHandItem = player.getMainHandItem();
        ItemStack offhandItem = player.getOffhandItem();
        boolean holdsBow = mainHandItem.is(Items.BOW) || offhandItem.is(Items.BOW);
        boolean holdsCrossbow = mainHandItem.is(Items.CROSSBOW) || offhandItem.is(Items.CROSSBOW);
        if (!holdsBow && !holdsCrossbow) {
            return ItemInHandRenderer.HandRenderSelection.RENDER_BOTH_HANDS;
        } else if (player.isUsingItem()) {
            return selectionUsingItemWhileHoldingBowLike(player);
        } else {
            return isChargedCrossbow(mainHandItem)
                ? ItemInHandRenderer.HandRenderSelection.RENDER_MAIN_HAND_ONLY
                : ItemInHandRenderer.HandRenderSelection.RENDER_BOTH_HANDS;
        }
    }
 
    private static ItemInHandRenderer.HandRenderSelection selectionUsingItemWhileHoldingBowLike(LocalPlayer player) {
        ItemStack usedItemStack = player.getUseItem();
        InteractionHand usedHand = player.getUsedItemHand();
        if (!usedItemStack.is(Items.BOW) && !usedItemStack.is(Items.CROSSBOW)) {
            return usedHand == InteractionHand.MAIN_HAND && isChargedCrossbow(player.getOffhandItem())
                ? ItemInHandRenderer.HandRenderSelection.RENDER_MAIN_HAND_ONLY
                : ItemInHandRenderer.HandRenderSelection.RENDER_BOTH_HANDS;
        } else {
            return ItemInHandRenderer.HandRenderSelection.onlyForHand(usedHand);
        }
    }
 
    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()) {
            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)) {
                this.applyItemArmTransform(poseStack, arm, inverseArmHeight);
                boolean charged = CrossbowItem.isCharged(itemStack);
                boolean isRightArm = arm == HumanoidArm.RIGHT;
                int invert = isRightArm ? 1 : -1;
                if (player.isUsingItem() && player.getUseItemRemainingTicks() > 0 && player.getUsedItemHand() == hand && !charged) {
                    poseStack.translate(invert * -0.4785682F, -0.094387F, 0.05731531F);
                    poseStack.mulPose(Axis.XP.rotationDegrees(-11.935F));
                    poseStack.mulPose(Axis.YP.rotationDegrees(invert * 65.3F));
                    poseStack.mulPose(Axis.ZP.rotationDegrees(invert * -9.785F));
                    float timeHeld = itemStack.getUseDuration(player) - (player.getUseItemRemainingTicks() - frameInterp + 1.0F);
                    float power = timeHeld / 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(Axis.YN.rotationDegrees(invert * 45.0F));
                } else {
                    this.swingArm(attack, poseStack, invert, arm);
                    if (charged && attack < 0.001F && isMainHand) {
                        poseStack.translate(invert * -0.641864F, 0.0F, 0.0F);
                        poseStack.mulPose(Axis.YP.rotationDegrees(invert * 10.0F));
                    }
                }
 
                this.renderItem(
                    player,
                    itemStack,
                    isRightArm ? ItemDisplayContext.FIRST_PERSON_RIGHT_HAND : ItemDisplayContext.FIRST_PERSON_LEFT_HAND,
                    poseStack,
                    submitNodeCollector,
                    lightCoords
                );
            } else {
                boolean isRightArm = arm == HumanoidArm.RIGHT;
                int 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:
                        default:
                            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)) {
                                poseStack.translate(invert * -0.14142136F, 0.08F, 0.14142136F);
                                poseStack.mulPose(Axis.XP.rotationDegrees(-102.25F));
                                poseStack.mulPose(Axis.YP.rotationDegrees(invert * 13.365F));
                                poseStack.mulPose(Axis.ZP.rotationDegrees(invert * 78.05F));
                            }
                            break;
                        case BOW:
                            poseStack.translate(invert * -0.2785682F, 0.18344387F, 0.15731531F);
                            poseStack.mulPose(Axis.XP.rotationDegrees(-13.935F));
                            poseStack.mulPose(Axis.YP.rotationDegrees(invert * 35.3F));
                            poseStack.mulPose(Axis.ZP.rotationDegrees(invert * -9.785F));
                            float timeHeldxxx = itemStack.getUseDuration(player) - (player.getUseItemRemainingTicks() - frameInterp + 1.0F);
                            float powerxx = timeHeldxxx / 20.0F;
                            powerxx = (powerxx * powerxx + powerxx * 2.0F) / 3.0F;
                            if (powerxx > 1.0F) {
                                powerxx = 1.0F;
                            }
 
                            if (powerxx > 0.1F) {
                                float shakeOffset = Mth.sin((timeHeldxxx - 0.1F) * 1.3F);
                                float shakeIntensity = powerxx - 0.1F;
                                float shake = shakeOffset * shakeIntensity;
                                poseStack.translate(shake * 0.0F, shake * 0.004F, shake * 0.0F);
                            }
 
                            poseStack.translate(powerxx * 0.0F, powerxx * 0.0F, powerxx * 0.04F);
                            poseStack.scale(1.0F, 1.0F, 1.0F + powerxx * 0.2F);
                            poseStack.mulPose(Axis.YN.rotationDegrees(invert * 45.0F));
                            break;
                        case TRIDENT:
                            poseStack.translate(invert * -0.5F, 0.7F, 0.1F);
                            poseStack.mulPose(Axis.XP.rotationDegrees(-55.0F));
                            poseStack.mulPose(Axis.YP.rotationDegrees(invert * 35.3F));
                            poseStack.mulPose(Axis.ZP.rotationDegrees(invert * -9.785F));
                            float timeHeldxx = itemStack.getUseDuration(player) - (player.getUseItemRemainingTicks() - frameInterp + 1.0F);
                            float powerx = timeHeldxx / 10.0F;
                            if (powerx > 1.0F) {
                                powerx = 1.0F;
                            }
 
                            if (powerx > 0.1F) {
                                float shakeOffset = Mth.sin((timeHeldxx - 0.1F) * 1.3F);
                                float shakeIntensity = powerx - 0.1F;
                                float shake = shakeOffset * shakeIntensity;
                                poseStack.translate(shake * 0.0F, shake * 0.004F, shake * 0.0F);
                            }
 
                            poseStack.translate(0.0F, 0.0F, powerx * 0.2F);
                            poseStack.scale(1.0F, 1.0F, 1.0F + powerx * 0.2F);
                            poseStack.mulPose(Axis.YN.rotationDegrees(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(invert * 0.56F, -0.52F, -0.72F);
                            float timeHeldx = itemStack.getUseDuration(player) - (player.getUseItemRemainingTicks() - frameInterp + 1.0F);
                            SpearAnimations.firstPersonUse(player.getTicksSinceLastKineticHitFeedback(frameInterp), poseStack, timeHeldx, arm, itemStack);
                    }
                } else if (player.isAutoSpinAttack()) {
                    this.applyItemArmTransform(poseStack, arm, inverseArmHeight);
                    poseStack.translate(invert * -0.4F, 0.8F, 0.3F);
                    poseStack.mulPose(Axis.YP.rotationDegrees(invert * 65.0F));
                    poseStack.mulPose(Axis.ZP.rotationDegrees(invert * -85.0F));
                } else {
                    this.applyItemArmTransform(poseStack, arm, inverseArmHeight);
                    switch (itemStack.getSwingAnimation().type()) {
                        case NONE:
                        default:
                            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(invert * xSwingPosition, ySwingPosition, zSwingPosition);
        this.applyItemArmAttackTransform(poseStack, arm, attack);
    }
 
    private boolean shouldInstantlyReplaceVisibleItem(ItemStack currentlyVisibleItem, ItemStack expectedItem) {
        return ItemStack.matchesIgnoringComponents(currentlyVisibleItem, expectedItem, DataComponentType::ignoreSwapAnimation)
            ? true
            : !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 = this.mainHandHeight + Mth.clamp(mainHandTargetHeight - this.mainHandHeight, -0.4F, 0.4F);
            this.offHandHeight = 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;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    @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 ItemInHandRenderer.HandRenderSelection onlyForHand(InteractionHand hand) {
            return hand == InteractionHand.MAIN_HAND ? RENDER_MAIN_HAND_ONLY : RENDER_OFF_HAND_ONLY;
        }
    }
}

引用的其他类