3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-09-08 20:43:04 +02: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:
David Choo 2022-07-02 21:17:14 -04:00 committet von GitHub
Ursprung f2f894b1d1
Commit dc810f1d39
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
6 geänderte Dateien mit 67 neuen und 45 gelöschten Zeilen

Datei anzeigen

@ -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;
}
} }
} }

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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();
} }

Datei anzeigen

@ -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();
};
}
} }

Datei anzeigen

@ -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);
} }