Fix flight state between world teleports (#6012)

Thanks to @electronicboy for the general fix.

Fixes #4325 for Paper only :)

Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
This commit is contained in:
Josh Roy 2025-01-28 14:26:39 -05:00 committed by GitHub
parent 62fb6a16d4
commit ea3ea202a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 77 additions and 2 deletions

View File

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

View File

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

View File

@ -344,6 +344,8 @@ public interface ISettings extends IConf {
boolean isWorldChangeFlyResetEnabled();
boolean isWorldChangePreserveFlying();
boolean isWorldChangeSpeedResetEnabled();
long getCommandCooldownMs(String label);

View File

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

View File

@ -102,6 +102,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
// Misc
private transient final List<String> 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<User>, IMessageRecipien
}
return toggleShout == null ? toggleShout = ess.getSettings().isShoutDefault() : toggleShout;
}
public int getFlightTick() {
return flightTick;
}
public void setFlightTick(int flightTick) {
this.flightTick = flightTick;
}
}

View File

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

View File

@ -0,0 +1,8 @@
package net.ess3.provider;
import net.essentialsx.providers.NullableProvider;
@NullableProvider
public interface TickCountProvider extends Provider {
int getTickCount();
}

View File

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