LocalPlayer.java

net.minecraft.client.player.LocalPlayer

信息

  • 全限定名:net.minecraft.client.player.LocalPlayer
  • 类型:public class
  • 包:net.minecraft.client.player
  • 源码路径:src/main/java/net/minecraft/client/player/LocalPlayer.java
  • 起始行号:L111
  • 继承:AbstractClientPlayer
  • 职责:

    TODO

字段/常量

  • LOGGER

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

      TODO

  • POSITION_REMINDER_INTERVAL

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

      TODO

  • WATER_VISION_MAX_TIME

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

      TODO

  • WATER_VISION_QUICK_TIME

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

      TODO

  • WATER_VISION_QUICK_PERCENT

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

      TODO

  • SUFFOCATING_COLLISION_CHECK_SCALE

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

      TODO

  • MINOR_COLLISION_ANGLE_THRESHOLD_RADIAN

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

      TODO

  • connection

    • 类型: ClientPacketListener
    • 修饰符: public final
    • 源码定位: L119
    • 说明:

      TODO

  • stats

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

      TODO

  • recipeBook

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

      TODO

  • dropSpamThrottler

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

      TODO

  • ambientSoundHandlers

    • 类型: List<AmbientSoundHandler>
    • 修饰符: private final
    • 源码定位: L123
    • 说明:

      TODO

  • permissions

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

      TODO

  • chatAbilities

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

      TODO

  • xLast

    • 类型: double
    • 修饰符: private
    • 源码定位: L126
    • 说明:

      TODO

  • yLast

    • 类型: double
    • 修饰符: private
    • 源码定位: L127
    • 说明:

      TODO

  • zLast

    • 类型: double
    • 修饰符: private
    • 源码定位: L128
    • 说明:

      TODO

  • yRotLast

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

      TODO

  • xRotLast

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

      TODO

  • lastOnGround

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L131
    • 说明:

      TODO

  • lastHorizontalCollision

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L132
    • 说明:

      TODO

  • crouching

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L133
    • 说明:

      TODO

  • wasSprinting

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L134
    • 说明:

      TODO

  • positionReminder

    • 类型: int
    • 修饰符: private
    • 源码定位: L135
    • 说明:

      TODO

  • flashOnSetHealth

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L136
    • 说明:

      TODO

  • input

    • 类型: ClientInput
    • 修饰符: public
    • 源码定位: L137
    • 说明:

      TODO

  • lastSentInput

    • 类型: Input
    • 修饰符: private
    • 源码定位: L138
    • 说明:

      TODO

  • minecraft

    • 类型: Minecraft
    • 修饰符: protected final
    • 源码定位: L139
    • 说明:

      TODO

  • sprintTriggerTime

    • 类型: int
    • 修饰符: protected
    • 源码定位: L140
    • 说明:

      TODO

  • EXPERIENCE_DISPLAY_UNREADY_TO_SET

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

      TODO

  • EXPERIENCE_DISPLAY_READY_TO_SET

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

      TODO

  • experienceDisplayStartTick

    • 类型: int
    • 修饰符: public
    • 源码定位: L143
    • 说明:

      TODO

  • yBob

    • 类型: float
    • 修饰符: public
    • 源码定位: L144
    • 说明:

      TODO

  • xBob

    • 类型: float
    • 修饰符: public
    • 源码定位: L145
    • 说明:

      TODO

  • yBobO

    • 类型: float
    • 修饰符: public
    • 源码定位: L146
    • 说明:

      TODO

  • xBobO

    • 类型: float
    • 修饰符: public
    • 源码定位: L147
    • 说明:

      TODO

  • jumpRidingTicks

    • 类型: int
    • 修饰符: private
    • 源码定位: L148
    • 说明:

      TODO

  • jumpRidingScale

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

      TODO

  • portalEffectIntensity

    • 类型: float
    • 修饰符: public
    • 源码定位: L150
    • 说明:

      TODO

  • oPortalEffectIntensity

    • 类型: float
    • 修饰符: public
    • 源码定位: L151
    • 说明:

      TODO

  • startedUsingItem

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L152
    • 说明:

      TODO

  • usingItemHand

    • 类型: InteractionHand
    • 修饰符: private
    • 源码定位: L153
    • 说明:

      TODO

  • handsBusy

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L154
    • 说明:

      TODO

  • autoJumpEnabled

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L155
    • 说明:

      TODO

  • autoJumpTime

    • 类型: int
    • 修饰符: private
    • 源码定位: L156
    • 说明:

      TODO

  • wasFallFlying

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L157
    • 说明:

      TODO

  • waterVisionTime

    • 类型: int
    • 修饰符: private
    • 源码定位: L158
    • 说明:

      TODO

  • showDeathScreen

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L159
    • 说明:

      TODO

  • doLimitedCrafting

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L160
    • 说明:

      TODO

内部类/嵌套类型

构造器

public LocalPlayer(Minecraft minecraft, ClientLevel level, ClientPacketListener connection, StatsCounter stats, ClientRecipeBook recipeBook, Input lastSentInput, boolean wasSprinting, ChatAbilities chatAbilities) @ L162

  • 构造器名:LocalPlayer
  • 源码定位:L162
  • 修饰符:public

参数:

  • minecraft: Minecraft
  • level: ClientLevel
  • connection: ClientPacketListener
  • stats: StatsCounter
  • recipeBook: ClientRecipeBook
  • lastSentInput: Input
  • wasSprinting: boolean
  • chatAbilities: ChatAbilities

说明:

TODO

方法

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

public void heal(float heal) @ L185

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

参数:

  • heal: float

说明:

TODO

public boolean startRiding(Entity entity, boolean force, boolean sendEventAndTriggers) @ L189

  • 方法名:startRiding
  • 源码定位:L189
  • 返回类型:boolean
  • 修饰符:public

参数:

  • entity: Entity
  • force: boolean
  • sendEventAndTriggers: boolean

说明:

TODO

public void removeVehicle() @ L213

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

参数:

说明:

TODO

public float getViewXRot(float a) @ L219

  • 方法名:getViewXRot
  • 源码定位:L219
  • 返回类型:float
  • 修饰符:public

参数:

  • a: float

说明:

TODO

public float getViewYRot(float a) @ L224

  • 方法名:getViewYRot
  • 源码定位:L224
  • 返回类型:float
  • 修饰符:public

参数:

  • a: float

说明:

TODO

public void tick() @ L229

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

参数:

说明:

TODO

public float getCurrentMood() @ L256

  • 方法名:getCurrentMood
  • 源码定位:L256
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

private void sendPosition() @ L266

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

参数:

说明:

TODO

private void sendIsSprintingIfNeeded() @ L306

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

参数:

说明:

TODO

public boolean drop(boolean all) @ L317

  • 方法名:drop
  • 源码定位:L317
  • 返回类型:boolean
  • 修饰符:public

参数:

  • all: boolean

说明:

TODO

public void swing(InteractionHand hand) @ L326

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

参数:

  • hand: InteractionHand

说明:

TODO

public void respawn() @ L332

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

参数:

说明:

TODO

public void closeContainer() @ L337

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

参数:

说明:

TODO

public void clientSideCloseContainer() @ L343

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

参数:

说明:

TODO

public void hurtTo(float newHealth) @ L348

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

参数:

  • newHealth: float

说明:

TODO

public void onUpdateAbilities() @ L369

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

参数:

说明:

TODO

public void setReducedDebugInfo(boolean reducedDebugInfo) @ L374

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

参数:

  • reducedDebugInfo: boolean

说明:

TODO

public boolean isLocalPlayer() @ L380

  • 方法名:isLocalPlayer
  • 源码定位:L380
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean isSuppressingSlidingDownLadder() @ L385

  • 方法名:isSuppressingSlidingDownLadder
  • 源码定位:L385
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean canSpawnSprintParticle() @ L390

  • 方法名:canSpawnSprintParticle
  • 源码定位:L390
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

protected void sendRidingJump() @ L395

  • 方法名:sendRidingJump
  • 源码定位:L395
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

public void sendOpenInventory() @ L402

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

参数:

说明:

TODO

public StatsCounter getStats() @ L406

  • 方法名:getStats
  • 源码定位:L406
  • 返回类型:StatsCounter
  • 修饰符:public

参数:

说明:

TODO

public ClientRecipeBook getRecipeBook() @ L410

  • 方法名:getRecipeBook
  • 源码定位:L410
  • 返回类型:ClientRecipeBook
  • 修饰符:public

参数:

说明:

TODO

