minecraft-source/src/net/minecraft/server/level/ServerPlayerGameMode.java

323 lines
15 KiB
Java

package net.minecraft.server.level;
import org.apache.logging.log4j.LogManager;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.item.UseOnContext;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.JigsawBlock;
import net.minecraft.world.level.block.StructureBlock;
import net.minecraft.world.level.block.CommandBlock;
import java.util.Objects;
import net.minecraft.world.level.Level;
import net.minecraft.network.protocol.game.ClientboundBlockBreakAckPacket;
import net.minecraft.core.Direction;
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.GameType;
import org.apache.logging.log4j.Logger;
public class ServerPlayerGameMode {
private static final Logger LOGGER;
public ServerLevel level;
public ServerPlayer player;
private GameType gameModeForPlayer;
private boolean isDestroyingBlock;
private int destroyProgressStart;
private BlockPos destroyPos;
private int gameTicks;
private boolean hasDelayedDestroy;
private BlockPos delayedDestroyPos;
private int delayedTickStart;
private int lastSentState;
public ServerPlayerGameMode(final ServerLevel xd) {
this.gameModeForPlayer = GameType.NOT_SET;
this.destroyPos = BlockPos.ZERO;
this.delayedDestroyPos = BlockPos.ZERO;
this.lastSentState = -1;
this.level = xd;
}
public void setGameModeForPlayer(final GameType bjq) {
(this.gameModeForPlayer = bjq).updatePlayerAbilities(this.player.abilities);
this.player.onUpdateAbilities();
this.player.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.UPDATE_GAME_MODE, new ServerPlayer[] { this.player }));
this.level.updateSleepingPlayerList();
}
public GameType getGameModeForPlayer() {
return this.gameModeForPlayer;
}
public boolean isSurvival() {
return this.gameModeForPlayer.isSurvival();
}
public boolean isCreative() {
return this.gameModeForPlayer.isCreative();
}
public void updateGameMode(final GameType bjq) {
if (this.gameModeForPlayer == GameType.NOT_SET) {
this.gameModeForPlayer = bjq;
}
this.setGameModeForPlayer(this.gameModeForPlayer);
}
public void tick() {
++this.gameTicks;
if (this.hasDelayedDestroy) {
final BlockState byg2 = this.level.getBlockState(this.delayedDestroyPos);
if (byg2.isAir()) {
this.hasDelayedDestroy = false;
}
else {
final float float3 = this.incrementDestroyProgress(byg2, this.delayedDestroyPos, this.delayedTickStart);
if (float3 >= 1.0f) {
this.hasDelayedDestroy = false;
this.destroyBlock(this.delayedDestroyPos);
}
}
}
else if (this.isDestroyingBlock) {
final BlockState byg2 = this.level.getBlockState(this.destroyPos);
if (byg2.isAir()) {
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
this.lastSentState = -1;
this.isDestroyingBlock = false;
}
else {
this.incrementDestroyProgress(byg2, this.destroyPos, this.destroyProgressStart);
}
}
}
private float incrementDestroyProgress(final BlockState byg, final BlockPos fk, final int integer) {
final int integer2 = this.gameTicks - integer;
final float float6 = byg.getDestroyProgress(this.player, this.player.level, fk) * (integer2 + 1);
final int integer3 = (int)(float6 * 10.0f);
if (integer3 != this.lastSentState) {
this.level.destroyBlockProgress(this.player.getId(), fk, integer3);
this.lastSentState = integer3;
}
return float6;
}
public void handleBlockBreakAction(final BlockPos fk, final ServerboundPlayerActionPacket.Action a, final Direction fp, final int integer) {
final double double6 = this.player.getX() - (fk.getX() + 0.5);
final double double7 = this.player.getY() - (fk.getY() + 0.5) + 1.5;
final double double8 = this.player.getZ() - (fk.getZ() + 0.5);
final double double9 = double6 * double6 + double7 * double7 + double8 * double8;
if (double9 > 36.0) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, false, "too far"));
return;
}
if (fk.getY() >= integer) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, false, "too high"));
return;
}
if (a == ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK) {
if (!this.level.mayInteract(this.player, fk)) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, false, "may not interact"));
return;
}
if (this.isCreative()) {
if (!this.level.extinguishFire(null, fk, fp)) {
this.destroyAndAck(fk, a, "creative destroy");
}
else {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, true, "fire put out"));
}
return;
}
if (this.player.blockActionRestricted(this.level, fk, this.gameModeForPlayer)) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, false, "block action restricted"));
return;
}
this.level.extinguishFire(null, fk, fp);
this.destroyProgressStart = this.gameTicks;
float float14 = 1.0f;
final BlockState byg15 = this.level.getBlockState(fk);
if (!byg15.isAir()) {
byg15.attack(this.level, fk, this.player);
float14 = byg15.getDestroyProgress(this.player, this.player.level, fk);
}
if (!byg15.isAir() && float14 >= 1.0f) {
this.destroyAndAck(fk, a, "insta mine");
}
else {
if (this.isDestroyingBlock) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(this.destroyPos, this.level.getBlockState(this.destroyPos), ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, false, "abort destroying since another started (client insta mine, server disagreed)"));
}
this.isDestroyingBlock = true;
this.destroyPos = fk.immutable();
final int integer2 = (int)(float14 * 10.0f);
this.level.destroyBlockProgress(this.player.getId(), fk, integer2);
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, true, "actual start of destroying"));
this.lastSentState = integer2;
}
}
else if (a == ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK) {
if (fk.equals(this.destroyPos)) {
final int integer3 = this.gameTicks - this.destroyProgressStart;
final BlockState byg15 = this.level.getBlockState(fk);
if (!byg15.isAir()) {
final float float15 = byg15.getDestroyProgress(this.player, this.player.level, fk) * (integer3 + 1);
if (float15 >= 0.7f) {
this.isDestroyingBlock = false;
this.level.destroyBlockProgress(this.player.getId(), fk, -1);
this.destroyAndAck(fk, a, "destroyed");
return;
}
if (!this.hasDelayedDestroy) {
this.isDestroyingBlock = false;
this.hasDelayedDestroy = true;
this.delayedDestroyPos = fk;
this.delayedTickStart = this.destroyProgressStart;
}
}
}
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, true, "stopped destroying"));
}
else if (a == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) {
this.isDestroyingBlock = false;
if (!Objects.equals(this.destroyPos, fk)) {
ServerPlayerGameMode.LOGGER.warn("Mismatch in destroy block pos: " + this.destroyPos + " " + fk);
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
this.player.connection.send(new ClientboundBlockBreakAckPacket(this.destroyPos, this.level.getBlockState(this.destroyPos), a, true, "aborted mismatched destroying"));
}
this.level.destroyBlockProgress(this.player.getId(), fk, -1);
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, true, "aborted destroying"));
}
}
public void destroyAndAck(final BlockPos fk, final ServerboundPlayerActionPacket.Action a, final String string) {
if (this.destroyBlock(fk)) {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, true, string));
}
else {
this.player.connection.send(new ClientboundBlockBreakAckPacket(fk, this.level.getBlockState(fk), a, false, string));
}
}
public boolean destroyBlock(final BlockPos fk) {
final BlockState byg3 = this.level.getBlockState(fk);
if (!this.player.getMainHandItem().getItem().canAttackBlock(byg3, this.level, fk, this.player)) {
return false;
}
final BlockEntity bwi4 = this.level.getBlockEntity(fk);
final Block bpe5 = byg3.getBlock();
if ((bpe5 instanceof CommandBlock || bpe5 instanceof StructureBlock || bpe5 instanceof JigsawBlock) && !this.player.canUseGameMasterBlocks()) {
this.level.sendBlockUpdated(fk, byg3, byg3, 3);
return false;
}
if (this.player.blockActionRestricted(this.level, fk, this.gameModeForPlayer)) {
return false;
}
bpe5.playerWillDestroy(this.level, fk, byg3, this.player);
final boolean boolean6 = this.level.removeBlock(fk, false);
if (boolean6) {
bpe5.destroy(this.level, fk, byg3);
}
if (this.isCreative()) {
return true;
}
final ItemStack bek7 = this.player.getMainHandItem();
final ItemStack bek8 = bek7.copy();
final boolean boolean7 = this.player.canDestroy(byg3);
bek7.mineBlock(this.level, byg3, fk, this.player);
if (boolean6 && boolean7) {
bpe5.playerDestroy(this.level, this.player, fk, byg3, bwi4, bek8);
}
return true;
}
public InteractionResult useItem(final Player ayg, final Level bjt, final ItemStack bek, final InteractionHand ajh) {
if (this.gameModeForPlayer == GameType.SPECTATOR) {
return InteractionResult.PASS;
}
if (ayg.getCooldowns().isOnCooldown(bek.getItem())) {
return InteractionResult.PASS;
}
final int integer6 = bek.getCount();
final int integer7 = bek.getDamageValue();
final InteractionResultHolder<ItemStack> ajj8 = bek.use(bjt, ayg, ajh);
final ItemStack bek2 = ajj8.getObject();
if (bek2 == bek && bek2.getCount() == integer6 && bek2.getUseDuration() <= 0 && bek2.getDamageValue() == integer7) {
return ajj8.getResult();
}
if (ajj8.getResult() == InteractionResult.FAIL && bek2.getUseDuration() > 0 && !ayg.isUsingItem()) {
return ajj8.getResult();
}
ayg.setItemInHand(ajh, bek2);
if (this.isCreative()) {
bek2.setCount(integer6);
if (bek2.isDamageableItem() && bek2.getDamageValue() != integer7) {
bek2.setDamageValue(integer7);
}
}
if (bek2.isEmpty()) {
ayg.setItemInHand(ajh, ItemStack.EMPTY);
}
if (!ayg.isUsingItem()) {
((ServerPlayer)ayg).refreshContainer(ayg.inventoryMenu);
}
return ajj8.getResult();
}
public InteractionResult useItemOn(final Player ayg, final Level bjt, final ItemStack bek, final InteractionHand ajh, final BlockHitResult cvd) {
final BlockPos fk7 = cvd.getBlockPos();
final BlockState byg8 = bjt.getBlockState(fk7);
if (this.gameModeForPlayer == GameType.SPECTATOR) {
final MenuProvider ajl9 = byg8.getMenuProvider(bjt, fk7);
if (ajl9 != null) {
ayg.openMenu(ajl9);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
else {
final boolean boolean9 = !ayg.getMainHandItem().isEmpty() || !ayg.getOffhandItem().isEmpty();
final boolean boolean10 = ayg.isSecondaryUseActive() && boolean9;
if (!boolean10) {
final InteractionResult aji11 = byg8.use(bjt, ayg, ajh, cvd);
if (aji11.consumesAction()) {
return aji11;
}
}
if (bek.isEmpty() || ayg.getCooldowns().isOnCooldown(bek.getItem())) {
return InteractionResult.PASS;
}
final UseOnContext bfw11 = new UseOnContext(ayg, ajh, cvd);
if (this.isCreative()) {
final int integer12 = bek.getCount();
final InteractionResult aji12 = bek.useOn(bfw11);
bek.setCount(integer12);
return aji12;
}
return bek.useOn(bfw11);
}
}
public void setLevel(final ServerLevel xd) {
this.level = xd;
}
static {
LOGGER = LogManager.getLogger();
}
}