diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java index b09a9fcc5..25bbdbd3c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java @@ -130,7 +130,7 @@ public class ThrowableEntity extends Entity implements Tickable { case SNOWBALL: case EGG: case ENDER_PEARL: - return 0.0325f; + return 0.03f; case LLAMA_SPIT: return 0.06f; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index fb7aa8bff..2b2062ad1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -40,11 +40,13 @@ import java.util.UUID; */ public class ThrowableItemEntity extends ThrowableEntity { private boolean invisible; + private int age; public ThrowableItemEntity(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); setFlag(EntityFlag.INVISIBLE, true); invisible = false; + age = 0; } @Override @@ -55,9 +57,11 @@ public class ThrowableItemEntity extends ThrowableEntity { } private void checkVisibility() { - Vector3f playerPos = session.getPlayerEntity().getPosition(); + age++; + Vector3f playerPos = session.getPlayerEntity().getPosition().sub(0, session.getPlayerEntity().getDefinition().offset(),0); + // Prevent projectiles from blocking the player's screen - setInvisible(position.distanceSquared(playerPos) < 9); + setInvisible((age <= 2 && !session.isTickingFrozen()) || (playerPos.distanceSquared(position.add(0, definition.offset(), 0)) < 12.25)); if (invisible != getFlag(EntityFlag.INVISIBLE)) { setFlag(EntityFlag.INVISIBLE, invisible); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index a00b85a67..30e42756f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -618,7 +618,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Stores cookies sent by the Java server. */ @Setter - @Getter private Map cookies = new Object2ObjectOpenHashMap<>(); private final GeyserCameraData cameraData; @@ -627,6 +626,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private MinecraftProtocol protocol; + @Getter + private int millisecondsPerTick = 50; private boolean tickingFrozen = false; /** * The amount of ticks requested by the server that the game should proceed with, even if the game tick loop is frozen. @@ -857,31 +858,31 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } task.cleanup(); // player is online -> remove pending authentication immediately return task.getAuthentication().handle((result, ex) -> { - if (ex != null) { - geyser.getLogger().error("Failed to log in with Microsoft code!", ex); - disconnect(ex.toString()); - return false; - } + if (ex != null) { + geyser.getLogger().error("Failed to log in with Microsoft code!", ex); + disconnect(ex.toString()); + return false; + } - StepMCProfile.MCProfile mcProfile = result.session().getMcProfile(); - StepMCToken.MCToken mcToken = mcProfile.getMcToken(); + StepMCProfile.MCProfile mcProfile = result.session().getMcProfile(); + StepMCToken.MCToken mcToken = mcProfile.getMcToken(); - this.protocol = new MinecraftProtocol( - new GameProfile(mcProfile.getId(), mcProfile.getName()), - mcToken.getAccessToken() - ); + this.protocol = new MinecraftProtocol( + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() + ); - try { - connectDownstream(); - } catch (Throwable t) { - t.printStackTrace(); - return false; - } + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + return false; + } - // Save our auth chain for later use - geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session()))); - return true; - }).getNow(false); + // Save our auth chain for later use + geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session()))); + return true; + }).getNow(false); } /** @@ -902,7 +903,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE; // Start ticking - tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); + tickThread = eventLoop.scheduleAtFixedRate(this::tick, millisecondsPerTick, millisecondsPerTick, TimeUnit.MILLISECONDS); this.protocol.setUseDefaultListeners(false); @@ -1220,9 +1221,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void updateTickingState(float tickRate, boolean frozen) { - tickThread.cancel(true); + tickThread.cancel(false); this.tickingFrozen = frozen; - tickThread = eventLoop.scheduleAtFixedRate(this::tick, Math.round(1000 / tickRate), Math.round(1000 / tickRate), TimeUnit.MILLISECONDS); + millisecondsPerTick = Math.round(1000.0f / MathUtils.clamp(tickRate, 1.0f, 10000.0f)); + tickThread = eventLoop.scheduleAtFixedRate(this::tick, millisecondsPerTick, millisecondsPerTick, TimeUnit.MILLISECONDS); } /** @@ -1784,7 +1786,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Send a gamerule value to the client * * @param gameRule The gamerule to send - * @param value The value of the gamerule + * @param value The value of the gamerule */ public void sendGameRule(String gameRule, Object value) { GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java index 35ad942d0..d91e7e0fe 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java @@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator session.useItem(Hand.MAIN_HAND), - 50, TimeUnit.MILLISECONDS); + session.getMillisecondsPerTick(), TimeUnit.MILLISECONDS); } if (oldItem.getJavaId() != newItem.getJavaId()) { diff --git a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java index c020e96b2..071b24455 100644 --- a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java @@ -50,6 +50,7 @@ public class CooldownUtils { /** * Starts sending the fake cooldown to the Bedrock client. If the cooldown is not disabled, the sent type is the cooldownPreference in {@link PreferencesCache} + * * @param session GeyserSession */ public static void sendCooldown(GeyserSession session) { @@ -83,6 +84,7 @@ public class CooldownUtils { /** * Keeps updating the cooldown until the bar is complete. + * * @param session GeyserSession * @param sessionPreference The type of cooldown the client prefers * @param lastHitTime The time of the last hit. Used to gauge how long the cooldown is taking. @@ -102,7 +104,7 @@ public class CooldownUtils { session.sendUpstreamPacket(titlePacket); if (hasCooldown(session)) { session.scheduleInEventLoop(() -> - computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 + computeCooldown(session, sessionPreference, lastHitTime), session.getMillisecondsPerTick(), TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 } else { SetTitlePacket removeTitlePacket = new SetTitlePacket(); removeTitlePacket.setType(SetTitlePacket.Type.CLEAR); @@ -115,8 +117,8 @@ public class CooldownUtils { private static boolean hasCooldown(GeyserSession session) { long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1.5); - return cooldown < 1.1; + double cooldown = restrain(((double) time) * session.getAttackSpeed() / (session.getMillisecondsPerTick() * 20d), 1.5); + return cooldown < 1.0; } @@ -128,7 +130,7 @@ public class CooldownUtils { private static String getTitle(GeyserSession session) { long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1); + double cooldown = restrain(((double) time) * session.getAttackSpeed() / (session.getMillisecondsPerTick() * 20d), 1); int darkGrey = (int) Math.floor(10d * cooldown); int grey = 10 - darkGrey; @@ -157,7 +159,6 @@ public class CooldownUtils { * Convert the CooldownType string (from config) to the enum, DISABLED on fail * * @param name CooldownType string - * * @return The converted CooldownType */ public static CooldownType getByName(String name) {