diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishConfig.java index 82ae66b73..9fcfc6f18 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishConfig.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishConfig.java @@ -19,6 +19,9 @@ public class VanishConfig extends OkaeriConfig implements VanishSettings { @Comment("Give night vision effect to vanished players") public boolean nightVision = true; + @Comment("Allow vanished players to fly while vanish is enabled") + public boolean allowFlight = true; + @Comment("Should vanished players be able to silently view other players' inventories?") public boolean silentInventoryAccess = true; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishSettings.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishSettings.java index 4d3ed2139..0a90e77dc 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishSettings.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/VanishSettings.java @@ -10,6 +10,8 @@ public interface VanishSettings { boolean nightVision(); + boolean allowFlight(); + boolean silentInventoryAccess(); boolean glowEffect(); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightController.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightController.java new file mode 100644 index 000000000..2e309ed7b --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightController.java @@ -0,0 +1,102 @@ +package com.eternalcode.core.feature.vanish.controller; + +import com.eternalcode.core.feature.vanish.VanishService; +import com.eternalcode.core.feature.vanish.VanishSettings; +import com.eternalcode.core.feature.vanish.event.DisableVanishEvent; +import com.eternalcode.core.feature.vanish.event.EnableVanishEvent; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Controller; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +@Controller +class VanishFlightController implements Listener { + + private final Map previousFlightStates = new HashMap<>(); + + private final VanishSettings settings; + private final Server server; + + @Inject + VanishFlightController(VanishSettings settings, Server server) { + this.settings = settings; + this.server = server; + } + + @EventHandler(ignoreCancelled = true) + void onEnable(EnableVanishEvent event) { + if (!this.settings.allowFlight()) { + return; + } + + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + + this.previousFlightStates.putIfAbsent( + playerId, + new FlightState(player.getAllowFlight(), player.isFlying()) + ); + + player.setAllowFlight(true); + player.setFlying(true); + } + + @EventHandler(ignoreCancelled = true) + void onDisable(DisableVanishEvent event) { + this.restoreFlightState(event.getPlayer()); + } + + void synchronize(VanishService vanishService) { + Iterator> iterator = this.previousFlightStates.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + UUID playerId = entry.getKey(); + Player player = this.server.getPlayer(playerId); + + if (player == null || !player.isOnline()) { + iterator.remove(); + continue; + } + + if (!this.settings.allowFlight() || !vanishService.isVanished(playerId)) { + entry.getValue().apply(player); + iterator.remove(); + continue; + } + + if (!player.getAllowFlight()) { + player.setAllowFlight(true); + } + } + } + + private void restoreFlightState(Player player) { + FlightState previousFlightState = this.previousFlightStates.remove(player.getUniqueId()); + if (previousFlightState == null) { + return; + } + + previousFlightState.apply(player); + } + + private record FlightState(boolean allowFlight, boolean flying) { + + private void apply(Player player) { + if (this.allowFlight) { + player.setAllowFlight(true); + player.setFlying(this.flying); + return; + } + + player.setFlying(false); + player.setAllowFlight(false); + } + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightWatchdogTask.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightWatchdogTask.java new file mode 100644 index 000000000..2506605c4 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/vanish/controller/VanishFlightWatchdogTask.java @@ -0,0 +1,24 @@ +package com.eternalcode.core.feature.vanish.controller; + +import com.eternalcode.core.feature.vanish.VanishService; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Task; +import java.util.concurrent.TimeUnit; + +@Task(period = 5, delay = 5, unit = TimeUnit.SECONDS) +class VanishFlightWatchdogTask implements Runnable { + + private final VanishService vanishService; + private final VanishFlightController vanishFlightController; + + @Inject + VanishFlightWatchdogTask(VanishService vanishService, VanishFlightController vanishFlightController) { + this.vanishService = vanishService; + this.vanishFlightController = vanishFlightController; + } + + @Override + public void run() { + this.vanishFlightController.synchronize(this.vanishService); + } +}