ServerPlayerGameMode.java
net.minecraft.server.level.ServerPlayerGameMode
信息
- 全限定名:net.minecraft.server.level.ServerPlayerGameMode
- 类型:public class
- 包:net.minecraft.server.level
- 源码路径:src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
- 起始行号:L34
- 职责:
TODO
字段/常量
-
FLIGHT_DISABLE_RANGE- 类型:
double - 修饰符:
private static final - 源码定位:
L35 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L36 - 说明:
TODO
- 类型:
-
level- 类型:
ServerLevel - 修饰符:
protected - 源码定位:
L37 - 说明:
TODO
- 类型:
-
player- 类型:
ServerPlayer - 修饰符:
protected final - 源码定位:
L38 - 说明:
TODO
- 类型:
-
gameModeForPlayer- 类型:
GameType - 修饰符:
private - 源码定位:
L39 - 说明:
TODO
- 类型:
-
previousGameModeForPlayer- 类型:
GameType - 修饰符:
private - 源码定位:
L40 - 说明:
TODO
- 类型:
-
isDestroyingBlock- 类型:
boolean - 修饰符:
private - 源码定位:
L41 - 说明:
TODO
- 类型:
-
destroyProgressStart- 类型:
int - 修饰符:
private - 源码定位:
L42 - 说明:
TODO
- 类型:
-
destroyPos- 类型:
BlockPos - 修饰符:
private - 源码定位:
L43 - 说明:
TODO
- 类型:
-
gameTicks- 类型:
int - 修饰符:
private - 源码定位:
L44 - 说明:
TODO
- 类型:
-
hasDelayedDestroy- 类型:
boolean - 修饰符:
private - 源码定位:
L45 - 说明:
TODO
- 类型:
-
delayedDestroyPos- 类型:
BlockPos - 修饰符:
private - 源码定位:
L46 - 说明:
TODO
- 类型:
-
delayedTickStart- 类型:
int - 修饰符:
private - 源码定位:
L47 - 说明:
TODO
- 类型:
-
lastSentState- 类型:
int - 修饰符:
private - 源码定位:
L48 - 说明:
TODO
- 类型:
内部类/嵌套类型
- 无
构造器
public ServerPlayerGameMode(ServerPlayer player) @ L50
- 构造器名:ServerPlayerGameMode
- 源码定位:L50
- 修饰符:public
参数:
- player: ServerPlayer
说明:
TODO
方法
下面的方法块按源码顺序生成。
public boolean changeGameModeForPlayer(GameType gameModeForPlayer) @ L55
- 方法名:changeGameModeForPlayer
- 源码定位:L55
- 返回类型:boolean
- 修饰符:public
参数:
- gameModeForPlayer: GameType
说明:
TODO
protected void setGameModeForPlayer(GameType gameModeForPlayer, GameType previousGameModeForPlayer) @ L79
- 方法名:setGameModeForPlayer
- 源码定位:L79
- 返回类型:void
- 修饰符:protected
参数:
- gameModeForPlayer: GameType
- previousGameModeForPlayer: GameType
说明:
TODO
private boolean isInRangeOfGround() @ L86
- 方法名:isInRangeOfGround
- 源码定位:L86
- 返回类型:boolean
- 修饰符:private
参数:
- 无
说明:
TODO
public GameType getGameModeForPlayer() @ L91
- 方法名:getGameModeForPlayer
- 源码定位:L91
- 返回类型:GameType
- 修饰符:public
参数:
- 无
说明:
TODO
public GameType getPreviousGameModeForPlayer() @ L95
- 方法名:getPreviousGameModeForPlayer
- 源码定位:L95
- 返回类型:GameType
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isSurvival() @ L99
- 方法名:isSurvival
- 源码定位:L99
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isCreative() @ L103
- 方法名:isCreative
- 源码定位:L103
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public void tick() @ L107
- 方法名:tick
- 源码定位:L107
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private float incrementDestroyProgress(BlockState blockState, BlockPos delayedDestroyPos, int destroyStartTick) @ L132
- 方法名:incrementDestroyProgress
- 源码定位:L132
- 返回类型:float
- 修饰符:private
参数:
- blockState: BlockState
- delayedDestroyPos: BlockPos
- destroyStartTick: int
说明:
TODO
private void debugLogging(BlockPos pos, boolean allGood, int sequence, String message) @ L144
- 方法名:debugLogging
- 源码定位:L144
- 返回类型:void
- 修饰符:private
参数:
- pos: BlockPos
- allGood: boolean
- sequence: int
- message: String
说明:
TODO
public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int maxY, int sequence) @ L150
- 方法名:handleBlockBreakAction
- 源码定位:L150
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- action: ServerboundPlayerActionPacket.Action
- direction: Direction
- maxY: int
- sequence: int
说明:
TODO
public void destroyAndAck(BlockPos pos, int sequence, String exitId) @ L251
- 方法名:destroyAndAck
- 源码定位:L251
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- sequence: int
- exitId: String
说明:
TODO
public boolean destroyBlock(BlockPos pos) @ L260
- 方法名:destroyBlock
- 源码定位:L260
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public InteractionResult useItem(ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand) @ L300
- 方法名:useItem
- 源码定位:L300
- 返回类型:InteractionResult
- 修饰符:public
参数:
- player: ServerPlayer
- level: Level
- itemStack: ItemStack
- hand: InteractionHand
说明:
TODO
public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand, BlockHitResult hitResult) @ L341
- 方法名:useItemOn
- 源码定位:L341
- 返回类型:InteractionResult
- 修饰符:public
参数:
- player: ServerPlayer
- level: Level
- itemStack: ItemStack
- hand: InteractionHand
- hitResult: BlockHitResult
说明:
TODO
public void setLevel(ServerLevel newLevel) @ L396
- 方法名:setLevel
- 源码定位:L396
- 返回类型:void
- 修饰符:public
参数:
- newLevel: ServerLevel
说明:
TODO
代码
public class ServerPlayerGameMode {
private static final double FLIGHT_DISABLE_RANGE = 1.0;
private static final Logger LOGGER = LogUtils.getLogger();
protected ServerLevel level;
protected final ServerPlayer player;
private GameType gameModeForPlayer = GameType.DEFAULT_MODE;
private @Nullable GameType previousGameModeForPlayer;
private boolean isDestroyingBlock;
private int destroyProgressStart;
private BlockPos destroyPos = BlockPos.ZERO;
private int gameTicks;
private boolean hasDelayedDestroy;
private BlockPos delayedDestroyPos = BlockPos.ZERO;
private int delayedTickStart;
private int lastSentState = -1;
public ServerPlayerGameMode(ServerPlayer player) {
this.player = player;
this.level = player.level();
}
public boolean changeGameModeForPlayer(GameType gameModeForPlayer) {
if (gameModeForPlayer == this.gameModeForPlayer) {
return false;
} else {
Abilities abilities = this.player.getAbilities();
this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer);
if (abilities.flying && gameModeForPlayer != GameType.SPECTATOR && this.isInRangeOfGround()) {
abilities.flying = false;
}
this.player.onUpdateAbilities();
this.level
.getServer()
.getPlayerList()
.broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player));
this.level.updateSleepingPlayerList();
if (gameModeForPlayer == GameType.CREATIVE) {
this.player.resetCurrentImpulseContext();
}
return true;
}
}
protected void setGameModeForPlayer(GameType gameModeForPlayer, @Nullable GameType previousGameModeForPlayer) {
this.previousGameModeForPlayer = previousGameModeForPlayer;
this.gameModeForPlayer = gameModeForPlayer;
Abilities abilities = this.player.getAbilities();
gameModeForPlayer.updatePlayerAbilities(abilities);
}
private boolean isInRangeOfGround() {
List<VoxelShape> clipping = Entity.collectAllColliders(this.player, this.level, this.player.getBoundingBox());
return clipping.isEmpty() && this.player.getAvailableSpaceBelow(1.0) < 1.0;
}
public GameType getGameModeForPlayer() {
return this.gameModeForPlayer;
}
public @Nullable GameType getPreviousGameModeForPlayer() {
return this.previousGameModeForPlayer;
}
public boolean isSurvival() {
return this.gameModeForPlayer.isSurvival();
}
public boolean isCreative() {
return this.gameModeForPlayer.isCreative();
}
public void tick() {
this.gameTicks++;
if (this.hasDelayedDestroy) {
BlockState blockState = this.level.getBlockState(this.delayedDestroyPos);
if (blockState.isAir()) {
this.hasDelayedDestroy = false;
} else {
float destroyProgress = this.incrementDestroyProgress(blockState, this.delayedDestroyPos, this.delayedTickStart);
if (destroyProgress >= 1.0F) {
this.hasDelayedDestroy = false;
this.destroyBlock(this.delayedDestroyPos);
}
}
} else if (this.isDestroyingBlock) {
BlockState blockState = this.level.getBlockState(this.destroyPos);
if (blockState.isAir()) {
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
this.lastSentState = -1;
this.isDestroyingBlock = false;
} else {
this.incrementDestroyProgress(blockState, this.destroyPos, this.destroyProgressStart);
}
}
}
private float incrementDestroyProgress(BlockState blockState, BlockPos delayedDestroyPos, int destroyStartTick) {
int ticksSpentDestroying = this.gameTicks - destroyStartTick;
float destroyProgress = blockState.getDestroyProgress(this.player, this.player.level(), delayedDestroyPos) * (ticksSpentDestroying + 1);
int state = (int)(destroyProgress * 10.0F);
if (state != this.lastSentState) {
this.level.destroyBlockProgress(this.player.getId(), delayedDestroyPos, state);
this.lastSentState = state;
}
return destroyProgress;
}
private void debugLogging(BlockPos pos, boolean allGood, int sequence, String message) {
if (SharedConstants.DEBUG_BLOCK_BREAK) {
LOGGER.debug("Server ACK {} {} {} {}", sequence, pos, allGood, message);
}
}
public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int maxY, int sequence) {
if (!this.player.isWithinBlockInteractionRange(pos, 1.0)) {
this.debugLogging(pos, false, sequence, "too far");
} else if (pos.getY() > maxY) {
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
this.debugLogging(pos, false, sequence, "too high");
} else {
if (action == ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK) {
if (this.level.getServer().isUnderSpawnProtection(this.level, pos, this.player)) {
this.player.sendSpawnProtectionMessage(pos);
this.debugLogging(pos, false, sequence, "spawn protection");
return;
}
if (!this.level.mayInteract(this.player, pos)) {
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
this.debugLogging(pos, false, sequence, "may not interact");
return;
}
if (this.player.getAbilities().instabuild) {
this.destroyAndAck(pos, sequence, "creative destroy");
return;
}
if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) {
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
this.debugLogging(pos, false, sequence, "block action restricted");
return;
}
this.destroyProgressStart = this.gameTicks;
float progress = 1.0F;
BlockState blockState = this.level.getBlockState(pos);
if (!blockState.isAir()) {
EnchantmentHelper.onHitBlock(
this.level,
this.player.getMainHandItem(),
this.player,
this.player,
EquipmentSlot.MAINHAND,
Vec3.atCenterOf(pos),
blockState,
item -> this.player.onEquippedItemBroken(item, EquipmentSlot.MAINHAND)
);
blockState.attack(this.level, pos, this.player);
progress = blockState.getDestroyProgress(this.player, this.player.level(), pos);
}
if (!blockState.isAir() && progress >= 1.0F) {
this.destroyAndAck(pos, sequence, "insta mine");
} else {
if (this.isDestroyingBlock) {
this.player.connection.send(new ClientboundBlockUpdatePacket(this.destroyPos, this.level.getBlockState(this.destroyPos)));
this.debugLogging(pos, false, sequence, "abort destroying since another started (client insta mine, server disagreed)");
}
this.isDestroyingBlock = true;
this.destroyPos = pos.immutable();
int state = (int)(progress * 10.0F);
this.level.destroyBlockProgress(this.player.getId(), pos, state);
this.debugLogging(pos, true, sequence, "actual start of destroying");
this.lastSentState = state;
}
} else if (action == ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK) {
if (pos.equals(this.destroyPos)) {
int ticksSpentDestroying = this.gameTicks - this.destroyProgressStart;
BlockState state = this.level.getBlockState(pos);
if (!state.isAir()) {
float destroyProgress = state.getDestroyProgress(this.player, this.player.level(), pos) * (ticksSpentDestroying + 1);
if (destroyProgress >= 0.7F) {
this.isDestroyingBlock = false;
this.level.destroyBlockProgress(this.player.getId(), pos, -1);
this.destroyAndAck(pos, sequence, "destroyed");
return;
}
if (!this.hasDelayedDestroy) {
this.isDestroyingBlock = false;
this.hasDelayedDestroy = true;
this.delayedDestroyPos = pos;
this.delayedTickStart = this.destroyProgressStart;
}
}
}
this.debugLogging(pos, true, sequence, "stopped destroying");
} else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) {
this.isDestroyingBlock = false;
if (!Objects.equals(this.destroyPos, pos)) {
LOGGER.warn("Mismatch in destroy block pos: {} {}", this.destroyPos, pos);
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
this.debugLogging(pos, true, sequence, "aborted mismatched destroying");
}
this.level.destroyBlockProgress(this.player.getId(), pos, -1);
this.debugLogging(pos, true, sequence, "aborted destroying");
}
}
}
public void destroyAndAck(BlockPos pos, int sequence, String exitId) {
if (this.destroyBlock(pos)) {
this.debugLogging(pos, true, sequence, exitId);
} else {
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
this.debugLogging(pos, false, sequence, exitId);
}
}
public boolean destroyBlock(BlockPos pos) {
BlockState state = this.level.getBlockState(pos);
if (!this.player.getMainHandItem().canDestroyBlock(state, this.level, pos, this.player)) {
return false;
} else {
BlockEntity blockEntity = this.level.getBlockEntity(pos);
Block block = state.getBlock();
if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
this.level.sendBlockUpdated(pos, state, state, 3);
return false;
} else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) {
return false;
} else {
BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player);
boolean changed = this.level.removeBlock(pos, false);
if (SharedConstants.DEBUG_BLOCK_BREAK) {
LOGGER.info("server broke {} {} -> {}", pos, adjustedState, this.level.getBlockState(pos));
}
if (changed) {
block.destroy(this.level, pos, adjustedState);
}
if (this.player.preventsBlockDrops()) {
return true;
} else {
ItemStack itemStack = this.player.getMainHandItem();
ItemStack destroyedWith = itemStack.copy();
boolean canDestroy = this.player.hasCorrectToolForDrops(adjustedState);
itemStack.mineBlock(this.level, adjustedState, pos, this.player);
if (changed && canDestroy) {
block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith);
}
return true;
}
}
}
}
public InteractionResult useItem(ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand) {
if (this.gameModeForPlayer == GameType.SPECTATOR) {
return InteractionResult.PASS;
} else if (player.getCooldowns().isOnCooldown(itemStack)) {
return InteractionResult.PASS;
} else {
int oldCount = itemStack.getCount();
int oldDamage = itemStack.getDamageValue();
InteractionResult result = itemStack.use(level, player, hand);
ItemStack resultStack;
if (result instanceof InteractionResult.Success success) {
resultStack = Objects.requireNonNullElse(success.heldItemTransformedTo(), player.getItemInHand(hand));
} else {
resultStack = player.getItemInHand(hand);
}
if (resultStack == itemStack
&& resultStack.getCount() == oldCount
&& resultStack.getUseDuration(player) <= 0
&& resultStack.getDamageValue() == oldDamage) {
return result;
} else if (result instanceof InteractionResult.Fail && resultStack.getUseDuration(player) > 0 && !player.isUsingItem()) {
return result;
} else {
if (itemStack != resultStack) {
player.setItemInHand(hand, resultStack);
}
if (resultStack.isEmpty()) {
player.setItemInHand(hand, ItemStack.EMPTY);
}
if (!player.isUsingItem()) {
player.inventoryMenu.sendAllDataToRemote();
}
return result;
}
}
}
public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand, BlockHitResult hitResult) {
BlockPos pos = hitResult.getBlockPos();
BlockState state = level.getBlockState(pos);
if (!state.getBlock().isEnabled(level.enabledFeatures())) {
return InteractionResult.FAIL;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
MenuProvider menuProvider = state.getMenuProvider(level, pos);
if (menuProvider != null) {
player.openMenu(menuProvider);
return InteractionResult.CONSUME;
} else {
return InteractionResult.PASS;
}
} else {
boolean haveSomethingInOurHands = !player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty();
boolean suppressUsingBlock = player.isSecondaryUseActive() && haveSomethingInOurHands;
ItemStack usedItemStack = itemStack.copy();
if (!suppressUsingBlock) {
InteractionResult itemUse = state.useItemOn(player.getItemInHand(hand), level, player, hand, hitResult);
if (itemUse.consumesAction()) {
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(player, pos, usedItemStack);
return itemUse;
}
if (itemUse instanceof InteractionResult.TryEmptyHandInteraction && hand == InteractionHand.MAIN_HAND) {
InteractionResult use = state.useWithoutItem(level, player, hitResult);
if (use.consumesAction()) {
CriteriaTriggers.DEFAULT_BLOCK_USE.trigger(player, pos);
return use;
}
}
}
if (!itemStack.isEmpty() && !player.getCooldowns().isOnCooldown(itemStack)) {
UseOnContext context = new UseOnContext(player, hand, hitResult);
InteractionResult success;
if (player.hasInfiniteMaterials()) {
int count = itemStack.getCount();
success = itemStack.useOn(context);
itemStack.setCount(count);
} else {
success = itemStack.useOn(context);
}
if (success.consumesAction()) {
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(player, pos, usedItemStack);
}
return success;
} else {
return InteractionResult.PASS;
}
}
}
public void setLevel(ServerLevel newLevel) {
this.level = newLevel;
}
}引用的其他类
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundBlockUpdatePacket()
- 引用位置:
-
ClientboundPlayerInfoUpdatePacket
- 引用位置:
构造调用 - 关联成员:
ClientboundPlayerInfoUpdatePacket()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Entity.collectAllColliders()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
UseOnContext()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
EnchantmentHelper.onHitBlock()
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Vec3.atCenterOf()
- 引用位置: