diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCalculatorFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCalculatorFactory.java index 1ddef39f..9628ce3b 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCalculatorFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCalculatorFactory.java @@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList; import lombok.AllArgsConstructor; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.bukkit.calculators.AttachmentProcessor; +import me.lucko.luckperms.bukkit.calculators.ChildProcessor; import me.lucko.luckperms.bukkit.calculators.DefaultsProcessor; import me.lucko.luckperms.bukkit.inject.Injector; import me.lucko.luckperms.bukkit.inject.LPPermissible; @@ -44,6 +45,7 @@ public class BukkitCalculatorFactory implements CalculatorFactory { ImmutableList.Builder processors = ImmutableList.builder(); processors.add(new MapProcessor()); + processors.add(new ChildProcessor(plugin.getChildPermissionProvider())); processors.add(new AttachmentProcessor(() -> { LPPermissible permissible = Injector.getPermissible(uuid); return permissible == null ? null : permissible.getAttachmentPermissions(); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index 149605e0..ee4951da 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -31,6 +31,7 @@ import me.lucko.luckperms.api.PlatformType; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.api.context.MutableContextSet; import me.lucko.luckperms.bukkit.calculators.AutoOPListener; +import me.lucko.luckperms.bukkit.calculators.ChildPermissionProvider; import me.lucko.luckperms.bukkit.calculators.DefaultsProvider; import me.lucko.luckperms.bukkit.vault.VaultHook; import me.lucko.luckperms.common.LuckPermsPlugin; @@ -86,6 +87,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { private Importer importer; private ConsecutiveExecutor consecutiveExecutor; private DefaultsProvider defaultsProvider; + private ChildPermissionProvider childPermissionProvider; private LocaleManager localeManager; private ContextManager contextManager; private WorldCalculator worldCalculator; @@ -104,8 +106,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { // setup the Bukkit defaults hook defaultsProvider = new DefaultsProvider(); + childPermissionProvider = new ChildPermissionProvider(); + // give all plugins a chance to load their defaults, then refresh. - getServer().getScheduler().runTaskLater(this, () -> defaultsProvider.refresh(), 1L); + getServer().getScheduler().runTaskLater(this, () -> { + defaultsProvider.refresh(); + childPermissionProvider.setup(); + }, 1L); // register events PluginManager pm = getServer().getPluginManager(); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildPermissionProvider.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildPermissionProvider.java new file mode 100644 index 00000000..cb34ca0d --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildPermissionProvider.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.bukkit.calculators; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.permissions.Permission; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ChildPermissionProvider { + + @Getter + private ImmutableMap, ImmutableMap> permissions = ImmutableMap.of(); + + public void setup() { + ImmutableMap.Builder, ImmutableMap> permissions = ImmutableMap.builder(); + + for (Permission permission : Bukkit.getServer().getPluginManager().getPermissions()) { + // handle true + Map children = new HashMap<>(); + resolveChildren(children, Collections.singletonMap(permission.getName(), true), false); + permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), true), ImmutableMap.copyOf(children)); + + // handle false + Map nChildren = new HashMap<>(); + resolveChildren(nChildren, Collections.singletonMap(permission.getName(), false), false); + permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), false), ImmutableMap.copyOf(nChildren)); + } + + this.permissions = permissions.build(); + } + + private static void resolveChildren(Map accumulator, Map children, boolean invert) { + for (Map.Entry e : children.entrySet()) { + if (accumulator.containsKey(e.getKey())) { + continue; // Prevent infinite loops + } + + Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey()); + boolean value = e.getValue() ^ invert; + String lName = e.getKey().toLowerCase(); + + accumulator.put(lName, value); + + if (perm != null) { + resolveChildren(accumulator, perm.getChildren(), !value); + } + } + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildProcessor.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildProcessor.java new file mode 100644 index 00000000..6dd622b3 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/ChildProcessor.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.bukkit.calculators; + +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.api.Tristate; +import me.lucko.luckperms.common.calculators.PermissionProcessor; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@RequiredArgsConstructor +public class ChildProcessor implements PermissionProcessor { + private final ChildPermissionProvider provider; + private Map childPermissions = new ConcurrentHashMap<>(); + + @Override + public Tristate hasPermission(String permission) { + Boolean b = childPermissions.get(permission); + return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b); + } + + @Override + public void updateBacking(Map map) { + childPermissions.clear(); + for (Map.Entry e : map.entrySet()) { + Map children = provider.getPermissions().get(e); + if (children != null) { + childPermissions.putAll(children); + } + } + } +}