Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-03 14:50:19 +01:00
Fix break time while submerged in water (#3110)
* Fix break time while submerged in water * Review stuff * LAYERS -> LEVELS
Dieser Commit ist enthalten in:
Ursprung
f2f894b1d1
Commit
dc810f1d39
@ -99,19 +99,9 @@ public class FishingHookEntity extends ThrowableEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
double waterHeight = BlockStateValues.getWaterHeight(blockID);
|
||||||
if (BlockRegistries.WATERLOGGED.get().contains(blockID)) {
|
if (waterHeight != -1 && position.getY() <= (iter.getY() + waterHeight)) {
|
||||||
waterLevel = 0;
|
touchingWater = true;
|
||||||
}
|
|
||||||
if (waterLevel >= 0) {
|
|
||||||
double waterMaxY = iter.getY() + 1 - (waterLevel + 1) / 9.0;
|
|
||||||
// Falling water is a full block
|
|
||||||
if (waterLevel >= 8) {
|
|
||||||
waterMaxY = iter.getY() + 1;
|
|
||||||
}
|
|
||||||
if (position.getY() <= waterMaxY) {
|
|
||||||
touchingWater = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ public final class BlockStateValues {
|
|||||||
public static int JAVA_SPAWNER_ID;
|
public static int JAVA_SPAWNER_ID;
|
||||||
public static int JAVA_WATER_ID;
|
public static int JAVA_WATER_ID;
|
||||||
|
|
||||||
|
public static final int NUM_WATER_LEVELS = 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the block state contains Bedrock block information
|
* Determines if the block state contains Bedrock block information
|
||||||
*
|
*
|
||||||
@ -449,7 +451,6 @@ public final class BlockStateValues {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the level of water from the block state.
|
* Get the level of water from the block state.
|
||||||
* This is used in FishingHookEntity to create splash sounds when the hook hits the water.
|
|
||||||
*
|
*
|
||||||
* @param state BlockState of the block
|
* @param state BlockState of the block
|
||||||
* @return The water level or -1 if the block isn't water
|
* @return The water level or -1 if the block isn't water
|
||||||
@ -458,6 +459,30 @@ public final class BlockStateValues {
|
|||||||
return WATER_LEVEL.getOrDefault(state, -1);
|
return WATER_LEVEL.getOrDefault(state, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the height of water from the block state
|
||||||
|
* This is used in FishingHookEntity to create splash sounds when the hook hits the water. In addition,
|
||||||
|
* CollisionManager uses this to determine if the player's eyes are in water.
|
||||||
|
*
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return The water height or -1 if the block does not contain water
|
||||||
|
*/
|
||||||
|
public static double getWaterHeight(int state) {
|
||||||
|
int waterLevel = BlockStateValues.getWaterLevel(state);
|
||||||
|
if (BlockRegistries.WATERLOGGED.get().contains(state)) {
|
||||||
|
waterLevel = 0;
|
||||||
|
}
|
||||||
|
if (waterLevel >= 0) {
|
||||||
|
double waterHeight = 1 - (waterLevel + 1) / ((double) NUM_WATER_LEVELS);
|
||||||
|
// Falling water is a full block
|
||||||
|
if (waterLevel >= 8) {
|
||||||
|
waterHeight = 1;
|
||||||
|
}
|
||||||
|
return waterHeight;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the slipperiness of a block.
|
* Get the slipperiness of a block.
|
||||||
* This is used in ItemEntity to calculate the friction on an item as it slides across the ground
|
* This is used in ItemEntity to calculate the friction on an item as it slides across the ground
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.level.physics;
|
package org.geysermc.geyser.level.physics;
|
||||||
|
|
||||||
|
import com.nukkitx.math.GenericMath;
|
||||||
import com.nukkitx.math.vector.Vector3d;
|
import com.nukkitx.math.vector.Vector3d;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
@ -405,6 +406,18 @@ public class CollisionManager {
|
|||||||
return session.getGeyser().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockStateValues.JAVA_WATER_ID;
|
return session.getGeyser().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockStateValues.JAVA_WATER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isWaterInEyes() {
|
||||||
|
double eyeX = playerBoundingBox.getMiddleX();
|
||||||
|
double eyeY = playerBoundingBox.getMiddleY() - playerBoundingBox.getSizeY() / 2d + session.getEyeHeight();
|
||||||
|
double eyeZ = playerBoundingBox.getMiddleZ();
|
||||||
|
|
||||||
|
eyeY -= 1 / ((double) BlockStateValues.NUM_WATER_LEVELS); // Subtract the height of one water layer
|
||||||
|
int blockID = session.getGeyser().getWorldManager().getBlockAt(session, GenericMath.floor(eyeX), GenericMath.floor(eyeY), GenericMath.floor(eyeZ));
|
||||||
|
double waterHeight = BlockStateValues.getWaterHeight(blockID);
|
||||||
|
|
||||||
|
return waterHeight != -1 && eyeY < (Math.floor(eyeY) + waterHeight);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates scaffolding entity flags
|
* Updates scaffolding entity flags
|
||||||
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side
|
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side
|
||||||
|
@ -100,6 +100,7 @@ import org.geysermc.geyser.GeyserImpl;
|
|||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.command.CommandSender;
|
import org.geysermc.geyser.command.CommandSender;
|
||||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||||
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;
|
||||||
@ -1767,6 +1768,17 @@ public class GeyserSession implements GeyserConnection, CommandSender {
|
|||||||
sendUpstreamPacket(packet);
|
sendUpstreamPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getEyeHeight() {
|
||||||
|
return switch (pose) {
|
||||||
|
case SNEAKING -> 1.27f;
|
||||||
|
case SWIMMING,
|
||||||
|
FALL_FLYING, // Elytra
|
||||||
|
SPIN_ATTACK -> 0.4f; // Trident spin attack
|
||||||
|
case SLEEPING -> 0.2f;
|
||||||
|
default -> EntityDefinitions.PLAYER.offset();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public MinecraftCodecHelper getCodecHelper() {
|
public MinecraftCodecHelper getCodecHelper() {
|
||||||
return (MinecraftCodecHelper) this.downstream.getCodecHelper();
|
return (MinecraftCodecHelper) this.downstream.getCodecHelper();
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
|
|
||||||
// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
|
// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
|
||||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - getEyeHeight(session));
|
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||||
|
|
||||||
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||||
|
|
||||||
@ -608,7 +608,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
// Use the bounding box's position since we need the player's position seen by the Java server
|
// Use the bounding box's position since we need the player's position seen by the Java server
|
||||||
Vector3d playerPosition = session.getCollisionManager().getPlayerBoundingBox().getBottomCenter();
|
Vector3d playerPosition = session.getCollisionManager().getPlayerBoundingBox().getBottomCenter();
|
||||||
float xDiff = (float) (target.getX() - playerPosition.getX());
|
float xDiff = (float) (target.getX() - playerPosition.getX());
|
||||||
float yDiff = (float) (target.getY() - (playerPosition.getY() + getEyeHeight(session)));
|
float yDiff = (float) (target.getY() - (playerPosition.getY() + session.getEyeHeight()));
|
||||||
float zDiff = (float) (target.getZ() - playerPosition.getZ());
|
float zDiff = (float) (target.getZ() - playerPosition.getZ());
|
||||||
|
|
||||||
// First triangle on the XZ plane
|
// First triangle on the XZ plane
|
||||||
@ -637,15 +637,4 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
}, 150, TimeUnit.MILLISECONDS));
|
}, 150, TimeUnit.MILLISECONDS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getEyeHeight(GeyserSession session) {
|
|
||||||
return switch (session.getPose()) {
|
|
||||||
case SNEAKING -> 1.27f;
|
|
||||||
case SWIMMING,
|
|
||||||
FALL_FLYING, // Elytra
|
|
||||||
SPIN_ATTACK -> 0.4f; // Trident spin attack
|
|
||||||
case SLEEPING -> 0.2f;
|
|
||||||
default -> EntityDefinitions.PLAYER.offset();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ import org.geysermc.geyser.registry.type.ItemMapping;
|
|||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class BlockUtils {
|
public final class BlockUtils {
|
||||||
|
|
||||||
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) {
|
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) {
|
||||||
@ -101,7 +103,7 @@ public final class BlockUtils {
|
|||||||
// https://minecraft.gamepedia.com/Breaking
|
// https://minecraft.gamepedia.com/Breaking
|
||||||
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock,
|
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock,
|
||||||
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
|
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
|
||||||
boolean insideOfWaterWithoutAquaAffinity, boolean outOfWaterButNotOnGround, boolean insideWaterAndNotOnGround) {
|
boolean insideOfWaterWithoutAquaAffinity, boolean onGround) {
|
||||||
double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
|
double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
|
||||||
double speed = 1.0 / baseTime;
|
double speed = 1.0 / baseTime;
|
||||||
|
|
||||||
@ -129,12 +131,11 @@ public final class BlockUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
|
if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
|
||||||
if (outOfWaterButNotOnGround) speed *= 0.2;
|
if (!onGround) speed *= 0.2;
|
||||||
if (insideWaterAndNotOnGround) speed *= 0.2;
|
|
||||||
return 1.0 / speed;
|
return 1.0 / speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, CompoundTag nbtData, boolean isSessionPlayer) {
|
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable CompoundTag nbtData, boolean isSessionPlayer) {
|
||||||
boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice
|
boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice
|
||||||
boolean canHarvestWithHand = blockMapping.isCanBreakWithHand();
|
boolean canHarvestWithHand = blockMapping.isCanBreakWithHand();
|
||||||
String toolType = "";
|
String toolType = "";
|
||||||
@ -154,36 +155,28 @@ public final class BlockUtils {
|
|||||||
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(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
||||||
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false,
|
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true);
|
||||||
false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 isInWater = session.getCollisionManager().isPlayerInWater();
|
boolean waterInEyes = session.getCollisionManager().isWaterInEyes();
|
||||||
|
boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
|
||||||
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
|
||||||
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
||||||
|
|
||||||
boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround());
|
|
||||||
boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround();
|
|
||||||
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
|
||||||
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity,
|
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
|
||||||
outOfWaterButNotOnGround, insideWaterNotOnGround);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) {
|
public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) {
|
||||||
PlayerInventory inventory = session.getPlayerInventory();
|
PlayerInventory inventory = session.getPlayerInventory();
|
||||||
GeyserItemStack item = inventory.getItemInHand();
|
GeyserItemStack item = inventory.getItemInHand();
|
||||||
ItemMapping mapping;
|
ItemMapping mapping = ItemMapping.AIR;
|
||||||
CompoundTag nbtData;
|
CompoundTag nbtData = null;
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
mapping = item.getMapping(session);
|
mapping = item.getMapping(session);
|
||||||
nbtData = item.getNbt();
|
nbtData = item.getNbt();
|
||||||
} else {
|
|
||||||
mapping = ItemMapping.AIR;
|
|
||||||
nbtData = new CompoundTag("");
|
|
||||||
}
|
}
|
||||||
return getBreakTime(session, blockMapping, mapping, nbtData, true);
|
return getBreakTime(session, blockMapping, mapping, nbtData, true);
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren