From 112fd0d53d40db4cc170202905daf717077606fa Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Fri, 14 Jan 2022 20:33:08 +0100 Subject: [PATCH] Makes temporary permissions work Saves and loads temporary permissions to/from disk as necessary Gives players their temporary permissions when joining Adds an un-used config file Changes an english string in strings.yml --- .../permissionsigns/PermissionSigns.java | 7 ++ .../container/TemporaryPermission.java | 7 +- .../listener/PlayerListener.java | 26 +++++ .../manager/PermissionManager.java | 94 ++++++++++++++++--- .../permissionsigns/manager/SignManager.java | 4 +- src/main/resources/config.yml | 5 + src/main/resources/strings.yml | 2 +- 7 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java create mode 100644 src/main/resources/config.yml diff --git a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java index e74ad06..637f6e4 100644 --- a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java +++ b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java @@ -5,6 +5,7 @@ import net.knarcraft.permissionsigns.command.PermissionSignsTabCompleter; import net.knarcraft.permissionsigns.container.PermissionSign; import net.knarcraft.permissionsigns.container.SignCreationRequest; import net.knarcraft.permissionsigns.formatting.Translator; +import net.knarcraft.permissionsigns.listener.PlayerListener; import net.knarcraft.permissionsigns.listener.SignListener; import net.knarcraft.permissionsigns.manager.EconomyManager; import net.knarcraft.permissionsigns.manager.PermissionManager; @@ -149,6 +150,10 @@ public final class PermissionSigns extends JavaPlugin { //TODO: Check for existence of old permission signs when clicked and register them as new permission signs. If // it has the permissionSigns header and a name matching contents in signs.yml, add it. + //TODO: Implement config file + //TODO: Account for per-world permissions if enabled (perhaps allow world specification as world:permission?) + //TODO: Allow for custom language files. Perhaps just look for strings.yml in the folder + //Check if vault is loaded ServicesManager servicesManager = this.getServer().getServicesManager(); RegisteredServiceProvider permissionProvider = servicesManager.getRegistration(Permission.class); @@ -160,6 +165,7 @@ public final class PermissionSigns extends JavaPlugin { throw new IllegalStateException("[PermissionSigns] Error: Vault could not be loaded"); } getServer().getPluginManager().registerEvents(new SignListener(), this); + getServer().getPluginManager().registerEvents(new PlayerListener(), this); Translator.loadLanguages("en"); registerCommands(); @@ -167,6 +173,7 @@ public final class PermissionSigns extends JavaPlugin { scheduler.runTaskTimer(this, new SignCreationRequestTimeoutThread(signCreationRequests), 0L, 100L); scheduler.runTaskTimer(this, new PermissionTimeoutThread(), 0L, 25L); SignManager.loadSigns(); + PermissionManager.loadTemporaryPermissions(); } /** diff --git a/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java b/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java index b1ecb22..2b854ac 100644 --- a/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java +++ b/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java @@ -1,5 +1,6 @@ package net.knarcraft.permissionsigns.container; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull; public class TemporaryPermission implements Comparable { private final long grantedTime; - private final Player grantedPlayer; + private final OfflinePlayer grantedPlayer; private final String permissionNode; private final int duration; @@ -37,7 +38,7 @@ public class TemporaryPermission implements Comparable { * @param grantedTime

The time this temporary permission was granted

* @param duration

The duration, in seconds, the temporary permission should last

*/ - public TemporaryPermission(Player player, String permissionNode, long grantedTime, int duration) { + public TemporaryPermission(OfflinePlayer player, String permissionNode, long grantedTime, int duration) { this.grantedPlayer = player; this.permissionNode = permissionNode; this.grantedTime = grantedTime; @@ -67,7 +68,7 @@ public class TemporaryPermission implements Comparable { * * @return

The player this temporary permission was granted to

*/ - public Player getGrantedPlayer() { + public OfflinePlayer getGrantedPlayer() { return grantedPlayer; } diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java new file mode 100644 index 0000000..fc22c28 --- /dev/null +++ b/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java @@ -0,0 +1,26 @@ +package net.knarcraft.permissionsigns.listener; + +import net.knarcraft.permissionsigns.container.TemporaryPermission; +import net.knarcraft.permissionsigns.manager.PermissionManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.PriorityQueue; +import java.util.Queue; + +/** + * A listener listening to player events + */ +public class PlayerListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + //Give the joining player any temporary permissions containing their UUID + Queue temporaryPermissions = new PriorityQueue<>(PermissionManager.getTemporaryPermissions()); + temporaryPermissions.removeIf((item) -> !item.getGrantedPlayer().getUniqueId().equals(event.getPlayer().getUniqueId())); + temporaryPermissions.forEach((item) -> PermissionManager.grantTemporaryPermission(event.getPlayer(), + item.getPermissionNode())); + } + +} diff --git a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java index 50abac3..d980f42 100644 --- a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java +++ b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java @@ -1,11 +1,20 @@ package net.knarcraft.permissionsigns.manager; +import net.knarcraft.permissionsigns.PermissionSigns; import net.knarcraft.permissionsigns.container.TemporaryPermission; import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import java.io.File; +import java.io.IOException; import java.util.Queue; +import java.util.UUID; import java.util.concurrent.PriorityBlockingQueue; +import java.util.logging.Level; /** * A manager that performs all Permission tasks @@ -13,7 +22,8 @@ import java.util.concurrent.PriorityBlockingQueue; public class PermissionManager { private static Permission permission; - private static final Queue temporaryPermissions = new PriorityBlockingQueue<>(); + private static Queue temporaryPermissions = new PriorityBlockingQueue<>(); + private static final File permissionsFile = new File(PermissionSigns.getInstance().getDataFolder(), "data.yml"); /** * Initializes the permission manager @@ -44,6 +54,16 @@ public class PermissionManager { permission.playerAdd(null, player, permissionNode); } + /** + * Grants a temporary permission to the given player + * + * @param player

The player to add the temporary permission to

+ * @param permissionNode

The permission node to grant

+ */ + public static void grantTemporaryPermission(Player player, String permissionNode) { + permission.playerAddTransient(null, player, permissionNode); + } + /** * Grants a temporary permission to a player * @@ -52,27 +72,77 @@ public class PermissionManager { * @param duration

The duration for which the player should keep the given permission

*/ public static void addTemporaryPermission(Player player, String permissionNode, int duration) { - permission.playerAddTransient(null, player, permissionNode); + grantTemporaryPermission(player, permissionNode); temporaryPermissions.add(new TemporaryPermission(player, permissionNode, duration)); - //TODO: Create and store a temporary permission - // Check all stored temporary permissions on startup: - // * Remove expired temporary permissions - // * Grant transient permissions - // In a separate thread, remove any expired permissions, checking at least once every seconds. Might want to - // store the granted permissions in a priority queue where the priority is the least duration left. - // How to store temporary permissions? Identifier as Player + permission granted time? + try { + saveTemporaryPermissions(); + } catch (IOException e) { + PermissionSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to save temporary permissions! " + + "Players will lose their temporary permissions upon server restart!"); + } } /** * Removes a temporary permission * - * @param player

The player to remove the permission from

+ * @param offlinePlayer

The player to remove the permission from

* @param permissionNode

The permission node to remove from the player

*/ - public static void removeTemporaryPermission(Player player, String permissionNode) { - if (player.hasPermission(permissionNode)) { + public static void removeTemporaryPermission(OfflinePlayer offlinePlayer, String permissionNode) { + Player player = offlinePlayer.getPlayer(); + if (player != null && player.hasPermission(permissionNode)) { permission.playerRemoveTransient(null, player, permissionNode); } } + /** + * Saves all temporary permissions to a file + * + * @throws IOException

If unable to write to the file

+ */ + public static void saveTemporaryPermissions() throws IOException { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(permissionsFile); + ConfigurationSection permissionSection = configuration.createSection("permissions"); + + temporaryPermissions.forEach((item) -> { + String key = item.getGrantedPlayer().getUniqueId() + "," + item.getGrantedTime(); + permissionSection.set(key + ".permissionNode", item.getPermissionNode()); + permissionSection.set(key + ".duration", item.getGrantedDuration()); + }); + configuration.save(permissionsFile); + } + + /** + * Loads all saved temporary permissions + */ + public static void loadTemporaryPermissions() { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(permissionsFile); + ConfigurationSection permissionSection = configuration.getConfigurationSection("permissions"); + temporaryPermissions = new PriorityBlockingQueue<>(); + if (permissionSection == null) { + PermissionSigns.getInstance().getLogger().log(Level.WARNING, "Permission section not found in data.yml"); + return; + } + + long currentTime = System.currentTimeMillis(); + for (String key : permissionSection.getKeys(false)) { + String[] identifierParts = key.split(","); + OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(identifierParts[0])); + String permissionNode = permissionSection.getString(key + ".permissionNode"); + long granted = Long.parseLong(identifierParts[1]); + int duration = permissionSection.getInt(key + ".duration", 1); + + //Skip any expired temporary permissions + if (currentTime > granted + (1000L * duration)) { + continue; + } + //TODO: Need to wait for the player to join the server before allocating transient permissions + temporaryPermissions.add(new TemporaryPermission(player, permissionNode, granted, duration)); + } + try { + saveTemporaryPermissions(); + } catch (IOException ignored) { + } + } + } diff --git a/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java b/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java index fd13c45..d8526c3 100644 --- a/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java +++ b/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java @@ -28,7 +28,7 @@ import java.util.logging.Level; public class SignManager { private static Map managedSigns = new HashMap<>(); - private static final File signsFile = new File(PermissionSigns.getInstance().getDataFolder(), "signs.yml"); + private static final File signsFile = new File(PermissionSigns.getInstance().getDataFolder(), "data.yml"); /** * Gets the permission sign at the given location @@ -89,7 +89,7 @@ public class SignManager { ConfigurationSection signSection = configuration.getConfigurationSection("signs"); managedSigns = new HashMap<>(); if (signSection == null) { - PermissionSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in signs.yml"); + PermissionSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in data.yml"); return; } for (String key : signSection.getKeys(false)) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..5c9c577 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,5 @@ +# The language to use for the plugin +language: en + +# Whether to only give permissions for a single world, instead of granting permissions for all worlds +perWorldPermissions: false diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml index 1f646a1..7e22542 100644 --- a/src/main/resources/strings.yml +++ b/src/main/resources/strings.yml @@ -13,7 +13,7 @@ en: COMMAND_PERMISSION_DENIED: "&7You do not have necessary permissions to perform this command" CREATION_REQUEST_CREATED: "&7Permission Sign request created. Right-click an empty sign within 60 seconds to create the new permission sign" CANNOT_AFFORD: "&7You cannot afford to use this permission sign" - ALREADY_HAS_PERMISSIONS: "&7You already have all permissions sold by this permission sign" + ALREADY_HAS_PERMISSIONS: "&7You already have all permissions given by this permission sign" PERMISSIONS_GRANTED: "&7You have been granted the following permission nodes: {permissions} for {time}" PERMISSION_SIGN_CREATED: "&7Permission sign successfully created!" CREATION_REQUEST_CANCELLED: "&7Your last permission sign creation request has been cancelled" \ No newline at end of file