public void removeRecipeHighlight(RecipeDisplayId recipe) @ L414

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

参数:

  • recipe: RecipeDisplayId

说明:

TODO

public PermissionSet permissions() @ L421

  • 方法名:permissions
  • 源码定位:L421
  • 返回类型:PermissionSet
  • 修饰符:public

参数:

说明:

TODO

public void setPermissions(PermissionSet newPermissions) @ L426

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

参数:

  • newPermissions: PermissionSet

说明:

TODO

public ChatAbilities chatAbilities() @ L435

  • 方法名:chatAbilities
  • 源码定位:L435
  • 返回类型:ChatAbilities
  • 修饰符:public

参数:

说明:

TODO

public void refreshChatAbilities() @ L439

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

参数:

说明:

TODO

public void sendSystemMessage(Component message) @ L444

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

参数:

  • message: Component

说明:

TODO

public void sendOverlayMessage(Component message) @ L449

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

参数:

  • message: Component

说明:

TODO

private void moveTowardsClosestSpace(double x, double z) @ L454

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

参数:

  • x: double
  • z: double

说明:

TODO

private boolean suffocatesAt(BlockPos pos) @ L483

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

参数:

  • pos: BlockPos

说明:

TODO

public void setExperienceValues(float experienceProgress, int totalExp, int experienceLevel) @ L489

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

参数:

  • experienceProgress: float
  • totalExp: int
  • experienceLevel: int

说明:

TODO

private void setExperienceDisplayStartTickToTickCount() @ L499

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

参数:

说明:

TODO

public void handleEntityEvent(byte id) @ L507

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

参数:

  • id: byte

说明:

TODO

public void setShowDeathScreen(boolean show) @ L530

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

参数:

  • show: boolean

说明:

TODO

public boolean shouldShowDeathScreen() @ L534

  • 方法名:shouldShowDeathScreen
  • 源码定位:L534
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void setDoLimitedCrafting(boolean value) @ L538

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

参数:

  • value: boolean

说明:

TODO

public boolean getDoLimitedCrafting() @ L542

  • 方法名:getDoLimitedCrafting
  • 源码定位:L542
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void playSound(SoundEvent sound, float volume, float pitch) @ L546

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

参数:

  • sound: SoundEvent
  • volume: float
  • pitch: float

说明:

TODO

public void startUsingItem(InteractionHand hand) @ L551

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

参数:

  • hand: InteractionHand

说明:

TODO

public boolean isUsingItem() @ L561

  • 方法名:isUsingItem
  • 源码定位:L561
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

private boolean isSlowDueToUsingItem() @ L566

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

参数:

说明:

TODO

private float itemUseSpeedMultiplier() @ L570

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

参数:

说明:

TODO

public void stopUsingItem() @ L574

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

参数:

说明:

TODO

public InteractionHand getUsedItemHand() @ L580

  • 方法名:getUsedItemHand
  • 源码定位:L580
  • 返回类型:InteractionHand
  • 修饰符:public

参数:

说明:

TODO

public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) @ L585

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

参数:

  • accessor: EntityDataAccessor<?>

说明:

TODO

public PlayerRideableJumping jumpableVehicle() @ L603

  • 方法名:jumpableVehicle
  • 源码定位:L603
  • 返回类型:PlayerRideableJumping
  • 修饰符:public

参数:

说明:

TODO

public float getJumpRidingScale() @ L609

  • 方法名:getJumpRidingScale
  • 源码定位:L609
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

public boolean isTextFilteringEnabled() @ L613

  • 方法名:isTextFilteringEnabled
  • 源码定位:L613
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void openTextEdit(SignBlockEntity sign, boolean isFrontText) @ L618

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

参数:

  • sign: SignBlockEntity
  • isFrontText: boolean

说明:

TODO

public void openMinecartCommandBlock(MinecartCommandBlock commandBlock) @ L627

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

参数:

  • commandBlock: MinecartCommandBlock

说明:

TODO

public void openCommandBlock(CommandBlockEntity commandBlock) @ L632

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

参数:

  • commandBlock: CommandBlockEntity

说明:

TODO

public void openStructureBlock(StructureBlockEntity structureBlock) @ L637

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

参数:

  • structureBlock: StructureBlockEntity

说明:

TODO

public void openTestBlock(TestBlockEntity testBlock) @ L642

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

参数:

  • testBlock: TestBlockEntity

说明:

TODO

public void openTestInstanceBlock(TestInstanceBlockEntity testInstanceBlock) @ L647

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

参数:

  • testInstanceBlock: TestInstanceBlockEntity

说明:

TODO

public void openJigsawBlock(JigsawBlockEntity jigsawBlock) @ L652

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

参数:

  • jigsawBlock: JigsawBlockEntity

说明:

TODO

public void openDialog(Holder<Dialog> dialog) @ L657

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

参数:

  • dialog: Holder

说明:

TODO

public void openItemGui(ItemStack itemStack, InteractionHand hand) @ L662

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

参数:

  • itemStack: ItemStack
  • hand: InteractionHand

说明:

TODO

public void crit(Entity entity) @ L670

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

参数:

  • entity: Entity

说明:

TODO

public void magicCrit(Entity entity) @ L675

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

参数:

  • entity: Entity

说明:

TODO

public boolean isShiftKeyDown() @ L680

  • 方法名:isShiftKeyDown
  • 源码定位:L680
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean isCrouching() @ L685

  • 方法名:isCrouching
  • 源码定位:L685
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean isMovingSlowly() @ L690

  • 方法名:isMovingSlowly
  • 源码定位:L690
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void applyInput() @ L694

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

参数:

说明:

TODO

private Vec2 modifyInput(Vec2 input) @ L710

  • 方法名:modifyInput
  • 源码定位:L710
  • 返回类型:Vec2
  • 修饰符:private

参数:

  • input: Vec2

说明:

TODO

private static Vec2 modifyInputSpeedForSquareMovement(Vec2 input) @ L728

  • 方法名:modifyInputSpeedForSquareMovement
  • 源码定位:L728
  • 返回类型:Vec2
  • 修饰符:private static

参数:

  • input: Vec2

说明:

TODO

private static float distanceToUnitSquare(Vec2 direction) @ L740

  • 方法名:distanceToUnitSquare
  • 源码定位:L740
  • 返回类型:float
  • 修饰符:private static

参数:

  • direction: Vec2

说明:

TODO

protected boolean isControlledCamera() @ L747

  • 方法名:isControlledCamera
  • 源码定位:L747
  • 返回类型:boolean
  • 修饰符:protected

参数:

说明:

TODO

public void resetPos() @ L751

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

参数:

说明:

TODO

public void aiStep() @ L769

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

参数:

说明:

TODO

private boolean shouldStopRunSprinting() @ L924

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

参数:

说明:

TODO

private boolean shouldStopSwimSprinting() @ L930

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

参数:

说明:

TODO

public Portal.Transition getActivePortalLocalTransition() @ L934

  • 方法名:getActivePortalLocalTransition
  • 源码定位:L934
  • 返回类型:Portal.Transition
  • 修饰符:public

参数:

说明:

TODO

protected void tickDeath() @ L938

  • 方法名:tickDeath
  • 源码定位:L938
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

private void handlePortalTransitionEffect(boolean active) @ L946

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

参数:

  • active: boolean

说明:

TODO

public void rideTick() @ L973

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

参数:

说明:

TODO

public boolean isHandsBusy() @ L984

  • 方法名:isHandsBusy
  • 源码定位:L984
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void move(MoverType moverType, Vec3 delta) @ L988

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

参数:

  • moverType: MoverType
  • delta: Vec3

说明:

TODO

public boolean isAutoJumpEnabled() @ L999

  • 方法名:isAutoJumpEnabled
  • 源码定位:L999
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean shouldRotateWithMinecart() @ L1003

  • 方法名:shouldRotateWithMinecart
  • 源码定位:L1003
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

protected void updateAutoJump(float xa, float za) @ L1008

  • 方法名:updateAutoJump
  • 源码定位:L1008
  • 返回类型:void
  • 修饰符:protected

参数:

  • xa: float
  • za: float

说明:

TODO

protected boolean isHorizontalCollisionMinor(Vec3 movement) @ L1105

  • 方法名:isHorizontalCollisionMinor
  • 源码定位:L1105
  • 返回类型:boolean
  • 修饰符:protected

参数:

  • movement: Vec3

说明:

TODO

private boolean canAutoJump() @ L1123

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

参数:

说明:

TODO

private boolean isMoving() @ L1133

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

参数:

说明:

TODO

