Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Some minor fixes, fix own block breaking progress not showing on the player's end
Dieser Commit ist enthalten in:
Ursprung
a2184e4fae
Commit
a41d705c42
@ -685,13 +685,13 @@ public final class EntityDefinitions {
|
||||
.addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown)
|
||||
.addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos)
|
||||
.properties(new GeyserEntityProperties.Builder()
|
||||
.addEnum("minecraft:creaking_state",
|
||||
.addEnum(CreakingEntity.CREAKING_STATE,
|
||||
"neutral",
|
||||
"hostile_observed",
|
||||
"hostile_unobserved",
|
||||
"twitching",
|
||||
"crumbling")
|
||||
.addInt("minecraft:creaking_swaying_ticks", 0, 6)
|
||||
.addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6)
|
||||
.build())
|
||||
.build();
|
||||
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
|
||||
|
@ -38,8 +38,6 @@ import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
|
||||
import org.geysermc.geyser.item.type.DyeItem;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
@ -62,7 +60,7 @@ import java.util.UUID;
|
||||
|
||||
public class WolfEntity extends TameableEntity {
|
||||
private byte collarColor = 14; // Red - default
|
||||
private GeyserHolderSet<Item> repairableItems = null;
|
||||
private HolderSet repairableItems = null;
|
||||
private boolean isCurseOfBinding = false;
|
||||
|
||||
public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
@ -130,8 +128,7 @@ public class WolfEntity extends TameableEntity {
|
||||
public void setBody(ItemStack stack) {
|
||||
super.setBody(stack);
|
||||
isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE);
|
||||
HolderSet set = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE);
|
||||
repairableItems = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, set);
|
||||
repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -166,7 +163,7 @@ public class WolfEntity extends TameableEntity {
|
||||
return InteractiveTag.REMOVE_WOLF_ARMOR;
|
||||
}
|
||||
if (getFlag(EntityFlag.SITTING) &&
|
||||
session.getTagCache().is(repairableItems, itemInHand.asItem()) &&
|
||||
session.getTagCache().isItem(repairableItems, itemInHand.asItem()) &&
|
||||
this.body.isValid() && this.body.getTag() != null &&
|
||||
this.body.getTag().getInt("Damage") > 0) {
|
||||
return InteractiveTag.REPAIR_WOLF_ARMOR;
|
||||
|
@ -41,10 +41,21 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTyp
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/*
|
||||
* Relevant bits:
|
||||
* - LevelSoundEvent2Packet(sound=SPAWN, position=(233.5, 112.295, 4717.5), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false)
|
||||
* - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(233.0, 110.0, 4717.0), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false)
|
||||
* - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(235.0, 113.0, 4722.0), extraData=13734, identifier=, babySound=false, relativeVolumeDisabled=false)
|
||||
* - [11:29:34:768] [CLIENT BOUND] - LevelEventPacket(type=PARTICLE_MOB_BLOCK_SPAWN, position=(233.0, 110.0, 4717.0), data=769)
|
||||
*
|
||||
*/
|
||||
public class CreakingEntity extends MonsterEntity {
|
||||
|
||||
private Vector3i homePosition;
|
||||
|
||||
public static final String CREAKING_STATE = "minecraft:creaking_state";
|
||||
public static final String CREAKING_SWAYING_TICKS = "minecraft:creaking_swaying_ticks";
|
||||
|
||||
public CreakingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
@ -58,7 +69,7 @@ public class CreakingEntity extends MonsterEntity {
|
||||
|
||||
@Override
|
||||
public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) {
|
||||
propertyManager.add("minecraft:creaking_state", "neutral");
|
||||
propertyManager.add(CREAKING_STATE, "neutral");
|
||||
propertyManager.add("minecraft:creaking_swaying_ticks", 0);
|
||||
propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties());
|
||||
}
|
||||
@ -68,11 +79,11 @@ public class CreakingEntity extends MonsterEntity {
|
||||
setFlag(EntityFlag.BODY_ROTATION_BLOCKED, false);
|
||||
|
||||
// unfreeze sound? SoundEvent.UNFREEZE
|
||||
propertyManager.add("minecraft:creaking_state", "hostile_unobserved");
|
||||
propertyManager.add(CREAKING_STATE, "hostile_unobserved");
|
||||
updateBedrockEntityProperties();
|
||||
} else {
|
||||
setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true);
|
||||
propertyManager.add("minecraft:creaking_state", "hostile_observed");
|
||||
propertyManager.add(CREAKING_STATE, "hostile_observed");
|
||||
updateBedrockEntityProperties();
|
||||
}
|
||||
|
||||
@ -92,7 +103,7 @@ public class CreakingEntity extends MonsterEntity {
|
||||
// setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true);
|
||||
// setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true);
|
||||
} else {
|
||||
propertyManager.add("minecraft:creaking_state", "neutral");
|
||||
propertyManager.add(CREAKING_STATE, "neutral");
|
||||
}
|
||||
GeyserImpl.getInstance().getLogger().warning("set active; " + booleanEntityMetadata.toString());
|
||||
}
|
||||
@ -100,7 +111,7 @@ public class CreakingEntity extends MonsterEntity {
|
||||
public void setIsTearingDown(EntityMetadata<Boolean,? extends MetadataType<Boolean>> booleanEntityMetadata) {
|
||||
GeyserImpl.getInstance().getLogger().warning("set isTearingDown; " + booleanEntityMetadata.toString());
|
||||
if (booleanEntityMetadata.getValue()) {
|
||||
propertyManager.add("minecraft:creaking_state", "crumbling");
|
||||
propertyManager.add(CREAKING_STATE, "crumbling");
|
||||
updateBedrockEntityProperties();
|
||||
// LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||
// levelEventPacket.setType(ParticleType.CREAKING_CRUMBLE);
|
||||
|
@ -40,10 +40,7 @@ import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
@ -403,8 +400,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeyserHolderSet<Item> set = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, repairable);
|
||||
return session.getTagCache().is(set, material.asItem());
|
||||
return session.getTagCache().isItem(repairable, material.asItem());
|
||||
}
|
||||
|
||||
private boolean isRenaming(GeyserSession session, AnvilContainer anvilContainer, boolean bedrock) {
|
||||
|
@ -28,16 +28,19 @@ package org.geysermc.geyser.session.cache;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrays;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ -127,6 +130,34 @@ public final class TagCache {
|
||||
return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessible via the {@link #isItem(HolderSet, Item)} method.
|
||||
* @return true if the specified network ID is in the given {@link HolderSet} set.
|
||||
*/
|
||||
private <T> boolean is(@Nullable HolderSet holderSet, @NonNull JavaRegistryKey<T> registry, int id) {
|
||||
if (holderSet == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int[] entries = holderSet.resolve(key -> {
|
||||
if (key.value().startsWith("#")) {
|
||||
key = Key.key(key.namespace(), key.value().substring(1));
|
||||
}
|
||||
return getRaw(new Tag<>(registry, key));
|
||||
});
|
||||
|
||||
return contains(entries, id);
|
||||
}
|
||||
|
||||
public boolean isItem(@Nullable HolderSet holderSet, @NonNull Item item) {
|
||||
return is(holderSet, JavaRegistries.ITEM, item.javaId());
|
||||
}
|
||||
|
||||
public boolean isBlock(@Nullable HolderSet holderSet, @NonNull Block block) {
|
||||
return is(holderSet, JavaRegistries.BLOCK, block.javaId());
|
||||
}
|
||||
|
||||
|
||||
public <T> List<T> get(Tag<T> tag) {
|
||||
return mapRawArray(session, getRaw(tag), tag.registry());
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.TagCache;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -88,27 +87,6 @@ public final class GeyserHolderSet<T> {
|
||||
return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a MCPL {@link HolderSet} and turns it into a GeyserHolderSet.
|
||||
* @param registry the registry the HolderSet contains IDs from.
|
||||
* @param holderSet the HolderSet as the MCPL HolderSet object
|
||||
*/
|
||||
public static <T> GeyserHolderSet<T> convertHolderSet(@NonNull JavaRegistryKey<T> registry, @Nullable HolderSet holderSet) {
|
||||
if (holderSet == null) {
|
||||
return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
if (holderSet.getHolders() != null) {
|
||||
return new GeyserHolderSet<>(registry, holderSet.getHolders());
|
||||
}
|
||||
|
||||
if (holderSet.getLocation() != null) {
|
||||
return new GeyserHolderSet<>(registry, new Tag<>(registry, holderSet.getLocation()));
|
||||
}
|
||||
|
||||
throw new IllegalStateException("HolderSet must have a tag or a list of IDs! " + holderSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a HolderSet from an object from NBT.
|
||||
*
|
||||
|
@ -89,7 +89,7 @@ final class BedrockBlockActions {
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; // TODO afdaöwelfunöwoaenf
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, BlockState.of(blockState).block());
|
||||
|
||||
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
||||
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
||||
@ -137,7 +137,7 @@ final class BedrockBlockActions {
|
||||
Direction direction = Direction.VALUES[blockFace];
|
||||
spawnBlockBreakParticles(session, direction, vector, breakingBlockState);
|
||||
|
||||
double breakTime = BlockUtils.getSessionBreakTime(session, breakingBlockState.block()) * 20;
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, breakingBlockState.block());
|
||||
// If the block is custom, we must keep track of when it should break ourselves
|
||||
long blockBreakStartTime = session.getBlockBreakStartTime();
|
||||
if (blockBreakStartTime != 0) {
|
||||
|
@ -40,7 +40,7 @@ import java.util.Set;
|
||||
@Translator(packet = ClientboundSelectKnownPacks.class)
|
||||
public class JavaSelectKnownPacksTranslator extends PacketTranslator<ClientboundSelectKnownPacks> {
|
||||
// todo: dump from client?
|
||||
private static final Set<String> KNOWN_PACK_IDS = Set.of("core", "winter_drop", "trade_rebalance", "redstone_experiments", "minecart_improvements");
|
||||
private static final Set<String> KNOWN_PACK_IDS = Set.of("core", "trade_rebalance", "redstone_experiments", "minecart_improvements");
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSelectKnownPacks packet) {
|
||||
|
@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.EvokerFangsEntity;
|
||||
@ -294,6 +295,8 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
|
||||
creakingEntity.createParticleBeam();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GeyserImpl.getInstance().getLogger().debug("unhandled entity event: " + packet);
|
||||
}
|
||||
|
||||
if (entityEventPacket.getType() != null) {
|
||||
|
@ -41,7 +41,12 @@ public class JavaBlockDestructionTranslator extends PacketTranslator<Clientbound
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundBlockDestructionPacket packet) {
|
||||
int state = session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
|
||||
int breakTime = (int) (65535 / Math.ceil(BlockUtils.getBreakTime(session, BlockState.of(state).block(), ItemMapping.AIR, null, false) * 20));
|
||||
int breakTime = 12; //(int) (65535 / Math.ceil(BlockUtils.getBreakTime(session, BlockState.of(state).block(), ItemMapping.AIR, null, false)));
|
||||
// TODO we need to send a "total" time to Bedrock.
|
||||
// Current plan:
|
||||
// - start with block destroy time (if applicable)
|
||||
// - track the time in ticks between stages
|
||||
// - attempt to "extrapolate" to a value for Bedrock
|
||||
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||
levelEventPacket.setPosition(packet.getPosition().toFloat());
|
||||
levelEventPacket.setType(LevelEvent.BLOCK_START_BREAK);
|
||||
|
@ -25,33 +25,31 @@
|
||||
|
||||
package org.geysermc.geyser.util;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
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.type.ItemMapping;
|
||||
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.GeyserHolderSet;
|
||||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||
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.ToolData;
|
||||
|
||||
public final class BlockUtils {
|
||||
|
||||
public static float getBlockDestroyProgress(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) {
|
||||
float destroySpeed = blockState.block().destroyTime();
|
||||
/**
|
||||
* Returns the total mining progress added by mining the block in a single tick
|
||||
* @return the mining progress added by this tick.
|
||||
*/
|
||||
public static float getBlockMiningProgressPerTick(GeyserSession session, Block block, GeyserItemStack itemInHand) {
|
||||
float destroySpeed = block.destroyTime();
|
||||
if (destroySpeed == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int speedMultiplier = hasCorrectTool(session, blockState.block(), itemInHand) ? 30 : 100;
|
||||
return getPlayerDestroySpeed(session, blockState, itemInHand) / destroySpeed / speedMultiplier;
|
||||
int speedMultiplier = hasCorrectTool(session, block, itemInHand) ? 30 : 100;
|
||||
return getPlayerDestroySpeed(session, block, itemInHand) / destroySpeed / speedMultiplier;
|
||||
}
|
||||
|
||||
private static boolean hasCorrectTool(GeyserSession session, Block block, GeyserItemStack stack) {
|
||||
@ -66,8 +64,7 @@ public final class BlockUtils {
|
||||
|
||||
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)) {
|
||||
if (session.getTagCache().isBlock(rule.getBlocks(), block)) {
|
||||
return rule.getCorrectForDrops();
|
||||
}
|
||||
}
|
||||
@ -84,8 +81,7 @@ public final class BlockUtils {
|
||||
|
||||
for (ToolData.Rule rule : tool.getRules()) {
|
||||
if (rule.getSpeed() != null) {
|
||||
GeyserHolderSet<Block> set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks());
|
||||
if (session.getTagCache().is(set, block)) {
|
||||
if (session.getTagCache().isBlock(rule.getBlocks(), block)) {
|
||||
return rule.getSpeed();
|
||||
}
|
||||
}
|
||||
@ -94,8 +90,8 @@ public final class BlockUtils {
|
||||
return tool.getDefaultMiningSpeed();
|
||||
}
|
||||
|
||||
private static float getPlayerDestroySpeed(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) {
|
||||
float destroySpeed = getItemDestroySpeed(session, blockState.block(), itemInHand);
|
||||
private static float getPlayerDestroySpeed(GeyserSession session, Block block, GeyserItemStack itemInHand) {
|
||||
float destroySpeed = getItemDestroySpeed(session, block, itemInHand);
|
||||
EntityEffectCache effectCache = session.getEffectCache();
|
||||
|
||||
if (destroySpeed > 1.0F) {
|
||||
@ -133,17 +129,8 @@ public final class BlockUtils {
|
||||
return Math.max(cache.getHaste(), cache.getConduitPower());
|
||||
}
|
||||
|
||||
public int getDestroyStage(GeyserSession session) {
|
||||
return session.getDestroyProgress() > 0F ? (int) session.getDestroyProgress() * 10 : -1;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return 0.0; // TODO 1.21.4
|
||||
}
|
||||
|
||||
public static double getSessionBreakTime(GeyserSession session, Block block) {
|
||||
return 0.0; // TODO 1.21.4
|
||||
public static double getSessionBreakTimeTicks(GeyserSession session, Block block) {
|
||||
return Math.ceil(1 / getBlockMiningProgressPerTick(session, block, session.getPlayerInventory().getItemInHand()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren