From ea3ea202a7f604451e51eb0bf0f453254820fb28 Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+JRoy@users.noreply.github.com> Date: Tue, 28 Jan 2025 14:26:39 -0500 Subject: [PATCH] Fix flight state between world teleports (#6012) Thanks to @electronicboy for the general fix. Fixes #4325 for Paper only :) Co-authored-by: Shane Freeder --- .../com/earth2me/essentials/Essentials.java | 4 ++++ .../essentials/EssentialsPlayerListener.java | 22 +++++++++++++++-- .../com/earth2me/essentials/ISettings.java | 2 ++ .../com/earth2me/essentials/Settings.java | 5 ++++ .../java/com/earth2me/essentials/User.java | 9 +++++++ Essentials/src/main/resources/config.yml | 5 ++++ .../net/ess3/provider/TickCountProvider.java | 8 +++++++ .../providers/PaperTickCountProvider.java | 24 +++++++++++++++++++ 8 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 providers/BaseProviders/src/main/java/net/ess3/provider/TickCountProvider.java create mode 100644 providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperTickCountProvider.java diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index 2ae888dec..0c90a3689 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -93,6 +93,7 @@ import net.ess3.provider.providers.PaperMaterialTagProvider; import net.ess3.provider.providers.PaperRecipeBookListener; import net.ess3.provider.providers.PaperSerializationProvider; import net.ess3.provider.providers.PaperServerStateProvider; +import net.ess3.provider.providers.PaperTickCountProvider; import net.ess3.provider.providers.PrehistoricPotionMetaProvider; import net.essentialsx.api.v2.services.BalanceTop; import net.essentialsx.api.v2.services.mail.MailService; @@ -421,6 +422,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { // Biome Key Provider providerFactory.registerProvider(PaperBiomeKeyProvider.class); + // Tick Count Provider + providerFactory.registerProvider(PaperTickCountProvider.class); + providerFactory.finalizeRegistration(); // Event Providers diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java index 65d495c99..84a190a02 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java @@ -20,6 +20,7 @@ import net.ess3.provider.CommandSendListenerProvider; import net.ess3.provider.FormattedCommandAliasProvider; import net.ess3.provider.InventoryViewProvider; import net.ess3.provider.KnownCommandsProvider; +import net.ess3.provider.TickCountProvider; import net.ess3.provider.providers.BukkitCommandSendListenerProvider; import net.ess3.provider.providers.PaperCommandSendListenerProvider; import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent; @@ -588,6 +589,17 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor { if (ess.getSettings().isTeleportInvulnerability()) { user.enableInvulnerabilityAfterTeleport(); } + + // Mitigation for https://github.com/EssentialsX/Essentials/issues/4325 + final TickCountProvider tickCountProvider = ess.provider(TickCountProvider.class); + if (tickCountProvider != null && ess.getSettings().isWorldChangePreserveFlying() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_17_R01)) { + if (user.isAuthorized("essentials.fly")) { + //noinspection DataFlowIssue - not real + if (event.getFrom().getWorld() != event.getTo().getWorld() && player.isFlying()) { + user.setFlightTick(tickCountProvider.getTickCount()); + } + } + } } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @@ -741,8 +753,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor { if (ess.getSettings().isWorldChangeFlyResetEnabled()) { if (user.getBase().getGameMode() != GameMode.CREATIVE - // COMPAT: String compare for 1.7.10 - && !user.getBase().getGameMode().name().equals("SPECTATOR") + && user.getBase().getGameMode() != GameMode.SPECTATOR && !user.isAuthorized("essentials.fly")) { user.getBase().setFallDistance(0f); user.getBase().setAllowFlight(false); @@ -765,6 +776,13 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor { } } } + + final TickCountProvider tickCountProvider = ess.provider(TickCountProvider.class); + if (tickCountProvider != null && user.getFlightTick() == tickCountProvider.getTickCount()) { + user.getBase().setAllowFlight(true); + user.getBase().setFlying(true); + } + user.setFlightTick(-1); } @EventHandler(priority = EventPriority.MONITOR) diff --git a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java index eedc49e01..691bd3286 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java @@ -344,6 +344,8 @@ public interface ISettings extends IConf { boolean isWorldChangeFlyResetEnabled(); + boolean isWorldChangePreserveFlying(); + boolean isWorldChangeSpeedResetEnabled(); long getCommandCooldownMs(String label); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index 4f490d584..4c09d57d4 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -1919,6 +1919,11 @@ public class Settings implements net.ess3.api.ISettings { return config.getBoolean("world-change-fly-reset", true); } + @Override + public boolean isWorldChangePreserveFlying() { + return config.getBoolean("world-change-preserve-flying", true); + } + @Override public boolean isWorldChangeSpeedResetEnabled() { return config.getBoolean("world-change-speed-reset", true); diff --git a/Essentials/src/main/java/com/earth2me/essentials/User.java b/Essentials/src/main/java/com/earth2me/essentials/User.java index ec823e206..c5cf54e45 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/User.java +++ b/Essentials/src/main/java/com/earth2me/essentials/User.java @@ -102,6 +102,7 @@ public class User extends UserData implements Comparable, IMessageRecipien // Misc private transient final List signCopy = Lists.newArrayList("", "", "", ""); private transient long lastVanishTime = System.currentTimeMillis(); + private transient int flightTick = -1; private String lastLocaleString; private Locale playerLocale; @@ -1299,4 +1300,12 @@ public class User extends UserData implements Comparable, IMessageRecipien } return toggleShout == null ? toggleShout = ess.getSettings().isShoutDefault() : toggleShout; } + + public int getFlightTick() { + return flightTick; + } + + public void setFlightTick(int flightTick) { + this.flightTick = flightTick; + } } diff --git a/Essentials/src/main/resources/config.yml b/Essentials/src/main/resources/config.yml index f10f99248..aece1efe2 100644 --- a/Essentials/src/main/resources/config.yml +++ b/Essentials/src/main/resources/config.yml @@ -224,6 +224,11 @@ socialspy-uses-displaynames: true # This will disable flight if the player does not have essentials.fly. world-change-fly-reset: true +# Starting in 1.17, Minecraft no longer preserves the abilities of a player when they change worlds. +# Setting this to true will make EssentialsX preserve if users flying when they change worlds. +# This will only work if the player has the essentials.fly permission. +world-change-preserve-flying: true + # When a player changes world, should we reset their speed according to their permissions? # This resets the player's speed to the default if they don't have essentials.speed. # If the player doesn't have essentials.speed.bypass, this resets their speed to the maximum specified above. diff --git a/providers/BaseProviders/src/main/java/net/ess3/provider/TickCountProvider.java b/providers/BaseProviders/src/main/java/net/ess3/provider/TickCountProvider.java new file mode 100644 index 000000000..9579d604e --- /dev/null +++ b/providers/BaseProviders/src/main/java/net/ess3/provider/TickCountProvider.java @@ -0,0 +1,8 @@ +package net.ess3.provider; + +import net.essentialsx.providers.NullableProvider; + +@NullableProvider +public interface TickCountProvider extends Provider { + int getTickCount(); +} diff --git a/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperTickCountProvider.java b/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperTickCountProvider.java new file mode 100644 index 000000000..aea1b3217 --- /dev/null +++ b/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperTickCountProvider.java @@ -0,0 +1,24 @@ +package net.ess3.provider.providers; + +import net.ess3.provider.TickCountProvider; +import net.essentialsx.providers.ProviderData; +import net.essentialsx.providers.ProviderTest; +import org.bukkit.Bukkit; + +@ProviderData(description = "Paper Tick Count Provider") +public class PaperTickCountProvider implements TickCountProvider { + @Override + public int getTickCount() { + return Bukkit.getCurrentTick(); + } + + @ProviderTest + public static boolean test() { + try { + Bukkit.class.getDeclaredMethod("getCurrentTick"); + return true; + } catch (final NoSuchMethodException ignored) { + return false; + } + } +}