private boolean isSprintingPossible(boolean allowedInShallowWater) @ L1137

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

参数:

  • allowedInShallowWater: boolean

说明:

TODO

private boolean canStartSprinting() @ L1143

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

参数:

说明:

TODO

private boolean vehicleCanSprint(Entity vehicle) @ L1152

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

参数:

  • vehicle: Entity

说明:

TODO

public float getWaterVision() @ L1156

  • 方法名:getWaterVision
  • 源码定位:L1156
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

public void onGameModeChanged(GameType gameType) @ L1172

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

参数:

  • gameType: GameType

说明:

TODO

public boolean isUnderWater() @ L1178

  • 方法名:isUnderWater
  • 源码定位:L1178
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

protected boolean updateIsUnderwater() @ L1183

  • 方法名:updateIsUnderwater
  • 源码定位:L1183
  • 返回类型:boolean
  • 修饰符:protected

参数:

说明:

TODO

public Vec3 getRopeHoldPosition(float partialTickTime) @ L1204

  • 方法名:getRopeHoldPosition
  • 源码定位:L1204
  • 返回类型:Vec3
  • 修饰符:public

参数:

  • partialTickTime: float

说明:

TODO

public void updateTutorialInventoryAction(ItemStack itemCarried, ItemStack itemInSlot, ClickAction clickAction) @ L1217

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

参数:

  • itemCarried: ItemStack
  • itemInSlot: ItemStack
  • clickAction: ClickAction

说明:

TODO

public float getVisualRotationYInDegrees() @ L1222

  • 方法名:getVisualRotationYInDegrees
  • 源码定位:L1222
  • 返回类型:float
  • 修饰符:public

参数:

说明:

TODO

public void handleCreativeModeItemDrop(ItemStack stack) @ L1227

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

参数:

  • stack: ItemStack

说明:

TODO

public boolean canDropItems() @ L1232

  • 方法名:canDropItems
  • 源码定位:L1232
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public TickThrottler getDropSpamThrottler() @ L1237

  • 方法名:getDropSpamThrottler
  • 源码定位:L1237
  • 返回类型:TickThrottler
  • 修饰符:public

参数:

说明:

TODO

public Input getLastSentInput() @ L1241

  • 方法名:getLastSentInput
  • 源码定位:L1241
  • 返回类型:Input
  • 修饰符:public

参数:

说明:

TODO

public HitResult raycastHitResult(float a, Entity cameraEntity) @ L1245

  • 方法名:raycastHitResult
  • 源码定位:L1245
  • 返回类型:HitResult
  • 修饰符:public

参数:

  • a: float
  • cameraEntity: Entity

说明:

TODO

private static HitResult pick(Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) @ L1265

  • 方法名:pick
  • 源码定位:L1265
  • 返回类型:HitResult
  • 修饰符:private static

参数:

  • cameraEntity: Entity
  • blockInteractionRange: double
  • entityInteractionRange: double
  • partialTicks: float

说明:

TODO

private static HitResult filterHitResult(HitResult hitResult, Vec3 from, double maxRange) @ L1286

  • 方法名:filterHitResult
  • 源码定位:L1286
  • 返回类型:HitResult
  • 修饰符:private static

