mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 14:34:59 +01:00
start implementing new block breaking
This commit is contained in:
parent
77ffb6098e
commit
289a74975d
5 changed files with 150 additions and 118 deletions
|
@ -51,6 +51,9 @@ public enum GeyserAttributeType {
|
||||||
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
|
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
|
||||||
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f),
|
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f),
|
||||||
BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f),
|
BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f),
|
||||||
|
MINING_EFFICIENCY("minecraft:mining_efficiency", null, 0f, 1024f, 0f),
|
||||||
|
BLOCK_BREAK_SPEED("minecraft:block_break_speed", null, 0f, 1024f, 1f),
|
||||||
|
SUBMERGED_MINING_SPEED("minecraft:submerged_mining_speed", null, 0f, 20f, 0.2f),
|
||||||
|
|
||||||
// Bedrock Attributes
|
// Bedrock Attributes
|
||||||
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
|
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
|
||||||
|
|
|
@ -286,6 +286,15 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
return attributeData;
|
return attributeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float attributeOrDefault(GeyserAttributeType type) {
|
||||||
|
var attribute = this.attributes.get(type);
|
||||||
|
if (attribute == null) {
|
||||||
|
return type.getDefaultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attribute.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
||||||
if (pos != null) {
|
if (pos != null) {
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
||||||
|
|
|
@ -523,6 +523,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
@Setter
|
@Setter
|
||||||
private long blockBreakStartTime;
|
private long blockBreakStartTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* // TODO
|
||||||
|
*/
|
||||||
|
private long destroyProgress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores whether the player intended to place a bucket.
|
* Stores whether the player intended to place a bucket.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.PlayerActionType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.PlayerBlockActionData;
|
import org.cloudburstmc.protocol.bedrock.data.PlayerBlockActionData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||||
import org.geysermc.geyser.entity.type.Entity;
|
import org.geysermc.geyser.entity.type.Entity;
|
||||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||||
|
@ -88,7 +89,7 @@ final class BedrockBlockActions {
|
||||||
LevelEventPacket startBreak = new LevelEventPacket();
|
LevelEventPacket startBreak = new LevelEventPacket();
|
||||||
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
||||||
startBreak.setPosition(vector.toFloat());
|
startBreak.setPosition(vector.toFloat());
|
||||||
double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20;
|
double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; // TODO afdaöwelfunöwoaenf
|
||||||
|
|
||||||
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
||||||
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
||||||
|
@ -169,6 +170,7 @@ final class BedrockBlockActions {
|
||||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||||
// As of 1.16.210: item frame items are taken out here.
|
// As of 1.16.210: item frame items are taken out here.
|
||||||
// Survival also sends START_BREAK, but by attaching our process here adventure mode also works
|
// Survival also sends START_BREAK, but by attaching our process here adventure mode also works
|
||||||
|
GeyserImpl.getInstance().getLogger().warning("abort break, not creative - item frame???");
|
||||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||||
if (itemFrameEntity != null) {
|
if (itemFrameEntity != null) {
|
||||||
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||||
|
@ -180,6 +182,7 @@ final class BedrockBlockActions {
|
||||||
|
|
||||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
||||||
session.sendDownstreamGamePacket(abortBreakingPacket);
|
session.sendDownstreamGamePacket(abortBreakingPacket);
|
||||||
|
|
||||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||||
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
||||||
stopBreak.setPosition(vector.toFloat());
|
stopBreak.setPosition(vector.toFloat());
|
||||||
|
|
|
@ -27,156 +27,168 @@ package org.geysermc.geyser.util;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
|
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||||
|
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||||
import org.geysermc.geyser.level.block.Blocks;
|
import org.geysermc.geyser.level.block.Blocks;
|
||||||
import org.geysermc.geyser.level.block.type.Block;
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.session.cache.EntityEffectCache;
|
||||||
|
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||||
import org.geysermc.geyser.session.cache.tags.BlockTag;
|
import org.geysermc.geyser.session.cache.tags.BlockTag;
|
||||||
|
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData;
|
||||||
|
|
||||||
public final class BlockUtils {
|
public final class BlockUtils {
|
||||||
|
|
||||||
private static boolean correctTool(GeyserSession session, Block block, String itemToolType) {
|
public static float getBlockDestroyProgress(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) {
|
||||||
return switch (itemToolType) {
|
float destroySpeed = blockState.block().destroyTime();
|
||||||
case "axe" -> session.getTagCache().is(BlockTag.MINEABLE_AXE, block);
|
if (destroySpeed == -1) {
|
||||||
case "hoe" -> session.getTagCache().is(BlockTag.MINEABLE_HOE, block);
|
return 0;
|
||||||
case "pickaxe" -> session.getTagCache().is(BlockTag.MINEABLE_PICKAXE, block);
|
}
|
||||||
case "shears" -> session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block);
|
|
||||||
case "shovel" -> session.getTagCache().is(BlockTag.MINEABLE_SHOVEL, block);
|
int speedMultiplier = hasCorrectTool(session, blockState.block(), itemInHand) ? 30 : 100;
|
||||||
case "sword" -> block == Blocks.COBWEB;
|
return getPlayerDestroySpeed(session, blockState, itemInHand) / destroySpeed / speedMultiplier;
|
||||||
default -> {
|
}
|
||||||
session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType);
|
|
||||||
yield false;
|
private static boolean hasCorrectTool(GeyserSession session, Block block, GeyserItemStack stack) {
|
||||||
|
return !block.requiresCorrectToolForDrops() || isCorrectItemForDrops(session, block, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCorrectItemForDrops(GeyserSession session, Block block, GeyserItemStack stack) {
|
||||||
|
ToolData tool = stack.getComponent(DataComponentType.TOOL);
|
||||||
|
if (tool == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ToolData.Rule rule : tool.getRules()) {
|
||||||
|
if (rule.getCorrectForDrops() != null) {
|
||||||
|
GeyserHolderSet<Block> set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks());
|
||||||
|
if (session.getTagCache().is(set, block)) {
|
||||||
|
return rule.getCorrectForDrops();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) {
|
private static float getItemDestroySpeed(GeyserSession session, Block block, GeyserItemStack stack) {
|
||||||
if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0;
|
ToolData tool = stack.getComponent(DataComponentType.TOOL);
|
||||||
if (toolType.isEmpty()) return 1.0;
|
if (tool == null) {
|
||||||
return switch (toolTier) {
|
return 1f;
|
||||||
// https://minecraft.wiki/w/Breaking#Speed
|
}
|
||||||
case "wooden" -> 2.0;
|
|
||||||
case "stone" -> 4.0;
|
for (ToolData.Rule rule : tool.getRules()) {
|
||||||
case "iron" -> 6.0;
|
if (rule.getSpeed() != null) {
|
||||||
case "diamond" -> 8.0;
|
GeyserHolderSet<Block> set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks());
|
||||||
case "netherite" -> 9.0;
|
if (session.getTagCache().is(set, block)) {
|
||||||
case "golden" -> 12.0;
|
return rule.getSpeed();
|
||||||
default -> 1.0;
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tool.getDefaultMiningSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean canToolTierBreakBlock(GeyserSession session, Block block, String toolTier) {
|
private static float getPlayerDestroySpeed(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) {
|
||||||
if (toolTier.equals("netherite") || toolTier.equals("diamond")) {
|
float destroySpeed = getItemDestroySpeed(session, blockState.block(), itemInHand);
|
||||||
// As of 1.17, these tiers can mine everything that is mineable
|
EntityEffectCache effectCache = session.getEffectCache();
|
||||||
return true;
|
|
||||||
|
if (destroySpeed > 1.0F) {
|
||||||
|
destroySpeed += session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.MINING_EFFICIENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (toolTier) {
|
int miningSpeedMultiplier = getMiningSpeedAmplification(effectCache);
|
||||||
// Use intentional fall-throughs to check each tier with this block
|
if (miningSpeedMultiplier > 0) {
|
||||||
default:
|
destroySpeed *= miningSpeedMultiplier * 0.2F;
|
||||||
if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, block)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case "stone":
|
|
||||||
if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, block)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case "iron":
|
|
||||||
if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, block)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (effectCache.getMiningFatigue() != 0) {
|
||||||
|
float slowdown = switch (effectCache.getMiningFatigue()) {
|
||||||
|
case 1 -> 0.3F;
|
||||||
|
case 2 -> 0.09F;
|
||||||
|
case 3 -> 0.0027F;
|
||||||
|
default -> 8.1E-4F;
|
||||||
|
};
|
||||||
|
destroySpeed *= slowdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroySpeed *= session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.BLOCK_BREAK_SPEED);
|
||||||
|
if (session.getCollisionManager().isWaterInEyes()) {
|
||||||
|
destroySpeed *= session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.SUBMERGED_MINING_SPEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session.getPlayerEntity().isOnGround()) {
|
||||||
|
destroySpeed /= 5F;
|
||||||
|
}
|
||||||
|
|
||||||
|
return destroySpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://minecraft.wiki/w/Breaking
|
private static int getMiningSpeedAmplification(EntityEffectCache cache) {
|
||||||
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock,
|
return Math.max(cache.getHaste(), cache.getConduitPower());
|
||||||
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
|
}
|
||||||
boolean insideOfWaterWithoutAquaAffinity, boolean onGround) {
|
|
||||||
double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
|
|
||||||
double speed = 1.0 / baseTime;
|
|
||||||
|
|
||||||
if (correctTool) {
|
public int getDestroyStage(GeyserSession session) {
|
||||||
speed *= toolBreakTimeBonus(toolType, toolTier, isShearsEffective);
|
return session.getDestroyProgress() > 0F ? (int) session.getDestroyProgress() * 10 : -1;
|
||||||
speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1;
|
|
||||||
}
|
|
||||||
speed *= 1.0 + (0.2 * hasteLevel);
|
|
||||||
|
|
||||||
switch (miningFatigueLevel) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
speed -= (speed * 0.7);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
speed -= (speed * 0.91);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
speed -= (speed * 0.9973);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
speed -= (speed * 0.99919);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
|
|
||||||
if (!onGround) speed *= 0.2;
|
|
||||||
return 1.0 / speed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 1.21.4 this changed probably; no more tiers
|
// TODO 1.21.4 this changed probably; no more tiers
|
||||||
public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) {
|
public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) {
|
||||||
boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice
|
// boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice
|
||||||
boolean canHarvestWithHand = !block.requiresCorrectToolForDrops();
|
// boolean canHarvestWithHand = !block.requiresCorrectToolForDrops();
|
||||||
String toolType = "";
|
// String toolType = "";
|
||||||
String toolTier = "";
|
// String toolTier = "";
|
||||||
boolean correctTool = false;
|
// boolean correctTool = false;
|
||||||
boolean toolCanBreak = false;
|
// boolean toolCanBreak = false;
|
||||||
if (item.isTool()) {
|
// if (item.isTool()) {
|
||||||
toolType = item.getToolType();
|
// toolType = item.getToolType();
|
||||||
toolTier = item.getToolTier();
|
// toolTier = item.getToolTier();
|
||||||
correctTool = correctTool(session, block, toolType);
|
// correctTool = correctTool(session, block, toolType);
|
||||||
toolCanBreak = canToolTierBreakBlock(session, block, toolTier);
|
// toolCanBreak = canToolTierBreakBlock(session, block, toolTier);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(session, components, BedrockEnchantment.EFFICIENCY);
|
// int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(session, components, BedrockEnchantment.EFFICIENCY);
|
||||||
int hasteLevel = 0;
|
// int hasteLevel = 0;
|
||||||
int miningFatigueLevel = 0;
|
// int miningFatigueLevel = 0;
|
||||||
|
//
|
||||||
if (!isSessionPlayer) {
|
// if (!isSessionPlayer) {
|
||||||
// Another entity is currently mining; we have all the information we know
|
// // Another entity is currently mining; we have all the information we know
|
||||||
return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
// return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
||||||
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true);
|
// toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
hasteLevel = Math.max(session.getEffectCache().getHaste(), session.getEffectCache().getConduitPower());
|
// hasteLevel = Math.max(session.getEffectCache().getHaste(), session.getEffectCache().getConduitPower());
|
||||||
miningFatigueLevel = session.getEffectCache().getMiningFatigue();
|
// miningFatigueLevel = session.getEffectCache().getMiningFatigue();
|
||||||
|
//
|
||||||
boolean waterInEyes = session.getCollisionManager().isWaterInEyes();
|
// boolean waterInEyes = session.getCollisionManager().isWaterInEyes();
|
||||||
boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
|
// boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
|
||||||
ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1;
|
// ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1;
|
||||||
|
//
|
||||||
return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
// return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
||||||
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
|
// toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getSessionBreakTime(GeyserSession session, Block block) {
|
public static double getSessionBreakTime(GeyserSession session, Block block) {
|
||||||
PlayerInventory inventory = session.getPlayerInventory();
|
// PlayerInventory inventory = session.getPlayerInventory();
|
||||||
GeyserItemStack item = inventory.getItemInHand();
|
// GeyserItemStack item = inventory.getItemInHand();
|
||||||
ItemMapping mapping = ItemMapping.AIR;
|
// ItemMapping mapping = ItemMapping.AIR;
|
||||||
DataComponents components = null;
|
// DataComponents components = null;
|
||||||
if (item != null) {
|
// if (item != null) {
|
||||||
mapping = item.getMapping(session);
|
// mapping = item.getMapping(session);
|
||||||
components = item.getAllComponents();
|
// components = item.getAllComponents();
|
||||||
}
|
// }
|
||||||
return getBreakTime(session, block, mapping, components, true);
|
// return getBreakTime(session, block, mapping, components, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue