Skip to content

Commit

Permalink
Adds tempflight command. (#75)
Browse files Browse the repository at this point in the history
* Adds tempflight command.

Closes TownyAdvanced/Towny#7252

TODO:

add feedback messages,
test Placeholder,
test saving every 10 cycles,
test logging out storing remaining flight, logging in restoring it.

* Clean up todo requirements and fix bugs found along the way.
  • Loading branch information
LlmDl authored Feb 14, 2024
1 parent c067d95 commit c9697b3
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 16 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmail.llmdlio</groupId>
<artifactId>TownyFlight</artifactId>
<version>1.9.0</version>
<version>1.10.0</version>
<name>TownyFlight</name>
<description>A flight plugin for Towny servers.</description>
<properties>
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/gmail/llmdlio/townyflight/TownyFlight.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.palmergames.bukkit.towny.scheduling.TaskScheduler;
import com.palmergames.bukkit.towny.scheduling.impl.BukkitTaskScheduler;
import com.palmergames.bukkit.towny.scheduling.impl.FoliaTaskScheduler;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
Expand All @@ -20,6 +23,9 @@
import com.gmail.llmdlio.townyflight.listeners.PlayerTeleportListener;
import com.gmail.llmdlio.townyflight.listeners.TownStatusScreenListener;
import com.gmail.llmdlio.townyflight.listeners.TownUnclaimListener;
import com.gmail.llmdlio.townyflight.tasks.TaskHandler;
import com.gmail.llmdlio.townyflight.tasks.TempFlightTask;
import com.gmail.llmdlio.townyflight.util.MetaData;
import com.palmergames.bukkit.util.Version;

public class TownyFlight extends JavaPlugin {
Expand Down Expand Up @@ -57,6 +63,9 @@ public void onEnable() {
registerCommands();
getLogger().info("Towny version " + townyVersion + " found.");
getLogger().info(this.getDescription().getFullName() + " by LlmDl Enabled.");

cycleTimerTasksOn();
reGrantTempFlightToOnlinePlayer();
}

public static TownyFlight getPlugin() {
Expand Down Expand Up @@ -127,6 +136,23 @@ private void registerCommands() {
getCommand("tfly").setExecutor(new TownyFlightCommand(this));
}

private void cycleTimerTasksOn() {
cycleTimerTasksOff();
TaskHandler.toggleTempFlightTask(true);
}

private void cycleTimerTasksOff() {
TaskHandler.toggleTempFlightTask(false);
}

private void reGrantTempFlightToOnlinePlayer() {
for (Player player : Bukkit.getOnlinePlayers()) {
long seconds = MetaData.getSeconds(player.getUniqueId());
if (seconds > 0L)
TempFlightTask.addPlayerTempFlightSeconds(player.getUniqueId(), seconds);
}
}

public TaskScheduler getScheduler() {
return this.scheduler;
}
Expand Down
29 changes: 15 additions & 14 deletions src/main/java/com/gmail/llmdlio/townyflight/TownyFlightAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.gmail.goosius.siegewar.SiegeController;
import com.gmail.goosius.siegewar.enums.SiegeStatus;
import com.gmail.llmdlio.townyflight.config.Settings;
import com.gmail.llmdlio.townyflight.tasks.TempFlightTask;
import com.gmail.llmdlio.townyflight.util.Message;
import com.gmail.llmdlio.townyflight.util.MetaData;
import com.gmail.llmdlio.townyflight.util.Permission;
Expand Down Expand Up @@ -52,24 +53,17 @@ public static TownyFlightAPI getInstance() {
* @return true if the {@link Player} is allowed to fly.
**/
public boolean canFly(Player player, boolean silent) {
Town town = TownyAPI.getInstance().getTown(player.getLocation());
if (player.hasPermission("townyflight.bypass")
|| player.getGameMode().equals(GameMode.SPECTATOR)
|| player.getGameMode().equals(GameMode.CREATIVE)
|| town != null && MetaData.getFreeFlightMeta(town)
|| getForceAllowFlight(player))
return true;

if (!Permission.has(player, "townyflight.command.tfly", silent)) return false;
if (!hasTempFlight(player) && !Permission.has(player, "townyflight.command.tfly", silent)) return false;

Resident resident = TownyUniverse.getInstance().getResident(player.getUniqueId());
if (resident == null) return false;

if (!resident.hasTown() && !locationTrustsResidents(town, resident)) {
if (!silent) Message.of("noTownMsg").to(player);
return false;
}

if (warPrevents(player.getLocation(), resident)) {
if (!silent) Message.of("notDuringWar").to(player);
return false;
Expand All @@ -82,11 +76,6 @@ public boolean canFly(Player player, boolean silent) {
return true;
}

private boolean locationTrustsResidents(Town town, Resident resident) {
return town != null && town.hasTrustedResident(resident);
}


/**
* Returns true if a player is allowed to fly at their current location. Checks
* if they are in the wilderness, in their own town and if not, whether they
Expand All @@ -104,13 +93,20 @@ public static boolean allowedLocation(Player player, Location location, Resident
if (TownyAPI.getInstance().isWilderness(location))
return false;

Town town = TownyAPI.getInstance().getTown(location);

if (player.hasPermission("townyflight.alltowns"))
return true;

Town town = TownyAPI.getInstance().getTown(location);
if (player.hasPermission("townyflight.trustedtowns") && town.hasTrustedResident(resident))
return true;

if (MetaData.getFreeFlightMeta(town))
return true;

if (!resident.hasTown())
return false;

Town residentTown = resident.getTownOrNull();
if (residentTown == null)
return false;
Expand Down Expand Up @@ -142,6 +138,7 @@ public void removeFlight(Player player, boolean silent, boolean forced, String c
String reason = Message.getLangString("flightDeactivatedMsg");
if (cause == "pvp") reason = Message.getLangString("flightDeactivatedPVPMsg");
if (cause == "console") reason = Message.getLangString("flightDeactivatedConsoleMsg");
if (cause == "time") reason = Message.getLangString("flightDeactivatedTimeMsg");
Message.of(reason + Message.getLangString("flightOffMsg")).to(player);
} else {
Message.of("flightOffMsg").to(player);
Expand Down Expand Up @@ -233,6 +230,10 @@ public boolean getForceAllowFlight(Player player) {
return player.getPersistentDataContainer().getOrDefault(forceAllowFlight, PersistentDataType.BYTE, (byte) 0) == 1;
}

private boolean hasTempFlight(Player player) {
return TempFlightTask.getSeconds(player.getUniqueId()) > 0L;
}

private boolean warPrevents(Location location, Resident resident) {
return Settings.disableDuringWar && (townHasActiveWar(location, resident) || residentIsSieged(location));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
Expand All @@ -12,22 +13,27 @@
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;

import com.gmail.llmdlio.townyflight.config.Settings;
import com.gmail.llmdlio.townyflight.tasks.TempFlightTask;
import com.gmail.llmdlio.townyflight.util.Message;
import com.gmail.llmdlio.townyflight.util.MetaData;
import com.gmail.llmdlio.townyflight.util.Permission;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.TownyUniverse;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.utils.NameUtil;
import com.palmergames.bukkit.util.Colors;
import com.palmergames.util.StringMgmt;
import com.palmergames.util.TimeMgmt;
import com.palmergames.util.TimeTools;

public class TownyFlightCommand implements TabExecutor {

private TownyFlight plugin;
private CommandSender sender;
private static final List<String> tflyTabCompletes = Arrays.asList(
"reload","town","help","?"
"reload","tempflight","town","help","?"
);

public TownyFlightCommand(TownyFlight plugin) {
Expand All @@ -38,6 +44,11 @@ public TownyFlightCommand(TownyFlight plugin) {
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if (args.length > 0) {
switch (args[0].toLowerCase()) {
case "tempflight":
if (args.length == 2)
return getTownyStartingWith(args[1], "r");
if (args.length == 3)
return NameUtil.filterByStart(Arrays.asList("remove", "10", "1000s", "60m", "1h", "1d"), args[2]);
case "town":
if (args.length == 2)
return getTownyStartingWith(args[1], "t");
Expand Down Expand Up @@ -69,6 +80,9 @@ private void parseCommand(String[] args) {
} else if (args[0].equalsIgnoreCase("reload")) {
// Reload the plugin.
reloadPlugin();
} else if (args[0].equalsIgnoreCase("tempflight")) {
// We have /tfly tempflight and tested for permission node.
parseTempFlightCommand(StringMgmt.remFirstArg(args));
} else if (args[0].equalsIgnoreCase("town")) {
// parse /tfly town NAME OPTION command.
parseTownCommand(StringMgmt.remFirstArg(args));
Expand All @@ -88,6 +102,9 @@ private void parseCommand(String[] args) {
} else if (args[0].equalsIgnoreCase("reload") && Permission.has(sender,"townyflight.command.tfly.reload", false)) {
// We have /tfly reload and tested for permission node.
reloadPlugin();
} else if (args[0].equalsIgnoreCase("tempflight") && Permission.has(sender,"townyflight.command.tfly.tempflight", false)) {
// We have /tfly tempflight and tested for permission node.
parseTempFlightCommand(StringMgmt.remFirstArg(args));
} else if (args[0].equalsIgnoreCase("town") && Permission.has(sender,"townyflight.command.tfly.town", false)) {
// parse /tfly town NAME OPTION command.
parseTownCommand(StringMgmt.remFirstArg(args));
Expand All @@ -107,6 +124,66 @@ private void parseCommand(String[] args) {
}
}

private void parseTempFlightCommand(String[] args) {
if (args.length < 2) {
showTflyHelp();
return;
}

String name = args[0];
Player player = Bukkit.getPlayerExact(name);
UUID uuid = player != null ? player.getUniqueId() : null;
if (uuid == null && TownyUniverse.getInstance().hasResident(name)) {
Resident resident = TownyAPI.getInstance().getResident(name);
if (resident != null && resident.hasUUID())
uuid = resident.getUUID();
}

if (uuid == null) {
Message.of("Player " + name + " not found. Could not grant temp flight.").to(sender);
return;
}

if (args[1].equalsIgnoreCase("remove")) {
TempFlightTask.removeAllPlayerTempFlightSeconds(uuid);
Message.of(name + " has had their flight time set to 0.").to(sender);
return;
}

long seconds = parseSeconds(args[1]);
if (seconds == 0L) {
Message.of("Could not grant 0 seconds of temp flight.").to(sender);
return;
}

String formattedTimeValue = TimeMgmt.getFormattedTimeValue(seconds * 1000L);
Message.of(String.format(Message.getLangString("tempFlightGrantedToPlayer"), name, formattedTimeValue)).to(sender);
MetaData.addTempFlight(uuid, seconds);

if (player != null && player.isOnline()) {
TempFlightTask.addPlayerTempFlightSeconds(uuid, seconds);
Message.of(String.format(Message.getLangString("youHaveReceivedTempFlight"), formattedTimeValue)).to(player);

if (Settings.autoEnableFlight && TownyFlightAPI.getInstance().canFly(player, true))
TownyFlightAPI.getInstance().addFlight(player, Settings.autoEnableSilent);
}

}

private long parseSeconds(String string) {
if (string.endsWith("s") || string.endsWith("m") || string.endsWith("h") || string.endsWith("d"))
return TimeTools.getSeconds(string);

long seconds;
try {
seconds = Long.valueOf(string);
} catch (NumberFormatException e) {
Message.of("The number " + string + " cannot be parsed into a number of seconds.").to(sender);
return 0L;
}
return seconds;
}

private void parseTownCommand(String[] args) {
if (args.length < 2) {
showTflyHelp();
Expand Down Expand Up @@ -137,6 +214,13 @@ private void showTflyHelp() {
Message.of(Colors.White + "/tfly - Toggle flight.").to(sender);
if (Permission.has(sender, "townyflight.command.tfly.reload", true))
Message.of(Colors.White + "/tfly reload - Reload the TownyFlight config.").to(sender);
if (Permission.has(sender, "townyflight.command.tfly.tempflight", true)) {
Message.of(Colors.White + "/tfly tempflight [playername] [seconds] - Grant a player temp flight in seconds.").to(sender);
Message.of(Colors.White + "/tfly tempflight [playername] [time]m - Grant a player temp flight in minutes.").to(sender);
Message.of(Colors.White + "/tfly tempflight [playername] [time]h - Grant a player temp flight in hours.").to(sender);
Message.of(Colors.White + "/tfly tempflight [playername] [time]d - Grant a player temp flight in days.").to(sender);
Message.of(Colors.White + "/tfly tempflight [playername] remove - Remove a player's temp flight.").to(sender);
}
if (Permission.has(sender, "townyflight.command.tfly.other", true))
Message.of(Colors.White + "/tfly [playername] - Toggle flight for a player.").to(sender);
if (Permission.has(sender, "townyflight.command.tfly.town", true))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public enum ConfigNodes {
"Flight priviledges removed. ",
"",
"# Message shown when a player has flight taken away by console."),
LANG_FLIGHTDEACTIVATEDTIMEMSG(
"language.flightDeactivatedTimeMsg",
"You ran out of flight time. ",
"",
"# Message shown when a player has flight taken away because their tempflight ran out."),
LANG_NOPERMISSION(
"language.noPermission",
"You do not have permission for this command%s. ",
Expand Down Expand Up @@ -94,6 +99,22 @@ public enum ConfigNodes {
"Flight enabled for everyone within this town's borders.",
"",
"# The hover text shown on the free flight status screen component."),
LANG_TEMPFLIGHTGRANTEDTOPLAYER(
"language.tempFlightGrantedToPlayer",
"%s has had tempflight granted for %s.",
"",
"# The message shown to the admin/console when temp flight is given to a player."),
LANG_YOUHAVEBEENGIVENTEMPFLIGHT(
"language.youHaveReceivedTempFlight",
"You have been given %s of tempflight priviledges.",
"",
"# The message shown to the player when they receive temp flight."),
LANG_TEMPFLIGHTEXPIRED(
"language.yourTempFlightHasExpired",
"Your tempflight priviledges have expired.",
"",
"# The message shown to the player when they run out of temp flight."),


OPTIONS("options", "", "",
"#################",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static void loadStrings() {
lang.put("flightDeactivatedMsg", getString("flightDeactivatedMsg"));
lang.put("flightDeactivatedPVPMsg", getString("flightDeactivatedPVPMsg"));
lang.put("flightDeactivatedConsoleMsg", getString("flightDeactivatedConsoleMsg"));
lang.put("flightDeactivatedTimeMsg", getString("flightDeactivatedTimeMsg"));
lang.put("noPermission", getString("noPermission"));
lang.put("missingNode", getString("missingNode"));
lang.put("notDuringWar", getString("notDuringWar"));
Expand All @@ -54,6 +55,9 @@ public static void loadStrings() {
lang.put("enabled", getString("enabled"));
lang.put("statusScreenComponent", getString("statusScreenComponent"));
lang.put("statusScreenComponentHover", getString("statusScreenComponentHover"));
lang.put("tempFlightGrantedToPlayer", getString("tempFlightGrantedToPlayer"));
lang.put("youHaveReceivedTempFlight", getString("youHaveReceivedTempFlight"));
lang.put("yourTempFlightHasExpired", getString("yourTempFlightHasExpired"));
}

public static String getLangString(String languageString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import com.gmail.llmdlio.townyflight.TownyFlight;
import com.gmail.llmdlio.townyflight.TownyFlightAPI;
import com.gmail.llmdlio.townyflight.tasks.TempFlightTask;
import com.palmergames.util.TimeMgmt;

import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.md_5.bungee.api.ChatColor;
Expand Down Expand Up @@ -108,6 +110,11 @@ private String getOfflinePlayerPlaceholder(OfflinePlayer offlineplayer, String i
switch (identifier) {
case "can_player_fly": // %townyflight_can_player_fly%
return String.valueOf(TownyFlightAPI.canFlyAccordingToCache(player));
case "temp_flight_seconds_remaining": // %townyflight_temp_flight_seconds_remaining%
return TimeMgmt.getFormattedTimeValue(TempFlightTask.getSeconds(offlineplayer.getUniqueId()) * 1000L);
case "temp_flight_seconds_remaining_raw": // %townyflight_temp_flight_seconds_remaining_raw%
return String.valueOf(TempFlightTask.getSeconds(offlineplayer.getUniqueId()));

default:
return "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import com.gmail.llmdlio.townyflight.TownyFlightAPI;
import com.gmail.llmdlio.townyflight.config.Settings;
import com.gmail.llmdlio.townyflight.tasks.TempFlightTask;
import com.gmail.llmdlio.townyflight.util.MetaData;

public class PlayerJoinListener implements Listener {
private final TownyFlight plugin;
Expand All @@ -26,6 +28,10 @@ private void playerJoinEvent(PlayerJoinEvent event) {
final Player player = event.getPlayer();

plugin.getScheduler().runLater(player, () -> {
long seconds = MetaData.getSeconds(player.getUniqueId());
if (seconds > 0L)
TempFlightTask.addPlayerTempFlightSeconds(player.getUniqueId(), seconds);

boolean canFly = TownyFlightAPI.getInstance().canFly(player, true);
boolean isFlying = player.isFlying();
if (isFlying && canFly)
Expand Down
Loading

0 comments on commit c9697b3

Please sign in to comment.