diff --git a/README.md b/README.md index 8626b677..ba4a4743 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ You can add LuckPerms as a Maven dependency by adding the following to your proj ## Versioning As of version 2.0, LuckPerms roughly follows the standards set out in Semantic Versioning. -The only difference is that patch number is not included anywhere within the pom, and is calculated each build, based upon how may commits have been made since the last tag. (A new tag is made every minor version) +The only difference is that the patch number is not included anywhere within the pom, and is calculated each build, based upon how may commits have been made since the last tag. (A new tag is made every minor version) This means that API versions do not have a patch number (as no API changes are made in patches). API versions will be x.y, and each individual build of LuckPerms will follow x.y.z. diff --git a/api/src/main/java/me/lucko/luckperms/api/Datastore.java b/api/src/main/java/me/lucko/luckperms/api/Datastore.java index ada35bfa..18c94f1b 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Datastore.java +++ b/api/src/main/java/me/lucko/luckperms/api/Datastore.java @@ -28,7 +28,8 @@ import java.util.UUID; /** * Wrapper interface for the internal Datastore instance - * The implementations of this interface limit access to the datastore and add parameter checks to further prevent + * + *

The implementations of this interface limit access to the datastore and add parameter checks to further prevent * errors and ensure all API interactions to not damage the state of the plugin. */ @SuppressWarnings("unused") diff --git a/api/src/main/java/me/lucko/luckperms/api/Group.java b/api/src/main/java/me/lucko/luckperms/api/Group.java index c1eaa44b..3f92af7d 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Group.java +++ b/api/src/main/java/me/lucko/luckperms/api/Group.java @@ -29,7 +29,8 @@ import java.util.List; /** * Wrapper interface for internal Group instances - * The implementations of this interface limit access to the Group and add parameter checks to further prevent + * + *

The implementations of this interface limit access to the Group and add parameter checks to further prevent * errors and ensure all API interactions to not damage the state of the group. */ @SuppressWarnings("unused") diff --git a/api/src/main/java/me/lucko/luckperms/api/Logger.java b/api/src/main/java/me/lucko/luckperms/api/Logger.java index 82fc4eed..5687c38c 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Logger.java +++ b/api/src/main/java/me/lucko/luckperms/api/Logger.java @@ -24,7 +24,8 @@ package me.lucko.luckperms.api; /** * A wrapper class for platform logger instances. - * Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the commons + * + *

Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the commons * module can access a logger. */ public interface Logger { diff --git a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java index 0f5ae3e8..ca3df1b2 100644 --- a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java +++ b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java @@ -30,7 +30,8 @@ import java.util.Map; /** * Wrapper interface for internal PermissionHolder (user/group) instances - * The implementations of this interface limit access to the object and add parameter checks to further prevent + * + *

The implementations of this interface limit access to the object and add parameter checks to further prevent * errors and ensure all API interactions to not damage the state of the object. */ @SuppressWarnings("unused") diff --git a/api/src/main/java/me/lucko/luckperms/api/Track.java b/api/src/main/java/me/lucko/luckperms/api/Track.java index 60c336c1..76fe2d1a 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Track.java +++ b/api/src/main/java/me/lucko/luckperms/api/Track.java @@ -29,7 +29,8 @@ import java.util.List; /** * Wrapper interface for internal Track instances - * The implementations of this interface limit access to the Track and add parameter checks to further prevent + * + *

The implementations of this interface limit access to the Track and add parameter checks to further prevent * errors and ensure all API interactions to not damage the state of the track. */ @SuppressWarnings("unused") diff --git a/api/src/main/java/me/lucko/luckperms/api/User.java b/api/src/main/java/me/lucko/luckperms/api/User.java index ae247b43..e12ab60c 100644 --- a/api/src/main/java/me/lucko/luckperms/api/User.java +++ b/api/src/main/java/me/lucko/luckperms/api/User.java @@ -30,7 +30,8 @@ import java.util.UUID; /** * Wrapper interface for internal User instances - * The implementations of this interface limit access to the User and add parameter checks to further prevent + * + *

The implementations of this interface limit access to the User and add parameter checks to further prevent * errors and ensure all API interactions to not damage the state of the user. */ @SuppressWarnings("unused") diff --git a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java index a93a30fc..a7c67ec4 100644 --- a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java +++ b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java @@ -30,10 +30,10 @@ import java.util.UUID; * they first join the server, but this UUID will then not be consistent across the network. LuckPerms will instead check * the datastore cache, to get a UUID for a user that is consistent across an entire network. * - * If you want to get a user object from the datastore using the api on a server in offline mode, you will need to use this cache, + *

If you want to get a user object from the datastore using the api on a server in offline mode, you will need to use this cache, * OR use Datastore#getUUID, for users that are not online. * - * WARNING: THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS. + *

WARNING: THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS. */ public interface UuidCache { diff --git a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java index 73c6034c..3e1c3fb9 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java +++ b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java @@ -28,10 +28,24 @@ import me.lucko.luckperms.LPBukkitPlugin; import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionAttachment; +import java.lang.reflect.Field; import java.util.Map; import java.util.UUID; public class BukkitUser extends User { + private static Field permissionsField = null; + private static Field getPermissionsField() { + if (permissionsField == null) { + try { + permissionsField = PermissionAttachment.class.getDeclaredField("permissions"); + permissionsField.setAccessible(true); + } catch (SecurityException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + return permissionsField; + } + private final LPBukkitPlugin plugin; @@ -49,6 +63,7 @@ public class BukkitUser extends User { this.plugin = plugin; } + @SuppressWarnings("unchecked") @Override public void refreshPermissions() { plugin.doSync(() -> { @@ -60,12 +75,35 @@ public class BukkitUser extends User { setAttachment(player.addAttachment(plugin)); } - // Clear existing permissions - attachment.getPermissions().keySet().forEach(p -> attachment.setPermission(p, false)); + // Calculate the permissions that should be applied + Map toApply = getLocalPermissions(getPlugin().getConfiguration().getServer(), player.getWorld().getName(), null); - // Re-add all defined permissions for the user - Map local = getLocalPermissions(getPlugin().getConfiguration().getServer(), player.getWorld().getName(), null); - local.entrySet().forEach(e -> attachment.setPermission(e.getKey(), e.getValue())); + try { + Map existing = (Map) getPermissionsField().get(attachment); + + boolean different = false; + if (toApply.size() != existing.size()) { + different = true; + } else { + for (Map.Entry e : existing.entrySet()) { + if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) { + continue; + } + different = true; + break; + } + } + + if (!different) return; + + // Faster than recalculating permissions after each PermissionAttachment#setPermission + existing.clear(); + existing.putAll(toApply); + attachment.getPermissible().recalculatePermissions(); + + } catch (Exception e) { + e.printStackTrace(); + } }); } } diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index be0ab7ff..96452f80 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -7,4 +7,102 @@ description: A permissions plugin commands: luckperms: description: Manage permissions - aliases: [perms, permissions, lp, p, perm] \ No newline at end of file + aliases: [perms, permissions, lp, p, perm] +permissions: + luckperms.*: + description: Gives access to all LuckPerms commands + children: + luckperms.sync: true + luckperms.info: true + luckperms.debug: true + luckperms.creategroup: true + luckperms.deletegroup: true + luckperms.listgroups: true + luckperms.createtrack: true + luckperms.deletetrack: true + luckperms.listtracks: true + luckperms.user.info: true + luckperms.user.getuuid: true + luckperms.user.listnodes: true + luckperms.user.haspermission: true + luckperms.user.inheritspermission: true + luckperms.user.setpermission: true + luckperms.user.unsetpermission: true + luckperms.user.addgroup: true + luckperms.user.removegroup: true + luckperms.user.settemppermission: true + luckperms.user.unsettemppermission: true + luckperms.user.addtempgroup: true + luckperms.user.removetempgroup: true + luckperms.user.setprimarygroup: true + luckperms.user.showtracks: true + luckperms.user.promote: true + luckperms.user.demote: true + luckperms.user.showpos: true + luckperms.user.clear: true + luckperms.group.info: true + luckperms.group.listnodes: true + luckperms.group.haspermission: true + luckperms.group.inheritspermission: true + luckperms.group.setpermission: true + luckperms.group.unsetpermission: true + luckperms.group.setinherit: true + luckperms.group.unsetinherit: true + luckperms.group.settemppermission: true + luckperms.group.unsettemppermission: true + luckperms.group.settempinherit: true + luckperms.group.unsettempinherit: true + luckperms.group.showtracks: true + luckperms.group.clear: true + luckperms.track.info: true + luckperms.track.append: true + luckperms.track.insert: true + luckperms.track.remove: true + luckperms.track.clear: true + luckperms.user.*: + description: Gives access to all LuckPerms user commands + children: + luckperms.user.info: true + luckperms.user.getuuid: true + luckperms.user.listnodes: true + luckperms.user.haspermission: true + luckperms.user.inheritspermission: true + luckperms.user.setpermission: true + luckperms.user.unsetpermission: true + luckperms.user.addgroup: true + luckperms.user.removegroup: true + luckperms.user.settemppermission: true + luckperms.user.unsettemppermission: true + luckperms.user.addtempgroup: true + luckperms.user.removetempgroup: true + luckperms.user.setprimarygroup: true + luckperms.user.showtracks: true + luckperms.user.promote: true + luckperms.user.demote: true + luckperms.user.showpos: true + luckperms.user.clear: true + luckperms.group.*: + description: Gives access to all LuckPerms group commands + children: + luckperms.group.info: true + luckperms.group.listnodes: true + luckperms.group.haspermission: true + luckperms.group.inheritspermission: true + luckperms.group.setpermission: true + luckperms.group.unsetpermission: true + luckperms.group.setinherit: true + luckperms.group.unsetinherit: true + luckperms.group.settemppermission: true + luckperms.group.unsettemppermission: true + luckperms.group.settempinherit: true + luckperms.group.unsettempinherit: true + luckperms.group.showtracks: true + luckperms.group.clear: true + luckperms.track.*: + description: Gives access to all LuckPerms track commands + children: + luckperms.track.info: true + luckperms.track.append: true + luckperms.track.insert: true + luckperms.track.remove: true + luckperms.track.clear: true \ No newline at end of file diff --git a/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java b/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java index 98321e35..50090bea 100644 --- a/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java +++ b/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java @@ -40,6 +40,6 @@ public class InfoCommand extends SingleMainCommand { protected void execute(LuckPermsPlugin plugin, Sender sender, List args, String label) { final LPConfiguration c = plugin.getConfiguration(); Message.INFO.send(sender, plugin.getVersion(), plugin.getDatastore().getName(), c.getServer(), - c.getDefaultGroupName(), c.getSyncTime(), c.getIncludeGlobalPerms(), c.getOnlineMode()); + c.getDefaultGroupName(), c.getSyncTime(), c.getIncludeGlobalPerms(), c.getOnlineMode(), c.getApplyWildcards()); } } diff --git a/common/src/main/java/me/lucko/luckperms/constants/Message.java b/common/src/main/java/me/lucko/luckperms/constants/Message.java index a012ff81..d56d99c1 100644 --- a/common/src/main/java/me/lucko/luckperms/constants/Message.java +++ b/common/src/main/java/me/lucko/luckperms/constants/Message.java @@ -41,7 +41,7 @@ public enum Message { COMMAND_NOT_RECOGNISED("Command not recognised.", true), COMMAND_NO_PERMISSION("You do not have permission to use this command!", true), - INFO_BRIEF("&6Running &bLuckPerms %s&6.", true), + INFO_BRIEF("&6Running &bLuckPerms v%s&6.", true), ALREADY_HASPERMISSION("%s already has this permission!", true), DOES_NOT_HAVEPERMISSION("%s does not have this permission set.", true), @@ -118,14 +118,15 @@ public enum Message { UPDATE_TASK_RUN("&bRunning update task for all online users.", true), INFO( - PREFIX + "&6Running &bLuckPerms %s&6." + "\n" + + PREFIX + "&6Running &bLuckPerms v%s&6." + "\n" + PREFIX + "&eAuthor: &6Luck" + "\n" + PREFIX + "&eStorage Method: &6%s" + "\n" + PREFIX + "&eServer Name: &6%s" + "\n" + PREFIX + "&eDefault Group: &6%s" + "\n" + PREFIX + "&eSync Interval: &6%s minutes" + "\n" + PREFIX + "&eInclude Global Perms: &6%s" + "\n" + - PREFIX + "&eOnline Mode: &6%s", + PREFIX + "&eOnline Mode: &6%s" + "\n" + + PREFIX + "&eApply Wildcards: &6%s", false ), DEBUG( @@ -240,7 +241,7 @@ public enum Message { ), TRACK_CLEAR("&b%s&a's groups track was cleared.", true), TRACK_APPEND_SUCCESS("&aGroup &b%s&a was successfully appended to track &b%s&a.", true), - TRACK_INSERT_SUCCESS("&aGroup &b%s&a was successfully inserted into to track &b%s&a at position &b%s&a.", true), + TRACK_INSERT_SUCCESS("&aGroup &b%s&a was successfully inserted into track &b%s&a at position &b%s&a.", true), TRACK_INSERT_ERROR_NUMBER("Expected number but instead received: %s", true), TRACK_INSERT_ERROR_INVALID_POS("Unable to insert at position %s. Index out of bounds.", true), TRACK_REMOVE_SUCCESS("&aGroup &b%s&a was successfully removed from track &b%s&a.", true); diff --git a/sponge/pom.xml b/sponge/pom.xml index 805570d4..a5d69c6f 100644 --- a/sponge/pom.xml +++ b/sponge/pom.xml @@ -45,10 +45,6 @@ true - - org.slf4j - me.lucko.luckperms.lib.slf4j - com.zaxxer.hikari me.lucko.luckperms.lib.hikari @@ -139,13 +135,6 @@ 2.4.7 compile - - - org.slf4j - slf4j-simple - 1.7.9 - compile - de.icongmbh.oss.maven.plugins diff --git a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java index 6f0cb55d..1a4cabae 100644 --- a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java @@ -46,22 +46,26 @@ import org.spongepowered.api.command.CommandManager; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.game.state.GamePostInitializationEvent; import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.scheduler.Scheduler; import org.spongepowered.api.service.permission.PermissionDescription; import org.spongepowered.api.service.permission.PermissionService; +import org.spongepowered.api.text.Text; import java.io.File; import java.nio.file.Path; +import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Getter -@Plugin(id = "luckperms", name = "LuckPerms", version = "MAGIC", authors = {"Luck"}, description = "A permissions plugin") +@Plugin(id = "luckperms", name = "LuckPerms", version = "null", authors = {"Luck"}, description = "A permissions plugin") public class LPSpongePlugin implements LuckPermsPlugin { @Inject @@ -98,6 +102,7 @@ public class LPSpongePlugin implements LuckPermsPlugin { getLog().info("Registering commands..."); CommandManager cmdService = Sponge.getCommandManager(); cmdService.register(this, new SpongeCommand(this), "luckperms", "perms", "lp", "permissions", "p", "perm"); + registerPermissions(); getLog().info("Detecting storage method..."); final String storageMethod = configuration.getStorageMethod(); @@ -155,6 +160,11 @@ public class LPSpongePlugin implements LuckPermsPlugin { LuckPerms.unregisterProvider(); } + @Listener + public void onPostInit(GamePostInitializationEvent event) { + registerPermissions(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") private File getStorageDir() { File base = configDir.toFile().getParentFile().getParentFile(); @@ -165,7 +175,7 @@ public class LPSpongePlugin implements LuckPermsPlugin { @Override public String getVersion() { - return "MAGIC"; + return "null"; } @Override @@ -185,8 +195,11 @@ public class LPSpongePlugin implements LuckPermsPlugin { @Override public List getPossiblePermissions() { - PermissionService p = game.getServiceManager().provideUnchecked(PermissionService.class); - return p.getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList()); + Optional p = game.getServiceManager().provide(PermissionService.class); + if (!p.isPresent()) { + return Collections.emptyList(); + } + return p.get().getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList()); } @Override @@ -203,4 +216,79 @@ public class LPSpongePlugin implements LuckPermsPlugin { public void doSync(Runnable r) { scheduler.createTaskBuilder().execute(r).submit(LPSpongePlugin.this); } + + private void registerPermissions() { + Optional ps = game.getServiceManager().provide(PermissionService.class); + if (!ps.isPresent()) { + getLog().warn("Unable to register all LuckPerms permissions. PermissionService not available."); + return; + } + + final PermissionService p = ps.get(); + + Optional builder = p.newDescriptionBuilder(this); + if (!builder.isPresent()) { + getLog().warn("Unable to register all LuckPerms permissions. Description Builder not available."); + return; + } + + registerPermission(p, "luckperms.sync"); + registerPermission(p, "luckperms.info"); + registerPermission(p, "luckperms.debug"); + registerPermission(p, "luckperms.creategroup"); + registerPermission(p, "luckperms.deletegroup"); + registerPermission(p, "luckperms.listgroups"); + registerPermission(p, "luckperms.createtrack"); + registerPermission(p, "luckperms.deletetrack"); + registerPermission(p, "luckperms.listtracks"); + registerPermission(p, "luckperms.user.info"); + registerPermission(p, "luckperms.user.getuuid"); + registerPermission(p, "luckperms.user.listnodes"); + registerPermission(p, "luckperms.user.haspermission"); + registerPermission(p, "luckperms.user.inheritspermission"); + registerPermission(p, "luckperms.user.setpermission"); + registerPermission(p, "luckperms.user.unsetpermission"); + registerPermission(p, "luckperms.user.addgroup"); + registerPermission(p, "luckperms.user.removegroup"); + registerPermission(p, "luckperms.user.settemppermission"); + registerPermission(p, "luckperms.user.unsettemppermission"); + registerPermission(p, "luckperms.user.addtempgroup"); + registerPermission(p, "luckperms.user.removetempgroup"); + registerPermission(p, "luckperms.user.setprimarygroup"); + registerPermission(p, "luckperms.user.showtracks"); + registerPermission(p, "luckperms.user.promote"); + registerPermission(p, "luckperms.user.demote"); + registerPermission(p, "luckperms.user.showpos"); + registerPermission(p, "luckperms.user.clear"); + registerPermission(p, "luckperms.group.info"); + registerPermission(p, "luckperms.group.listnodes"); + registerPermission(p, "luckperms.group.haspermission"); + registerPermission(p, "luckperms.group.inheritspermission"); + registerPermission(p, "luckperms.group.setpermission"); + registerPermission(p, "luckperms.group.unsetpermission"); + registerPermission(p, "luckperms.group.setinherit"); + registerPermission(p, "luckperms.group.unsetinherit"); + registerPermission(p, "luckperms.group.settemppermission"); + registerPermission(p, "luckperms.group.unsettemppermission"); + registerPermission(p, "luckperms.group.settempinherit"); + registerPermission(p, "luckperms.group.unsettempinherit"); + registerPermission(p, "luckperms.group.showtracks"); + registerPermission(p, "luckperms.group.clear"); + registerPermission(p, "luckperms.track.info"); + registerPermission(p, "luckperms.track.append"); + registerPermission(p, "luckperms.track.insert"); + registerPermission(p, "luckperms.track.remove"); + registerPermission(p, "luckperms.track.clear"); + } + + private void registerPermission(PermissionService p, String node) { + Optional builder = p.newDescriptionBuilder(this); + if (!builder.isPresent()) return; + + try { + builder.get().assign(PermissionDescription.ROLE_ADMIN, true).description(Text.of(node)).id(node).register(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } } diff --git a/sponge/src/main/java/me/lucko/luckperms/SpongeCommand.java b/sponge/src/main/java/me/lucko/luckperms/SpongeCommand.java index d8cdae43..ee31f19d 100644 --- a/sponge/src/main/java/me/lucko/luckperms/SpongeCommand.java +++ b/sponge/src/main/java/me/lucko/luckperms/SpongeCommand.java @@ -51,6 +51,7 @@ class SpongeCommand extends CommandManager implements CommandCallable { @Override public List getSuggestions(CommandSource source, String s) throws CommandException { + // TODO: fix this so it actually works return onTabComplete(FACTORY.wrap(source), Arrays.asList(Patterns.SPACE.split(s))); } diff --git a/sponge/src/main/java/me/lucko/luckperms/SpongeListener.java b/sponge/src/main/java/me/lucko/luckperms/SpongeListener.java index 08202304..7e6c9dfb 100644 --- a/sponge/src/main/java/me/lucko/luckperms/SpongeListener.java +++ b/sponge/src/main/java/me/lucko/luckperms/SpongeListener.java @@ -33,7 +33,8 @@ import org.spongepowered.api.event.network.ClientConnectionEvent; import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.text.serializer.TextSerializers; -class SpongeListener extends AbstractListener { +@SuppressWarnings("WeakerAccess") +public class SpongeListener extends AbstractListener { private final LPSpongePlugin plugin; SpongeListener(LPSpongePlugin plugin) {