参数:

  • hitResult: HitResult
  • from: Vec3
  • maxRange: double

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class LocalPlayer extends AbstractClientPlayer {
    public static final Logger LOGGER = LogUtils.getLogger();
    private static final int POSITION_REMINDER_INTERVAL = 20;
    private static final int WATER_VISION_MAX_TIME = 600;
    private static final int WATER_VISION_QUICK_TIME = 100;
    private static final float WATER_VISION_QUICK_PERCENT = 0.6F;
    private static final double SUFFOCATING_COLLISION_CHECK_SCALE = 0.35;
    private static final double MINOR_COLLISION_ANGLE_THRESHOLD_RADIAN = 0.13962634F;
    public final ClientPacketListener connection;
    private final StatsCounter stats;
    private final ClientRecipeBook recipeBook;
    private final TickThrottler dropSpamThrottler = new TickThrottler(20, 1280);
    private final List<AmbientSoundHandler> ambientSoundHandlers = Lists.newArrayList();
    private PermissionSet permissions = PermissionSet.NO_PERMISSIONS;
    private ChatAbilities chatAbilities;
    private double xLast;
    private double yLast;
    private double zLast;
    private float yRotLast;
    private float xRotLast;
    private boolean lastOnGround;
    private boolean lastHorizontalCollision;
    private boolean crouching;
    private boolean wasSprinting;
    private int positionReminder;
    private boolean flashOnSetHealth;
    public ClientInput input = new ClientInput();
    private Input lastSentInput;
    protected final Minecraft minecraft;
    protected int sprintTriggerTime;
    private static final int EXPERIENCE_DISPLAY_UNREADY_TO_SET = Integer.MIN_VALUE;
    private static final int EXPERIENCE_DISPLAY_READY_TO_SET = -2147483647;
    public int experienceDisplayStartTick = Integer.MIN_VALUE;
    public float yBob;
    public float xBob;
    public float yBobO;
    public float xBobO;
    private int jumpRidingTicks;
    private float jumpRidingScale;
    public float portalEffectIntensity;
    public float oPortalEffectIntensity;
    private boolean startedUsingItem;
    private @Nullable InteractionHand usingItemHand;
    private boolean handsBusy;
    private boolean autoJumpEnabled = true;
    private int autoJumpTime;
    private boolean wasFallFlying;
    private int waterVisionTime;
    private boolean showDeathScreen = true;
    private boolean doLimitedCrafting = false;
 
    public LocalPlayer(
        Minecraft minecraft,
        ClientLevel level,
        ClientPacketListener connection,
        StatsCounter stats,
        ClientRecipeBook recipeBook,
        Input lastSentInput,
        boolean wasSprinting,
        ChatAbilities chatAbilities
    ) {
        super(level, connection.getLocalGameProfile());
        this.minecraft = minecraft;
        this.connection = connection;
        this.stats = stats;
        this.recipeBook = recipeBook;
        this.lastSentInput = lastSentInput;
        this.wasSprinting = wasSprinting;
        this.ambientSoundHandlers.add(new UnderwaterAmbientSoundHandler(this, minecraft.getSoundManager()));
        this.ambientSoundHandlers.add(new BubbleColumnAmbientSoundHandler(this));
        this.ambientSoundHandlers.add(new BiomeAmbientSoundsHandler(this, minecraft.getSoundManager()));
        this.chatAbilities = chatAbilities;
    }
 
    @Override
    public void heal(float heal) {
    }
 
    @Override
    public boolean startRiding(Entity entity, boolean force, boolean sendEventAndTriggers) {
        if (!super.startRiding(entity, force, sendEventAndTriggers)) {
            return false;
        } else {
            if (entity instanceof AbstractMinecart minecart) {
                this.minecraft
                    .getSoundManager()
                    .play(new RidingMinecartSoundInstance(this, minecart, true, SoundEvents.MINECART_INSIDE_UNDERWATER, 0.0F, 0.75F, 1.0F));
                this.minecraft.getSoundManager().play(new RidingMinecartSoundInstance(this, minecart, false, SoundEvents.MINECART_INSIDE, 0.0F, 0.75F, 1.0F));
            } else if (entity instanceof HappyGhast happyGhast) {
                this.minecraft
                    .getSoundManager()
                    .play(new RidingEntitySoundInstance(this, happyGhast, false, SoundEvents.HAPPY_GHAST_RIDING, happyGhast.getSoundSource(), 0.0F, 1.0F, 5.0F));
            } else if (entity instanceof AbstractNautilus nautilus) {
                this.minecraft
                    .getSoundManager()
                    .play(new RidingEntitySoundInstance(this, nautilus, true, SoundEvents.NAUTILUS_RIDING, nautilus.getSoundSource(), 0.0F, 1.0F, 5.0F));
            }
 
            return true;
        }
    }
 
    @Override
    public void removeVehicle() {
        super.removeVehicle();
        this.handsBusy = false;
    }
 
    @Override
    public float getViewXRot(float a) {
        return this.getXRot();
    }
 
    @Override
    public float getViewYRot(float a) {
        return this.isPassenger() ? super.getViewYRot(a) : this.getYRot();
    }
 
    @Override
    public void tick() {
        if (this.connection.hasClientLoaded()) {
            this.dropSpamThrottler.tick();
            super.tick();
            if (!this.lastSentInput.equals(this.input.keyPresses)) {
                this.connection.send(new ServerboundPlayerInputPacket(this.input.keyPresses));
                this.lastSentInput = this.input.keyPresses;
            }
 
            if (this.isPassenger()) {
                this.connection.send(new ServerboundMovePlayerPacket.Rot(this.getYRot(), this.getXRot(), this.onGround(), this.horizontalCollision));
                Entity vehicle = this.getRootVehicle();
                if (vehicle != this && vehicle.isLocalInstanceAuthoritative()) {
                    this.connection.send(ServerboundMoveVehiclePacket.fromEntity(vehicle));
                    this.sendIsSprintingIfNeeded();
                }
            } else {
                this.sendPosition();
            }
 
            for (AmbientSoundHandler soundHandler : this.ambientSoundHandlers) {
                soundHandler.tick();
            }
        }
    }
 
    public float getCurrentMood() {
        for (AmbientSoundHandler ambientSoundHandler : this.ambientSoundHandlers) {
            if (ambientSoundHandler instanceof BiomeAmbientSoundsHandler) {
                return ((BiomeAmbientSoundsHandler)ambientSoundHandler).getMoodiness();
            }
        }
 
        return 0.0F;
    }
 
    private void sendPosition() {
        this.sendIsSprintingIfNeeded();
        if (this.isControlledCamera()) {
            double deltaX = this.getX() - this.xLast;
            double deltaY = this.getY() - this.yLast;
            double deltaZ = this.getZ() - this.zLast;
            double deltaYRot = this.getYRot() - this.yRotLast;
            double deltaXRot = this.getXRot() - this.xRotLast;
            this.positionReminder++;
            boolean move = Mth.lengthSquared(deltaX, deltaY, deltaZ) > Mth.square(2.0E-4) || this.positionReminder >= 20;
            boolean rot = deltaYRot != 0.0 || deltaXRot != 0.0;
            if (move && rot) {
                this.connection
                    .send(new ServerboundMovePlayerPacket.PosRot(this.position(), this.getYRot(), this.getXRot(), this.onGround(), this.horizontalCollision));
            } else if (move) {
                this.connection.send(new ServerboundMovePlayerPacket.Pos(this.position(), this.onGround(), this.horizontalCollision));
            } else if (rot) {
                this.connection.send(new ServerboundMovePlayerPacket.Rot(this.getYRot(), this.getXRot(), this.onGround(), this.horizontalCollision));
            } else if (this.lastOnGround != this.onGround() || this.lastHorizontalCollision != this.horizontalCollision) {
                this.connection.send(new ServerboundMovePlayerPacket.StatusOnly(this.onGround(), this.horizontalCollision));
            }
 
            if (move) {
                this.xLast = this.getX();
                this.yLast = this.getY();
                this.zLast = this.getZ();
                this.positionReminder = 0;
            }
 
            if (rot) {
                this.yRotLast = this.getYRot();
                this.xRotLast = this.getXRot();
            }
 
            this.lastOnGround = this.onGround();
            this.lastHorizontalCollision = this.horizontalCollision;
            this.autoJumpEnabled = this.minecraft.options.autoJump().get();
        }
    }
 
    private void sendIsSprintingIfNeeded() {
        boolean isSprinting = this.isSprinting();
        if (isSprinting != this.wasSprinting) {
            ServerboundPlayerCommandPacket.Action action = isSprinting
                ? ServerboundPlayerCommandPacket.Action.START_SPRINTING
                : ServerboundPlayerCommandPacket.Action.STOP_SPRINTING;
            this.connection.send(new ServerboundPlayerCommandPacket(this, action));
            this.wasSprinting = isSprinting;
        }
    }
 
    public boolean drop(boolean all) {
        ServerboundPlayerActionPacket.Action action = all
            ? ServerboundPlayerActionPacket.Action.DROP_ALL_ITEMS
            : ServerboundPlayerActionPacket.Action.DROP_ITEM;
        ItemStack prediction = this.getInventory().removeFromSelected(all);
        this.connection.send(new ServerboundPlayerActionPacket(action, BlockPos.ZERO, Direction.DOWN));
        return !prediction.isEmpty();
    }
 
    @Override
    public void swing(InteractionHand hand) {
        super.swing(hand);
        this.connection.send(new ServerboundSwingPacket(hand));
    }
 
    public void respawn() {
        this.connection.send(new ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.PERFORM_RESPAWN));
        KeyMapping.resetToggleKeys();
    }
 
    @Override
    public void closeContainer() {
        this.connection.send(new ServerboundContainerClosePacket(this.containerMenu.containerId));
        this.clientSideCloseContainer();
    }
 
    public void clientSideCloseContainer() {
        super.closeContainer();
        this.minecraft.setScreen(null);
    }
 
    public void hurtTo(float newHealth) {
        if (this.flashOnSetHealth) {
            float dmg = this.getHealth() - newHealth;
            if (dmg <= 0.0F) {
                this.setHealth(newHealth);
                if (dmg < 0.0F) {
                    this.invulnerableTime = 10;
                }
            } else {
                this.lastHurt = dmg;
                this.invulnerableTime = 20;
                this.setHealth(newHealth);
                this.hurtDuration = 10;
                this.hurtTime = this.hurtDuration;
            }
        } else {
            this.setHealth(newHealth);
            this.flashOnSetHealth = true;
        }
    }
 
    @Override
    public void onUpdateAbilities() {
        this.connection.send(new ServerboundPlayerAbilitiesPacket(this.getAbilities()));
    }
 
    @Override
    public void setReducedDebugInfo(boolean reducedDebugInfo) {
        super.setReducedDebugInfo(reducedDebugInfo);
        this.minecraft.debugEntries.rebuildCurrentList();
    }
 
    @Override
    public boolean isLocalPlayer() {
        return true;
    }
 
    @Override
    public boolean isSuppressingSlidingDownLadder() {
        return !this.getAbilities().flying && super.isSuppressingSlidingDownLadder();
    }
 
    @Override
    public boolean canSpawnSprintParticle() {
        return !this.getAbilities().flying && super.canSpawnSprintParticle();
    }
 
    protected void sendRidingJump() {
        this.connection
            .send(
                new ServerboundPlayerCommandPacket(this, ServerboundPlayerCommandPacket.Action.START_RIDING_JUMP, Mth.floor(this.getJumpRidingScale() * 100.0F))
            );
    }
 
    public void sendOpenInventory() {
        this.connection.send(new ServerboundPlayerCommandPacket(this, ServerboundPlayerCommandPacket.Action.OPEN_INVENTORY));
    }
 
    public StatsCounter getStats() {
        return this.stats;
    }
 
    public ClientRecipeBook getRecipeBook() {
        return this.recipeBook;
    }
 
    public void removeRecipeHighlight(RecipeDisplayId recipe) {
        if (this.recipeBook.willHighlight(recipe)) {
            this.recipeBook.removeHighlight(recipe);
            this.connection.send(new ServerboundRecipeBookSeenRecipePacket(recipe));
        }
    }
 
    @Override
    public PermissionSet permissions() {
        return this.permissions;
    }
 
    public void setPermissions(PermissionSet newPermissions) {
        boolean previousGamemasterPermission = this.permissions.hasPermission(Permissions.COMMANDS_GAMEMASTER);
        boolean newGamemasterPermission = newPermissions.hasPermission(Permissions.COMMANDS_GAMEMASTER);
        this.permissions = newPermissions;
        if (previousGamemasterPermission != newGamemasterPermission && this.minecraft.screen instanceof HasGamemasterPermissionReaction screen) {
            screen.onGamemasterPermissionChanged(newGamemasterPermission);
        }
    }
 
    public ChatAbilities chatAbilities() {
        return this.chatAbilities;
    }
 
    public void refreshChatAbilities() {
        this.chatAbilities = this.minecraft.computeChatAbilities();
        this.minecraft.gui.getChat().setVisibleMessageFilter(this.chatAbilities.visibleMessagesFilter());
    }
 
    @Override
    public void sendSystemMessage(Component message) {
        this.minecraft.getChatListener().handleSystemMessage(message, true);
    }
 
    @Override
    public void sendOverlayMessage(Component message) {
        this.minecraft.getChatListener().handleOverlay(message);
    }
 
    private void moveTowardsClosestSpace(double x, double z) {
        BlockPos pos = BlockPos.containing(x, this.getY(), z);
        if (this.suffocatesAt(pos)) {
            double xd = x - pos.getX();
            double zd = z - pos.getZ();
            Direction dir = null;
            double closest = Double.MAX_VALUE;
            Direction[] directions = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH};
 
            for (Direction direction : directions) {
                double axisDistance = direction.getAxis().choose(xd, 0.0, zd);
                double distanceToEdge = direction.getAxisDirection() == Direction.AxisDirection.POSITIVE ? 1.0 - axisDistance : axisDistance;
                if (distanceToEdge < closest && !this.suffocatesAt(pos.relative(direction))) {
                    closest = distanceToEdge;
                    dir = direction;
                }
            }
 
            if (dir != null) {
                Vec3 oldMovement = this.getDeltaMovement();
                if (dir.getAxis() == Direction.Axis.X) {
                    this.setDeltaMovement(0.1 * dir.getStepX(), oldMovement.y, oldMovement.z);
                } else {
                    this.setDeltaMovement(oldMovement.x, oldMovement.y, 0.1 * dir.getStepZ());
                }
            }
        }
    }
 
    private boolean suffocatesAt(BlockPos pos) {
        AABB boundingBox = this.getBoundingBox();
        AABB testArea = new AABB(pos.getX(), boundingBox.minY, pos.getZ(), pos.getX() + 1.0, boundingBox.maxY, pos.getZ() + 1.0).deflate(1.0E-7);
        return this.level().collidesWithSuffocatingBlock(this, testArea);
    }
 
    public void setExperienceValues(float experienceProgress, int totalExp, int experienceLevel) {
        if (experienceProgress != this.experienceProgress) {
            this.setExperienceDisplayStartTickToTickCount();
        }
 
        this.experienceProgress = experienceProgress;
        this.totalExperience = totalExp;
        this.experienceLevel = experienceLevel;
    }
 
    private void setExperienceDisplayStartTickToTickCount() {
        if (this.experienceDisplayStartTick == Integer.MIN_VALUE) {
            this.experienceDisplayStartTick = -2147483647;
        } else {
            this.experienceDisplayStartTick = this.tickCount;
        }
    }
 
    @Override
    public void handleEntityEvent(byte id) {
        switch (id) {
            case 24:
                this.setPermissions(PermissionSet.NO_PERMISSIONS);
                break;
            case 25:
                this.setPermissions(LevelBasedPermissionSet.MODERATOR);
                break;
            case 26:
                this.setPermissions(LevelBasedPermissionSet.GAMEMASTER);
                break;
            case 27:
                this.setPermissions(LevelBasedPermissionSet.ADMIN);
                break;
            case 28:
                this.setPermissions(LevelBasedPermissionSet.OWNER);
                break;
            default:
                super.handleEntityEvent(id);
        }
    }
 
    public void setShowDeathScreen(boolean show) {
        this.showDeathScreen = show;
    }
 
    public boolean shouldShowDeathScreen() {
        return this.showDeathScreen;
    }
 
    public void setDoLimitedCrafting(boolean value) {
        this.doLimitedCrafting = value;
    }
 
    public boolean getDoLimitedCrafting() {
        return this.doLimitedCrafting;
    }
 
    @Override
    public void playSound(SoundEvent sound, float volume, float pitch) {
        this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), volume, pitch, false);
    }
 
    @Override
    public void startUsingItem(InteractionHand hand) {
        ItemStack itemStack = this.getItemInHand(hand);
        if (!itemStack.isEmpty() && !this.isUsingItem()) {
            super.startUsingItem(hand);
            this.startedUsingItem = true;
            this.usingItemHand = hand;
        }
    }
 
    @Override
    public boolean isUsingItem() {
        return this.startedUsingItem;
    }
 
    private boolean isSlowDueToUsingItem() {
        return this.isUsingItem() && !this.useItem.getOrDefault(DataComponents.USE_EFFECTS, UseEffects.DEFAULT).canSprint();
    }
 
    private float itemUseSpeedMultiplier() {
        return this.useItem.getOrDefault(DataComponents.USE_EFFECTS, UseEffects.DEFAULT).speedMultiplier();
    }
 
    @Override
    public void stopUsingItem() {
        super.stopUsingItem();
        this.startedUsingItem = false;
    }
 
    @Override
    public InteractionHand getUsedItemHand() {
        return Objects.requireNonNullElse(this.usingItemHand, InteractionHand.MAIN_HAND);
    }
 
    @Override
    public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) {
        super.onSyncedDataUpdated(accessor);
        if (DATA_LIVING_ENTITY_FLAGS.equals(accessor)) {
            boolean serverUsingItem = (this.entityData.get(DATA_LIVING_ENTITY_FLAGS) & 1) > 0;
            InteractionHand serverUsingHand = (this.entityData.get(DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
            if (serverUsingItem && !this.startedUsingItem) {
                this.startUsingItem(serverUsingHand);
            } else if (!serverUsingItem && this.startedUsingItem) {
                this.stopUsingItem();
            }
        }
 
        if (DATA_SHARED_FLAGS_ID.equals(accessor) && this.isFallFlying() && !this.wasFallFlying) {
            this.minecraft.getSoundManager().play(new ElytraOnPlayerSoundInstance(this));
        }
    }
 
    public @Nullable PlayerRideableJumping jumpableVehicle() {
        return this.getControlledVehicle() instanceof PlayerRideableJumping playerRideableJumping && playerRideableJumping.canJump()
            ? playerRideableJumping
            : null;
    }
 
    public float getJumpRidingScale() {
        return this.jumpRidingScale;
    }
 
    @Override
    public boolean isTextFilteringEnabled() {
        return this.minecraft.isTextFilteringEnabled();
    }
 
    @Override
    public void openTextEdit(SignBlockEntity sign, boolean isFrontText) {
        if (sign instanceof HangingSignBlockEntity hangingSign) {
            this.minecraft.setScreen(new HangingSignEditScreen(hangingSign, isFrontText, this.minecraft.isTextFilteringEnabled()));
        } else {
            this.minecraft.setScreen(new SignEditScreen(sign, isFrontText, this.minecraft.isTextFilteringEnabled()));
        }
    }
 
    @Override
    public void openMinecartCommandBlock(MinecartCommandBlock commandBlock) {
        this.minecraft.setScreen(new MinecartCommandBlockEditScreen(commandBlock));
    }
 
    @Override
    public void openCommandBlock(CommandBlockEntity commandBlock) {
        this.minecraft.setScreen(new CommandBlockEditScreen(commandBlock));
    }
 
    @Override
    public void openStructureBlock(StructureBlockEntity structureBlock) {
        this.minecraft.setScreen(new StructureBlockEditScreen(structureBlock));
    }
 
    @Override
    public void openTestBlock(TestBlockEntity testBlock) {
        this.minecraft.setScreen(new TestBlockEditScreen(testBlock));
    }
 
    @Override
    public void openTestInstanceBlock(TestInstanceBlockEntity testInstanceBlock) {
        this.minecraft.setScreen(new TestInstanceBlockEditScreen(testInstanceBlock));
    }
 
    @Override
    public void openJigsawBlock(JigsawBlockEntity jigsawBlock) {
        this.minecraft.setScreen(new JigsawBlockEditScreen(jigsawBlock));
    }
 
    @Override
    public void openDialog(Holder<Dialog> dialog) {
        this.connection.showDialog(dialog, this.minecraft.screen);
    }
 
    @Override
    public void openItemGui(ItemStack itemStack, InteractionHand hand) {
        WritableBookContent content = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT);
        if (content != null) {
            this.minecraft.setScreen(new BookEditScreen(this, itemStack, hand, content));
        }
    }
 
    @Override
    public void crit(Entity entity) {
        this.minecraft.particleEngine.createTrackingEmitter(entity, ParticleTypes.CRIT);
    }
 
    @Override
    public void magicCrit(Entity entity) {
        this.minecraft.particleEngine.createTrackingEmitter(entity, ParticleTypes.ENCHANTED_HIT);
    }
 
    @Override
    public boolean isShiftKeyDown() {
        return this.input.keyPresses.shift();
    }
 
    @Override
    public boolean isCrouching() {
        return this.crouching;
    }
 
    public boolean isMovingSlowly() {
        return this.isCrouching() || this.isVisuallyCrawling();
    }
 
    @Override
    public void applyInput() {
        if (this.isControlledCamera()) {
            Vec2 modifiedInput = this.modifyInput(this.input.getMoveVector());
            this.xxa = modifiedInput.x;
            this.zza = modifiedInput.y;
            this.jumping = this.input.keyPresses.jump();
            this.yBobO = this.yBob;
            this.xBobO = this.xBob;
            this.xBob = this.xBob + (this.getXRot() - this.xBob) * 0.5F;
            this.yBob = this.yBob + (this.getYRot() - this.yBob) * 0.5F;
        } else {
            super.applyInput();
        }
    }
 
    private Vec2 modifyInput(Vec2 input) {
        if (input.lengthSquared() == 0.0F) {
            return input;
        } else {
            Vec2 newInput = input.scale(0.98F);
            if (this.isUsingItem() && !this.isPassenger()) {
                newInput = newInput.scale(this.itemUseSpeedMultiplier());
            }
 
            if (this.isMovingSlowly()) {
                float sneakingMovementFactor = (float)this.getAttributeValue(Attributes.SNEAKING_SPEED);
                newInput = newInput.scale(sneakingMovementFactor);
            }
 
            return modifyInputSpeedForSquareMovement(newInput);
        }
    }
 
    private static Vec2 modifyInputSpeedForSquareMovement(Vec2 input) {
        float length = input.length();
        if (length <= 0.0F) {
            return input;
        } else {
            Vec2 direction = input.scale(1.0F / length);
            float distanceToUnitSquare = distanceToUnitSquare(direction);
            float modifiedLength = Math.min(length * distanceToUnitSquare, 1.0F);
            return direction.scale(modifiedLength);
        }
    }
 
    private static float distanceToUnitSquare(Vec2 direction) {
        float directionX = Math.abs(direction.x);
        float directionY = Math.abs(direction.y);
        float tan = directionY > directionX ? directionX / directionY : directionY / directionX;
        return Mth.sqrt(1.0F + Mth.square(tan));
    }
 
    protected boolean isControlledCamera() {
        return this.minecraft.getCameraEntity() == this;
    }
 
    public void resetPos() {
        this.setPose(Pose.STANDING);
        if (this.level() != null) {
            for (double testY = this.getY(); testY > this.level().getMinY() && testY <= this.level().getMaxY(); testY++) {
                this.setPos(this.getX(), testY, this.getZ());
                if (this.level().noCollision(this)) {
                    break;
                }
            }
 
            this.setDeltaMovement(Vec3.ZERO);
            this.setXRot(0.0F);
        }
 
        this.setHealth(this.getMaxHealth());
        this.deathTime = 0;
    }
 
    @Override
    public void aiStep() {
        if (this.sprintTriggerTime > 0) {
            this.sprintTriggerTime--;
        }
 
        if (!(this.minecraft.screen instanceof LevelLoadingScreen)) {
            this.handlePortalTransitionEffect(this.getActivePortalLocalTransition() == Portal.Transition.CONFUSION);
            this.processPortalCooldown();
        }
 
        boolean wasJumping = this.input.keyPresses.jump();
        boolean wasShiftKeyDown = this.input.keyPresses.shift();
        boolean hasForwardImpulse = this.input.hasForwardImpulse();
        Abilities abilities = this.getAbilities();
        this.crouching = !abilities.flying
            && !this.isSwimming()
            && !this.isPassenger()
            && this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)
            && (this.isShiftKeyDown() || !this.isSleeping() && !this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.STANDING));
        this.input.tick();
        this.minecraft.getTutorial().onInput(this.input);
        boolean wasAutoJump = false;
        if (this.autoJumpTime > 0) {
            this.autoJumpTime--;
            wasAutoJump = true;
            this.input.makeJump();
        }
 
        if (!this.noPhysics) {
            this.moveTowardsClosestSpace(this.getX() - this.getBbWidth() * 0.35, this.getZ() + this.getBbWidth() * 0.35);
            this.moveTowardsClosestSpace(this.getX() - this.getBbWidth() * 0.35, this.getZ() - this.getBbWidth() * 0.35);
            this.moveTowardsClosestSpace(this.getX() + this.getBbWidth() * 0.35, this.getZ() - this.getBbWidth() * 0.35);
            this.moveTowardsClosestSpace(this.getX() + this.getBbWidth() * 0.35, this.getZ() + this.getBbWidth() * 0.35);
        }
 
        if (wasShiftKeyDown || this.isSlowDueToUsingItem() && !this.isPassenger() || this.input.keyPresses.backward()) {
            this.sprintTriggerTime = 0;
        }
 
        if (this.canStartSprinting()) {
            if (!hasForwardImpulse) {
                if (this.sprintTriggerTime > 0) {
                    this.setSprinting(true);
                } else {
                    this.sprintTriggerTime = this.minecraft.options.sprintWindow().get();
                }
            }
 
            if (this.input.keyPresses.sprint()) {
                this.setSprinting(true);
            }
        }
 
        if (this.isSprinting()) {
            if (this.isSwimming()) {
                if (this.shouldStopSwimSprinting()) {
                    this.setSprinting(false);
                }
            } else if (this.shouldStopRunSprinting()) {
                this.setSprinting(false);
            }
        }
 
        boolean justToggledCreativeFlight = false;
        if (abilities.mayfly) {
            if (this.minecraft.gameMode.isSpectator()) {
                if (!abilities.flying) {
                    abilities.flying = true;
                    justToggledCreativeFlight = true;
                    this.onUpdateAbilities();
                }
            } else if (!wasJumping && this.input.keyPresses.jump() && !wasAutoJump) {
                if (this.jumpTriggerTime == 0) {
                    this.jumpTriggerTime = 7;
                } else if (!this.isSwimming() && (this.getVehicle() == null || this.jumpableVehicle() != null)) {
                    abilities.flying = !abilities.flying;
                    if (abilities.flying && this.onGround()) {
                        this.jumpFromGround();
                    }
 
                    justToggledCreativeFlight = true;
                    this.onUpdateAbilities();
                    this.jumpTriggerTime = 0;
                }
            }
        }
 
        if (this.input.keyPresses.jump() && !justToggledCreativeFlight && !wasJumping && !this.onClimbable() && this.tryToStartFallFlying()) {
            this.connection.send(new ServerboundPlayerCommandPacket(this, ServerboundPlayerCommandPacket.Action.START_FALL_FLYING));
        }
 
        this.wasFallFlying = this.isFallFlying();
        if (this.isInWater() && this.input.keyPresses.shift() && this.isAffectedByFluids()) {
            this.goDownInWater();
        }
 
        if (this.isEyeInFluid(FluidTags.WATER)) {
            int speed = this.isSpectator() ? 10 : 1;
            this.waterVisionTime = Mth.clamp(this.waterVisionTime + speed, 0, 600);
        } else if (this.waterVisionTime > 0) {
            this.isEyeInFluid(FluidTags.WATER);
            this.waterVisionTime = Mth.clamp(this.waterVisionTime - 10, 0, 600);
        }
 
        if (abilities.flying && this.isControlledCamera()) {
            int inputYa = 0;
            if (this.input.keyPresses.shift()) {
                inputYa--;
            }
 
            if (this.input.keyPresses.jump()) {
                inputYa++;
            }
 
            if (inputYa != 0) {
                this.setDeltaMovement(this.getDeltaMovement().add(0.0, inputYa * abilities.getFlyingSpeed() * 3.0F, 0.0));
            }
        }
 
        PlayerRideableJumping jumpableVehicle = this.jumpableVehicle();
        if (jumpableVehicle != null && jumpableVehicle.getJumpCooldown() == 0) {
            if (this.jumpRidingTicks < 0) {
                this.jumpRidingTicks++;
                if (this.jumpRidingTicks == 0) {
                    this.jumpRidingScale = 0.0F;
                }
            }
 
            if (wasJumping && !this.input.keyPresses.jump()) {
                this.jumpRidingTicks = -10;
                jumpableVehicle.onPlayerJump(Mth.floor(this.getJumpRidingScale() * 100.0F));
                this.sendRidingJump();
            } else if (!wasJumping && this.input.keyPresses.jump()) {
                this.jumpRidingTicks = 0;
                this.jumpRidingScale = 0.0F;
            } else if (wasJumping) {
                this.jumpRidingTicks++;
                if (this.jumpRidingTicks < 10) {
                    this.jumpRidingScale = this.jumpRidingTicks * 0.1F;
                } else {
                    this.jumpRidingScale = 0.8F + 2.0F / (this.jumpRidingTicks - 9) * 0.1F;
                }
            }
        } else {
            this.jumpRidingScale = 0.0F;
        }
 
        super.aiStep();
        if (this.onGround() && abilities.flying && !this.minecraft.gameMode.isSpectator()) {
            abilities.flying = false;
            this.onUpdateAbilities();
        }
    }
 
    private boolean shouldStopRunSprinting() {
        return !this.isSprintingPossible(this.getAbilities().flying)
            || !this.input.hasForwardImpulse()
            || this.horizontalCollision && !this.minorHorizontalCollision;
    }
 
    private boolean shouldStopSwimSprinting() {
        return !this.isSprintingPossible(true) || !this.isInWater() || !this.input.hasForwardImpulse() && !this.onGround() && !this.input.keyPresses.shift();
    }
 
    public Portal.Transition getActivePortalLocalTransition() {
        return this.portalProcess == null ? Portal.Transition.NONE : this.portalProcess.getPortalLocalTransition();
    }
 
    @Override
    protected void tickDeath() {
        this.deathTime++;
        if (this.deathTime == 20) {
            this.remove(Entity.RemovalReason.KILLED);
        }
    }
 
    private void handlePortalTransitionEffect(boolean active) {
        this.oPortalEffectIntensity = this.portalEffectIntensity;
        float step = 0.0F;
        if (active && this.portalProcess != null && this.portalProcess.isInsidePortalThisTick()) {
            if (this.minecraft.screen != null && !this.minecraft.screen.isAllowedInPortal()) {
                if (this.minecraft.screen instanceof AbstractContainerScreen) {
                    this.closeContainer();
                }
 
                this.minecraft.setScreen(null);
            }
 
            if (this.portalEffectIntensity == 0.0F) {
                this.minecraft
                    .getSoundManager()
                    .play(SimpleSoundInstance.forLocalAmbience(SoundEvents.PORTAL_TRIGGER, this.random.nextFloat() * 0.4F + 0.8F, 0.25F));
            }
 
            step = 0.0125F;
            this.portalProcess.setAsInsidePortalThisTick(false);
        } else if (this.portalEffectIntensity > 0.0F) {
            step = -0.05F;
        }
 
        this.portalEffectIntensity = Mth.clamp(this.portalEffectIntensity + step, 0.0F, 1.0F);
    }
 
    @Override
    public void rideTick() {
        super.rideTick();
        this.handsBusy = false;
        if (this.getControlledVehicle() instanceof AbstractBoat boat) {
            boat.setInput(this.input.keyPresses.left(), this.input.keyPresses.right(), this.input.keyPresses.forward(), this.input.keyPresses.backward());
            this.handsBusy = this.handsBusy
                | (this.input.keyPresses.left() || this.input.keyPresses.right() || this.input.keyPresses.forward() || this.input.keyPresses.backward());
        }
    }
 
    public boolean isHandsBusy() {
        return this.handsBusy;
    }
 
    @Override
    public void move(MoverType moverType, Vec3 delta) {
        double prevX = this.getX();
        double prevZ = this.getZ();
        super.move(moverType, delta);
        float deltaX = (float)(this.getX() - prevX);
        float deltaZ = (float)(this.getZ() - prevZ);
        this.updateAutoJump(deltaX, deltaZ);
        this.addWalkedDistance(Mth.length(deltaX, deltaZ) * 0.6F);
    }
 
    public boolean isAutoJumpEnabled() {
        return this.autoJumpEnabled;
    }
 
    @Override
    public boolean shouldRotateWithMinecart() {
        return this.minecraft.options.rotateWithMinecart().get();
    }
 
    protected void updateAutoJump(float xa, float za) {
        if (this.canAutoJump()) {
            Vec3 moveBegin = this.position();
            Vec3 moveEnd = moveBegin.add(xa, 0.0, za);
            Vec3 moveDiff = new Vec3(xa, 0.0, za);
            float currentSpeed = this.getSpeed();
            float moveDistSq = (float)moveDiff.lengthSqr();
            if (moveDistSq <= 0.001F) {
                Vec2 move = this.input.getMoveVector();
                float inputXa = currentSpeed * move.x;
                float inputZa = currentSpeed * move.y;
                float sin = Mth.sin(this.getYRot() * (float) (Math.PI / 180.0));
                float cos = Mth.cos(this.getYRot() * (float) (Math.PI / 180.0));
                moveDiff = new Vec3(inputXa * cos - inputZa * sin, moveDiff.y, inputZa * cos + inputXa * sin);
                moveDistSq = (float)moveDiff.lengthSqr();
                if (moveDistSq <= 0.001F) {
                    return;
                }
            }
 
            float moveDistInverted = Mth.invSqrt(moveDistSq);
            Vec3 moveDir = moveDiff.scale(moveDistInverted);
            Vec3 facingDir3 = this.getForward();
            float facingVsMovingDotProduct2 = (float)(facingDir3.x * moveDir.x + facingDir3.z * moveDir.z);
            if (!(facingVsMovingDotProduct2 < -0.15F)) {
                CollisionContext context = CollisionContext.of(this);
                BlockPos ceilingPos = BlockPos.containing(this.getX(), this.getBoundingBox().maxY, this.getZ());
                BlockState aboveBlock1 = this.level().getBlockState(ceilingPos);
                if (aboveBlock1.getCollisionShape(this.level(), ceilingPos, context).isEmpty()) {
                    ceilingPos = ceilingPos.above();
                    BlockState aboveBlock2 = this.level().getBlockState(ceilingPos);
                    if (aboveBlock2.getCollisionShape(this.level(), ceilingPos, context).isEmpty()) {
                        float lookAheadSteps = 7.0F;
                        float jumpHeight = 1.2F;
                        if (this.hasEffect(MobEffects.JUMP_BOOST)) {
                            jumpHeight += (this.getEffect(MobEffects.JUMP_BOOST).getAmplifier() + 1) * 0.75F;
                        }
 
                        float lookAheadDist = Math.max(currentSpeed * 7.0F, 1.0F / moveDistInverted);
                        Vec3 segEnd = moveEnd.add(moveDir.scale(lookAheadDist));
                        float playerWidth = this.getBbWidth();
                        float playerHeight = this.getBbHeight();
                        AABB testBox = new AABB(moveBegin, segEnd.add(0.0, playerHeight, 0.0)).inflate(playerWidth, 0.0, playerWidth);
                        Vec3 segBegin = moveBegin.add(0.0, 0.51F, 0.0);
                        segEnd = segEnd.add(0.0, 0.51F, 0.0);
                        Vec3 rightDir = moveDir.cross(new Vec3(0.0, 1.0, 0.0));
                        Vec3 rightOffset = rightDir.scale(playerWidth * 0.5F);
                        Vec3 leftSegBegin = segBegin.subtract(rightOffset);
                        Vec3 leftSegEnd = segEnd.subtract(rightOffset);
                        Vec3 rightSegBegin = segBegin.add(rightOffset);
                        Vec3 rightSegEnd = segEnd.add(rightOffset);
                        Iterable<VoxelShape> collisions = this.level().getCollisions(this, testBox);
                        Iterator<AABB> shape = StreamSupport.stream(collisions.spliterator(), false).flatMap(s -> s.toAabbs().stream()).iterator();
                        float obstacleHeight = Float.MIN_VALUE;
 
                        while (shape.hasNext()) {
                            AABB box = shape.next();
                            if (box.intersects(leftSegBegin, leftSegEnd) || box.intersects(rightSegBegin, rightSegEnd)) {
                                obstacleHeight = (float)box.maxY;
                                Vec3 obstacleShapeCenter = box.getCenter();
                                BlockPos obstacleBlockPos = BlockPos.containing(obstacleShapeCenter);
 
                                for (int steps = 1; steps < jumpHeight; steps++) {
                                    BlockPos abovePos1 = obstacleBlockPos.above(steps);
                                    BlockState aboveBlock = this.level().getBlockState(abovePos1);
                                    VoxelShape blockShape;
                                    if (!(blockShape = aboveBlock.getCollisionShape(this.level(), abovePos1, context)).isEmpty()) {
                                        obstacleHeight = (float)blockShape.max(Direction.Axis.Y) + abovePos1.getY();
                                        if (obstacleHeight - this.getY() > jumpHeight) {
                                            return;
                                        }
                                    }
 
                                    if (steps > 1) {
                                        ceilingPos = ceilingPos.above();
                                        BlockState aboveBlock3 = this.level().getBlockState(ceilingPos);
                                        if (!aboveBlock3.getCollisionShape(this.level(), ceilingPos, context).isEmpty()) {
                                            return;
                                        }
                                    }
                                }
                                break;
                            }
                        }
 
                        if (obstacleHeight != Float.MIN_VALUE) {
                            float ydelta = (float)(obstacleHeight - this.getY());
                            if (!(ydelta <= 0.5F) && !(ydelta > jumpHeight)) {
                                this.autoJumpTime = 1;
                            }
                        }
                    }
                }
            }
        }
    }
 
    @Override
    protected boolean isHorizontalCollisionMinor(Vec3 movement) {
        float yRotInRadians = this.getYRot() * (float) (Math.PI / 180.0);
        double yRotSin = Mth.sin(yRotInRadians);
        double yRotCos = Mth.cos(yRotInRadians);
        double globalXA = this.xxa * yRotCos - this.zza * yRotSin;
        double globalZA = this.zza * yRotCos + this.xxa * yRotSin;
        double aLengthSquared = Mth.square(globalXA) + Mth.square(globalZA);
        double movementLengthSquared = Mth.square(movement.x) + Mth.square(movement.z);
        if (!(aLengthSquared < 1.0E-5F) && !(movementLengthSquared < 1.0E-5F)) {
            double dotProduct = globalXA * movement.x + globalZA * movement.z;
            double angleBetweenDesiredAndActualMovement = Math.acos(dotProduct / Math.sqrt(aLengthSquared * movementLengthSquared));
            return angleBetweenDesiredAndActualMovement < 0.13962634F;
        } else {
            return false;
        }
    }
 
    private boolean canAutoJump() {
        return this.isAutoJumpEnabled()
            && this.autoJumpTime <= 0
            && this.onGround()
            && !this.isStayingOnGroundSurface()
            && !this.isPassenger()
            && this.isMoving()
            && this.getBlockJumpFactor() >= 1.0;
    }
 
    private boolean isMoving() {
        return this.input.getMoveVector().lengthSquared() > 0.0F;
    }
 
    private boolean isSprintingPossible(boolean allowedInShallowWater) {
        return !this.isMobilityRestricted()
            && (this.isPassenger() ? this.vehicleCanSprint(this.getVehicle()) : this.hasEnoughFoodToDoExhaustiveManoeuvres())
            && (allowedInShallowWater || !this.isInShallowWater());
    }
 
    private boolean canStartSprinting() {
        return !this.isSprinting()
            && this.input.hasForwardImpulse()
            && this.isSprintingPossible(this.getAbilities().flying)
            && !this.isSlowDueToUsingItem()
            && (!this.isFallFlying() || this.isUnderWater())
            && (!this.isMovingSlowly() || this.isUnderWater());
    }
 
    private boolean vehicleCanSprint(Entity vehicle) {
        return vehicle.canSprint() && vehicle.isLocalInstanceAuthoritative();
    }
 
    public float getWaterVision() {
        if (!this.isEyeInFluid(FluidTags.WATER)) {
            return 0.0F;
        } else {
            float max = 600.0F;
            float mid = 100.0F;
            if (this.waterVisionTime >= 600.0F) {
                return 1.0F;
            } else {
                float a = Mth.clamp(this.waterVisionTime / 100.0F, 0.0F, 1.0F);
                float b = this.waterVisionTime < 100.0F ? 0.0F : Mth.clamp((this.waterVisionTime - 100.0F) / 500.0F, 0.0F, 1.0F);
                return a * 0.6F + b * 0.39999998F;
            }
        }
    }
 
    public void onGameModeChanged(GameType gameType) {
        if (gameType == GameType.SPECTATOR) {
            this.setDeltaMovement(this.getDeltaMovement().with(Direction.Axis.Y, 0.0));
        }
    }
 
    @Override
    public boolean isUnderWater() {
        return this.wasUnderwater;
    }
 
    @Override
    protected boolean updateIsUnderwater() {
        boolean oldIsUnderwater = this.wasUnderwater;
        boolean newIsUnderwater = super.updateIsUnderwater();
        if (this.isSpectator()) {
            return this.wasUnderwater;
        } else {
            if (!oldIsUnderwater && newIsUnderwater) {
                this.level()
                    .playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.AMBIENT_UNDERWATER_ENTER, SoundSource.AMBIENT, 1.0F, 1.0F, false);
                this.minecraft.getSoundManager().play(new UnderwaterAmbientSoundInstances.UnderwaterAmbientSoundInstance(this));
            }
 
            if (oldIsUnderwater && !newIsUnderwater) {
                this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.AMBIENT_UNDERWATER_EXIT, SoundSource.AMBIENT, 1.0F, 1.0F, false);
            }
 
            return this.wasUnderwater;
        }
    }
 
    @Override
    public Vec3 getRopeHoldPosition(float partialTickTime) {
        if (this.minecraft.options.getCameraType().isFirstPerson()) {
            float yRot = Mth.lerp(partialTickTime * 0.5F, this.getYRot(), this.yRotO) * (float) (Math.PI / 180.0);
            float xRot = Mth.lerp(partialTickTime * 0.5F, this.getXRot(), this.xRotO) * (float) (Math.PI / 180.0);
            double handDir = this.getMainArm() == HumanoidArm.RIGHT ? -1.0 : 1.0;
            Vec3 offset = new Vec3(0.39 * handDir, -0.6, 0.3);
            return offset.xRot(-xRot).yRot(-yRot).add(this.getEyePosition(partialTickTime));
        } else {
            return super.getRopeHoldPosition(partialTickTime);
        }
    }
 
    @Override
    public void updateTutorialInventoryAction(ItemStack itemCarried, ItemStack itemInSlot, ClickAction clickAction) {
        this.minecraft.getTutorial().onInventoryAction(itemCarried, itemInSlot, clickAction);
    }
 
    @Override
    public float getVisualRotationYInDegrees() {
        return this.getYRot();
    }
 
    @Override
    public void handleCreativeModeItemDrop(ItemStack stack) {
        this.minecraft.gameMode.handleCreativeModeItemDrop(stack);
    }
 
    @Override
    public boolean canDropItems() {
        return this.dropSpamThrottler.isUnderThreshold();
    }
 
    public TickThrottler getDropSpamThrottler() {
        return this.dropSpamThrottler;
    }
 
    public Input getLastSentInput() {
        return this.lastSentInput;
    }
 
    public HitResult raycastHitResult(float a, Entity cameraEntity) {
        ItemStack itemStack = this.getActiveItem();
        AttackRange itemAttackRange = itemStack.get(DataComponents.ATTACK_RANGE);
        double blockInteractionRange = this.blockInteractionRange();
        HitResult hitResult = null;
        if (itemAttackRange != null) {
            hitResult = itemAttackRange.getClosesetHit(cameraEntity, a, EntitySelector.CAN_BE_PICKED);
            if (hitResult instanceof BlockHitResult) {
                hitResult = filterHitResult(hitResult, cameraEntity.getEyePosition(a), blockInteractionRange);
            }
        }
 
        if (hitResult == null || hitResult.getType() == HitResult.Type.MISS) {
            double entityInteractionRange = this.entityInteractionRange();
            hitResult = pick(cameraEntity, blockInteractionRange, entityInteractionRange, a);
        }
 
        return hitResult;
    }
 
    private static HitResult pick(Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) {
        double maxDistance = Math.max(blockInteractionRange, entityInteractionRange);
        double maxDistanceSq = Mth.square(maxDistance);
        Vec3 from = cameraEntity.getEyePosition(partialTicks);
        HitResult blockHitResult = cameraEntity.pick(maxDistance, partialTicks, false);
        double blockDistanceSq = blockHitResult.getLocation().distanceToSqr(from);
        if (blockHitResult.getType() != HitResult.Type.MISS) {
            maxDistanceSq = blockDistanceSq;
            maxDistance = Math.sqrt(blockDistanceSq);
        }
 
        Vec3 direction = cameraEntity.getViewVector(partialTicks);
        Vec3 to = from.add(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance);
        float overlap = 1.0F;
        AABB box = cameraEntity.getBoundingBox().expandTowards(direction.scale(maxDistance)).inflate(1.0, 1.0, 1.0);
        EntityHitResult entityHitResult = ProjectileUtil.getEntityHitResult(cameraEntity, from, to, box, EntitySelector.CAN_BE_PICKED, maxDistanceSq);
        return entityHitResult != null && entityHitResult.getLocation().distanceToSqr(from) < blockDistanceSq
            ? filterHitResult(entityHitResult, from, entityInteractionRange)
            : filterHitResult(blockHitResult, from, blockInteractionRange);
    }
 
    private static HitResult filterHitResult(HitResult hitResult, Vec3 from, double maxRange) {
        Vec3 hitLocation = hitResult.getLocation();
        if (!hitLocation.closerThan(from, maxRange)) {
            Vec3 location = hitResult.getLocation();
            Direction direction = Direction.getApproximateNearest(location.x - from.x, location.y - from.y, location.z - from.z);
            return BlockHitResult.miss(location, direction, BlockPos.containing(location));
        } else {
            return hitResult;
        }
    }
}

引用的其他类