1146 lines
48 KiB
Java
1146 lines
48 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.google.common.collect.Lists
|
|
* com.mojang.logging.LogUtils
|
|
* org.jspecify.annotations.Nullable
|
|
* org.slf4j.Logger
|
|
*/
|
|
package net.minecraft.client.player;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.mojang.logging.LogUtils;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.stream.StreamSupport;
|
|
import net.minecraft.client.ClientRecipeBook;
|
|
import net.minecraft.client.KeyMapping;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.screens.LevelLoadingScreen;
|
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
|
import net.minecraft.client.gui.screens.inventory.BookEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.CommandBlockEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.HangingSignEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.JigsawBlockEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.MinecartCommandBlockEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.SignEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.StructureBlockEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.TestBlockEditScreen;
|
|
import net.minecraft.client.gui.screens.inventory.TestInstanceBlockEditScreen;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
|
import net.minecraft.client.player.AbstractClientPlayer;
|
|
import net.minecraft.client.player.ClientInput;
|
|
import net.minecraft.client.resources.sounds.AmbientSoundHandler;
|
|
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
|
import net.minecraft.client.resources.sounds.BubbleColumnAmbientSoundHandler;
|
|
import net.minecraft.client.resources.sounds.ElytraOnPlayerSoundInstance;
|
|
import net.minecraft.client.resources.sounds.RidingEntitySoundInstance;
|
|
import net.minecraft.client.resources.sounds.RidingMinecartSoundInstance;
|
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
|
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundHandler;
|
|
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.protocol.game.ServerboundClientCommandPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundContainerClosePacket;
|
|
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket;
|
|
import net.minecraft.network.protocol.game.ServerboundPlayerAbilitiesPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket;
|
|
import net.minecraft.network.protocol.game.ServerboundRecipeBookSeenRecipePacket;
|
|
import net.minecraft.network.protocol.game.ServerboundSwingPacket;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.server.dialog.Dialog;
|
|
import net.minecraft.server.permissions.LevelBasedPermissionSet;
|
|
import net.minecraft.server.permissions.PermissionSet;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.stats.StatsCounter;
|
|
import net.minecraft.tags.FluidTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.TickThrottler;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.HumanoidArm;
|
|
import net.minecraft.world.entity.MoverType;
|
|
import net.minecraft.world.entity.PlayerRideableJumping;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.animal.HappyGhast;
|
|
import net.minecraft.world.entity.animal.nautilus.AbstractNautilus;
|
|
import net.minecraft.world.entity.player.Abilities;
|
|
import net.minecraft.world.entity.player.Input;
|
|
import net.minecraft.world.entity.vehicle.AbstractBoat;
|
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
|
import net.minecraft.world.entity.vehicle.MinecartCommandBlock;
|
|
import net.minecraft.world.inventory.ClickAction;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.component.UseEffects;
|
|
import net.minecraft.world.item.component.WritableBookContent;
|
|
import net.minecraft.world.item.crafting.display.RecipeDisplayId;
|
|
import net.minecraft.world.level.GameType;
|
|
import net.minecraft.world.level.block.Portal;
|
|
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
|
import net.minecraft.world.level.block.entity.HangingSignBlockEntity;
|
|
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
|
|
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
|
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
|
import net.minecraft.world.level.block.entity.TestBlockEntity;
|
|
import net.minecraft.world.level.block.entity.TestInstanceBlockEntity;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.Vec2;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.jspecify.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
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.13962633907794952;
|
|
public static final float USING_ITEM_SPEED_FACTOR = 0.2f;
|
|
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 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) {
|
|
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()));
|
|
}
|
|
|
|
@Override
|
|
public void heal(float heal) {
|
|
}
|
|
|
|
@Override
|
|
public boolean startRiding(Entity entity, boolean force, boolean sendEventAndTriggers) {
|
|
if (!super.startRiding(entity, force, sendEventAndTriggers)) {
|
|
return false;
|
|
}
|
|
if (entity instanceof AbstractMinecart) {
|
|
AbstractMinecart minecart = (AbstractMinecart)entity;
|
|
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 happyGhast = (HappyGhast)entity;
|
|
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) {
|
|
AbstractNautilus nautilus = (AbstractNautilus)entity;
|
|
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) {
|
|
if (this.isPassenger()) {
|
|
return super.getViewYRot(a);
|
|
}
|
|
return this.getYRot();
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
this.tickClientLoadTimeout();
|
|
if (!this.hasClientLoaded()) {
|
|
return;
|
|
}
|
|
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)) continue;
|
|
return ((BiomeAmbientSoundsHandler)ambientSoundHandler).getMoodiness();
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
private void sendPosition() {
|
|
this.sendIsSprintingIfNeeded();
|
|
if (this.isControlledCamera()) {
|
|
boolean rot;
|
|
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 bl = 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.hurtTime = this.hurtDuration = 10;
|
|
}
|
|
} 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 permissions) {
|
|
this.permissions = permissions;
|
|
}
|
|
|
|
@Override
|
|
public void displayClientMessage(Component component, boolean overlayMessage) {
|
|
this.minecraft.getChatListener().handleSystemMessage(component, overlayMessage);
|
|
}
|
|
|
|
private void moveTowardsClosestSpace(double x, double z) {
|
|
Direction[] directions;
|
|
BlockPos pos = BlockPos.containing(x, this.getY(), z);
|
|
if (!this.suffocatesAt(pos)) {
|
|
return;
|
|
}
|
|
double xd = x - (double)pos.getX();
|
|
double zd = z - (double)pos.getZ();
|
|
Direction dir = null;
|
|
double closest = Double.MAX_VALUE;
|
|
for (Direction direction : directions = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH}) {
|
|
double distanceToEdge;
|
|
double axisDistance = direction.getAxis().choose(xd, 0.0, zd);
|
|
double d = distanceToEdge = direction.getAxisDirection() == Direction.AxisDirection.POSITIVE ? 1.0 - axisDistance : axisDistance;
|
|
if (!(distanceToEdge < closest) || this.suffocatesAt(pos.relative(direction))) continue;
|
|
closest = distanceToEdge;
|
|
dir = direction;
|
|
}
|
|
if (dir != null) {
|
|
Vec3 oldMovement = this.getDeltaMovement();
|
|
if (dir.getAxis() == Direction.Axis.X) {
|
|
this.setDeltaMovement(0.1 * (double)dir.getStepX(), oldMovement.y, oldMovement.z);
|
|
} else {
|
|
this.setDeltaMovement(oldMovement.x, oldMovement.y, 0.1 * (double)dir.getStepZ());
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean suffocatesAt(BlockPos pos) {
|
|
AABB boundingBox = this.getBoundingBox();
|
|
AABB testArea = new AABB(pos.getX(), boundingBox.minY, pos.getZ(), (double)pos.getX() + 1.0, boundingBox.maxY, (double)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(experienceProgress);
|
|
}
|
|
this.experienceProgress = experienceProgress;
|
|
this.totalExperience = totalExp;
|
|
this.experienceLevel = experienceLevel;
|
|
}
|
|
|
|
private void setExperienceDisplayStartTickToTickCount(float experienceProgress) {
|
|
this.experienceDisplayStartTick = this.experienceDisplayStartTick == Integer.MIN_VALUE ? -2147483647 : 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 playNotifySound(SoundEvent sound, SoundSource soundSource, float volume, float pitch) {
|
|
this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), sound, soundSource, volume, pitch, false);
|
|
}
|
|
|
|
@Override
|
|
public void startUsingItem(InteractionHand hand) {
|
|
ItemStack itemStack = this.getItemInHand(hand);
|
|
if (itemStack.isEmpty() || this.isUsingItem()) {
|
|
return;
|
|
}
|
|
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)) {
|
|
InteractionHand serverUsingHand;
|
|
boolean serverUsingItem = ((Byte)this.entityData.get(DATA_LIVING_ENTITY_FLAGS) & 1) > 0;
|
|
InteractionHand interactionHand = serverUsingHand = ((Byte)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() {
|
|
PlayerRideableJumping playerRideableJumping;
|
|
Entity entity = this.getControlledVehicle();
|
|
return entity instanceof PlayerRideableJumping && (playerRideableJumping = (PlayerRideableJumping)((Object)entity)).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) {
|
|
HangingSignBlockEntity hangingSign = (HangingSignBlockEntity)sign;
|
|
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.getXRot() - this.xBob) * 0.5f;
|
|
this.yBob += (this.getYRot() - this.yBob) * 0.5f;
|
|
} else {
|
|
super.applyInput();
|
|
}
|
|
}
|
|
|
|
private Vec2 modifyInput(Vec2 input) {
|
|
if (input.lengthSquared() == 0.0f) {
|
|
return input;
|
|
}
|
|
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 LocalPlayer.modifyInputSpeedForSquareMovement(newInput);
|
|
}
|
|
|
|
private static Vec2 modifyInputSpeedForSquareMovement(Vec2 input) {
|
|
float length = input.length();
|
|
if (length <= 0.0f) {
|
|
return input;
|
|
}
|
|
Vec2 direction = input.scale(1.0f / length);
|
|
float distanceToUnitSquare = LocalPlayer.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 > (double)this.level().getMinY() && testY <= (double)this.level().getMaxY(); testY += 1.0) {
|
|
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() {
|
|
PlayerRideableJumping jumpableVehicle;
|
|
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() - (double)this.getBbWidth() * 0.35, this.getZ() + (double)this.getBbWidth() * 0.35);
|
|
this.moveTowardsClosestSpace(this.getX() - (double)this.getBbWidth() * 0.35, this.getZ() - (double)this.getBbWidth() * 0.35);
|
|
this.moveTowardsClosestSpace(this.getX() + (double)this.getBbWidth() * 0.35, this.getZ() - (double)this.getBbWidth() * 0.35);
|
|
this.moveTowardsClosestSpace(this.getX() + (double)this.getBbWidth() * 0.35, this.getZ() + (double)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()) {
|
|
boolean bl = 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, (float)inputYa * abilities.getFlyingSpeed() * 3.0f, 0.0));
|
|
}
|
|
}
|
|
if ((jumpableVehicle = this.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;
|
|
this.jumpRidingScale = this.jumpRidingTicks < 10 ? (float)this.jumpRidingTicks * 0.1f : 0.8f + 2.0f / (float)(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;
|
|
Entity entity = this.getControlledVehicle();
|
|
if (entity instanceof AbstractBoat) {
|
|
AbstractBoat boat = (AbstractBoat)entity;
|
|
boat.setInput(this.input.keyPresses.left(), this.input.keyPresses.right(), this.input.keyPresses.forward(), this.input.keyPresses.backward());
|
|
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()) {
|
|
return;
|
|
}
|
|
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));
|
|
float cos = Mth.cos(this.getYRot() * ((float)Math.PI / 180));
|
|
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) {
|
|
return;
|
|
}
|
|
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()) {
|
|
return;
|
|
}
|
|
ceilingPos = ceilingPos.above();
|
|
BlockState aboveBlock2 = this.level().getBlockState(ceilingPos);
|
|
if (!aboveBlock2.getCollisionShape(this.level(), ceilingPos, context).isEmpty()) {
|
|
return;
|
|
}
|
|
float lookAheadSteps = 7.0f;
|
|
float jumpHeight = 1.2f;
|
|
if (this.hasEffect(MobEffects.JUMP_BOOST)) {
|
|
jumpHeight += (float)(this.getEffect(MobEffects.JUMP_BOOST).getAmplifier() + 1) * 0.75f;
|
|
}
|
|
float lookAheadDist = Math.max(currentSpeed * 7.0f, 1.0f / moveDistInverted);
|
|
Vec3 segBegin = moveBegin;
|
|
Vec3 segEnd = moveEnd.add(moveDir.scale(lookAheadDist));
|
|
float playerWidth = this.getBbWidth();
|
|
float playerHeight = this.getBbHeight();
|
|
AABB testBox = new AABB(segBegin, segEnd.add(0.0, playerHeight, 0.0)).inflate(playerWidth, 0.0, playerWidth);
|
|
segBegin = segBegin.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 shape = StreamSupport.stream(collisions.spliterator(), false).flatMap(s -> s.toAabbs().stream()).iterator();
|
|
float obstacleHeight = Float.MIN_VALUE;
|
|
while (shape.hasNext()) {
|
|
AABB box = (AABB)shape.next();
|
|
if (!box.intersects(leftSegBegin, leftSegEnd) && !box.intersects(rightSegBegin, rightSegEnd)) continue;
|
|
obstacleHeight = (float)box.maxY;
|
|
Vec3 obstacleShapeCenter = box.getCenter();
|
|
BlockPos obstacleBlockPos = BlockPos.containing(obstacleShapeCenter);
|
|
int steps = 1;
|
|
while ((float)steps < jumpHeight) {
|
|
BlockPos abovePos1 = obstacleBlockPos.above(steps);
|
|
BlockState aboveBlock = this.level().getBlockState(abovePos1);
|
|
VoxelShape blockShape = aboveBlock.getCollisionShape(this.level(), abovePos1, context);
|
|
if (!blockShape.isEmpty() && (double)(obstacleHeight = (float)blockShape.max(Direction.Axis.Y) + (float)abovePos1.getY()) - this.getY() > (double)jumpHeight) {
|
|
return;
|
|
}
|
|
if (steps > 1) {
|
|
ceilingPos = ceilingPos.above();
|
|
BlockState aboveBlock3 = this.level().getBlockState(ceilingPos);
|
|
if (!aboveBlock3.getCollisionShape(this.level(), ceilingPos, context).isEmpty()) {
|
|
return;
|
|
}
|
|
}
|
|
++steps;
|
|
}
|
|
break block0;
|
|
}
|
|
if (obstacleHeight == Float.MIN_VALUE) {
|
|
return;
|
|
}
|
|
float ydelta = (float)((double)obstacleHeight - this.getY());
|
|
if (ydelta <= 0.5f || ydelta > jumpHeight) {
|
|
return;
|
|
}
|
|
this.autoJumpTime = 1;
|
|
}
|
|
|
|
@Override
|
|
protected boolean isHorizontalCollisionMinor(Vec3 movement) {
|
|
float yRotInRadians = this.getYRot() * ((float)Math.PI / 180);
|
|
double yRotSin = Mth.sin(yRotInRadians);
|
|
double yRotCos = Mth.cos(yRotInRadians);
|
|
double globalXA = (double)this.xxa * yRotCos - (double)this.zza * yRotSin;
|
|
double globalZA = (double)this.zza * yRotCos + (double)this.xxa * yRotSin;
|
|
double aLengthSquared = Mth.square(globalXA) + Mth.square(globalZA);
|
|
double movementLengthSquared = Mth.square(movement.x) + Mth.square(movement.z);
|
|
if (aLengthSquared < (double)1.0E-5f || movementLengthSquared < (double)1.0E-5f) {
|
|
return false;
|
|
}
|
|
double dotProduct = globalXA * movement.x + globalZA * movement.z;
|
|
double angleBetweenDesiredAndActualMovement = Math.acos(dotProduct / Math.sqrt(aLengthSquared * movementLengthSquared));
|
|
return angleBetweenDesiredAndActualMovement < 0.13962633907794952;
|
|
}
|
|
|
|
private boolean canAutoJump() {
|
|
return this.isAutoJumpEnabled() && this.autoJumpTime <= 0 && this.onGround() && !this.isStayingOnGroundSurface() && !this.isPassenger() && this.isMoving() && (double)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;
|
|
}
|
|
float max = 600.0f;
|
|
float mid = 100.0f;
|
|
if ((float)this.waterVisionTime >= 600.0f) {
|
|
return 1.0f;
|
|
}
|
|
float a = Mth.clamp((float)this.waterVisionTime / 100.0f, 0.0f, 1.0f);
|
|
float b = (float)this.waterVisionTime < 100.0f ? 0.0f : Mth.clamp(((float)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;
|
|
}
|
|
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);
|
|
float xRot = Mth.lerp(partialTickTime * 0.5f, this.getXRot(), this.xRotO) * ((float)Math.PI / 180);
|
|
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));
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|