From d51f952a2f44537e1d1b6b29c8af2c9677a1dd96 Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:06:50 -0700 Subject: [PATCH] Implement all permission functions --- .../patchbukkit/PatchBukkitPluginManager.java | 101 +++----- .../patchbukkit/entity/PatchBukkitEntity.java | 39 +++- .../PatchBukkitPermissionManager.java | 219 ++++++++++++++++++ 3 files changed, 277 insertions(+), 82 deletions(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/permissions/PatchBukkitPermissionManager.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitPluginManager.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitPluginManager.java index 846770d..92aaed9 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitPluginManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitPluginManager.java @@ -19,17 +19,19 @@ import org.bukkit.plugin.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; +import org.patchbukkit.permissions.PatchBukkitPermissionManager; @SuppressWarnings("removal") public class PatchBukkitPluginManager implements PluginManager { private final Server server; private final PatchBukkitEventManager eventManager; private final Map plugins = new ConcurrentHashMap<>(); - private final Map permissions = new HashMap<>(); + PermissionManager permissionManager; public PatchBukkitPluginManager(Server server) { this.server = server; this.eventManager = new PatchBukkitEventManager(server); + this.permissionManager = new PatchBukkitPermissionManager(); } @Override @@ -159,117 +161,82 @@ public class PatchBukkitPluginManager implements PluginManager { @Override public @Nullable Permission getPermission(@NotNull String name) { - return permissions.get(name); + return this.permissionManager.getPermission(name); } @Override public void addPermission(@NotNull Permission perm) { - permissions.put(perm.getName(), perm); + this.permissionManager.addPermission(perm); } @Override public void removePermission(@NotNull Permission perm) { - throw new UnsupportedOperationException( - "Unimplemented method 'removePermission'" - ); + this.permissionManager.removePermission(perm); } @Override public void removePermission(@NotNull String name) { - throw new UnsupportedOperationException( - "Unimplemented method 'removePermission'" - ); + this.permissionManager.removePermission(name); } @Override public @NotNull Set getDefaultPermissions(boolean op) { - throw new UnsupportedOperationException( - "Unimplemented method 'getDefaultPermissions'" - ); + return this.permissionManager.getDefaultPermissions(op); } @Override public void recalculatePermissionDefaults(@NotNull Permission perm) { - throw new UnsupportedOperationException( - "Unimplemented method 'recalculatePermissionDefaults'" - ); + this.permissionManager.recalculatePermissionDefaults(perm); } @Override - public void subscribeToPermission( - @NotNull String permission, - @NotNull Permissible permissible - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'subscribeToPermission'" - ); + public void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible) { + this.permissionManager.subscribeToPermission(permission, permissible); } @Override - public void unsubscribeFromPermission( - @NotNull String permission, - @NotNull Permissible permissible - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'unsubscribeFromPermission'" - ); + public void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible) { + this.permissionManager.unsubscribeFromPermission(permission, permissible); } @Override - public @NotNull Set getPermissionSubscriptions( - @NotNull String permission - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'getPermissionSubscriptions'" - ); + public @NotNull Set getPermissionSubscriptions(@NotNull String permission) { + return this.permissionManager.getPermissionSubscriptions(permission); } @Override - public void subscribeToDefaultPerms( - boolean op, - @NotNull Permissible permissible - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'subscribeToDefaultPerms'" - ); + public void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible) { + this.permissionManager.subscribeToDefaultPerms(op, permissible); } @Override - public void unsubscribeFromDefaultPerms( - boolean op, - @NotNull Permissible permissible - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'unsubscribeFromDefaultPerms'" - ); + public void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible) { + this.permissionManager.unsubscribeFromDefaultPerms(op, permissible); } @Override public @NotNull Set getDefaultPermSubscriptions(boolean op) { - throw new UnsupportedOperationException( - "Unimplemented method 'getDefaultPermSubscriptions'" - ); + return this.permissionManager.getDefaultPermSubscriptions(op); } @Override public @NotNull Set getPermissions() { - throw new UnsupportedOperationException( - "Unimplemented method 'getPermissions'" - ); + return this.permissionManager.getPermissions(); } @Override - public void addPermissions(List perm) { - throw new UnsupportedOperationException( - "Unimplemented method 'addPermissions'" - ); + public void addPermissions(@NotNull List perm) { + this.permissionManager.addPermissions(perm); } @Override public void clearPermissions() { - throw new UnsupportedOperationException( - "Unimplemented method 'clearPermissions'" - ); + this.permissionManager.clearPermissions(); + } + + @Override + public void overridePermissionManager(@NotNull Plugin plugin, @Nullable PermissionManager permissionManager) { + this.permissionManager = permissionManager; } @Override @@ -288,14 +255,4 @@ public class PatchBukkitPluginManager implements PluginManager { "Unimplemented method 'isTransitiveDependency'" ); } - - @Override - public void overridePermissionManager( - @NotNull Plugin plugin, - @Nullable PermissionManager permissionManager - ) { - throw new UnsupportedOperationException( - "Unimplemented method 'overridePermissionManager'" - ); - } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java index 401b50a..24a5582 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java @@ -2,10 +2,12 @@ package org.patchbukkit.entity; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import org.bukkit.Bukkit; import org.bukkit.EntityEffect; import org.bukkit.Location; import org.bukkit.Server; @@ -24,9 +26,11 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.MetadataValue; +import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.permissions.ServerOperator; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.plugin.Plugin; import org.bukkit.util.BoundingBox; @@ -46,6 +50,7 @@ public class PatchBukkitEntity implements Entity { protected final UUID uuid; private final String name; + private static PermissibleBase perm; public PatchBukkitEntity( UUID uuid, @@ -55,6 +60,24 @@ public class PatchBukkitEntity implements Entity { this.name = name; } + private static PermissibleBase getPermissibleBase() { + if (PatchBukkitEntity.perm == null) { + PatchBukkitEntity.perm = new PermissibleBase(new ServerOperator() { + + @Override + public boolean isOp() { + return false; + } + + @Override + public void setOp(boolean value) { + + } + }); + } + return PatchBukkitEntity.perm; + } + @Override public void setMetadata(@NotNull String metadataKey, @NotNull MetadataValue newMetadataValue) { // TODO Auto-generated method stub @@ -127,15 +150,13 @@ public class PatchBukkitEntity implements Entity { } @Override - public boolean hasPermission(@NotNull String name) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'hasPermission'"); + public boolean hasPermission(String name) { + return PatchBukkitEntity.getPermissibleBase().hasPermission(name); } @Override - public boolean hasPermission(@NotNull Permission perm) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'hasPermission'"); + public boolean hasPermission(Permission perm) { + return PatchBukkitEntity.getPermissibleBase().hasPermission(perm); } @Override @@ -183,14 +204,12 @@ public class PatchBukkitEntity implements Entity { @Override public boolean isOp() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'isOp'"); + return PatchBukkitEntity.getPermissibleBase().isOp(); } @Override public void setOp(boolean value) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'setOp'"); + PatchBukkitEntity.getPermissibleBase().setOp(value); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/permissions/PatchBukkitPermissionManager.java b/java/patchbukkit/src/main/java/org/patchbukkit/permissions/PatchBukkitPermissionManager.java new file mode 100644 index 0000000..fd843fc --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/permissions/PatchBukkitPermissionManager.java @@ -0,0 +1,219 @@ +package org.patchbukkit.permissions; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.HashSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; + +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableSet; + +import io.papermc.paper.plugin.PermissionManager; + +public class PatchBukkitPermissionManager implements PermissionManager { + private final Map permissions = new HashMap<>(); + private final Map> defaultPerms = new LinkedHashMap<>(); + private final Map> permSubs = new HashMap<>(); + private final Map> defSubs = new HashMap<>(); + + public PatchBukkitPermissionManager() { + this.defaultPerms().put(true, new LinkedHashSet<>()); + this.defaultPerms().put(false, new LinkedHashSet<>()); + } + + public Map permissions() { + return this.permissions; + } + + public Map> defaultPerms() { + return this.defaultPerms; + } + + public Map> permSubs() { + return this.permSubs; + } + + public Map> defSubs() { + return this.defSubs; + } + + @Override + @Nullable + public Permission getPermission(@NotNull String name) { + return this.permissions().get(name.toLowerCase(java.util.Locale.ENGLISH)); + } + + @Override + public void addPermission(@NotNull Permission perm) { + this.addPermission(perm, true); + } + + @Override + public void addPermissions(@NotNull List permissions) { + for (Permission permission : permissions) { + this.addPermission(permission, false); + } + this.dirtyPermissibles(); + } + + // Allow suppressing permission default calculations + private void addPermission(@NotNull Permission perm, boolean dirty) { + String name = perm.getName().toLowerCase(java.util.Locale.ENGLISH); + + if (this.permissions().containsKey(name)) { + throw new IllegalArgumentException("The permission " + name + " is already defined!"); + } + + this.permissions().put(name, perm); + this.calculatePermissionDefault(perm, dirty); + } + + @Override + @NotNull + public Set getDefaultPermissions(boolean op) { + return ImmutableSet.copyOf(this.defaultPerms().get(op)); + } + + + @Override + public void removePermission(@NotNull Permission perm) { + this.removePermission(perm.getName()); + } + + + @Override + public void removePermission(@NotNull String name) { + this.permissions().remove(name.toLowerCase(java.util.Locale.ENGLISH)); + } + + @Override + public void recalculatePermissionDefaults(@NotNull Permission perm) { + // we need a null check here because some plugins for some unknown reason pass null into this? + if (perm != null && this.permissions().containsKey(perm.getName().toLowerCase(Locale.ROOT))) { + this.defaultPerms().get(true).remove(perm); + this.defaultPerms().get(false).remove(perm); + + this.calculatePermissionDefault(perm, true); + } + } + + private void calculatePermissionDefault(@NotNull Permission perm, boolean dirty) { + if ((perm.getDefault() == PermissionDefault.OP) || (perm.getDefault() == PermissionDefault.TRUE)) { + this.defaultPerms().get(true).add(perm); + if (dirty) { + this.dirtyPermissibles(true); + } + } + if ((perm.getDefault() == PermissionDefault.NOT_OP) || (perm.getDefault() == PermissionDefault.TRUE)) { + this.defaultPerms().get(false).add(perm); + if (dirty) { + this.dirtyPermissibles(false); + } + } + } + + + @Override + public void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible) { + String name = permission.toLowerCase(java.util.Locale.ENGLISH); + Map map = this.permSubs().computeIfAbsent(name, k -> new WeakHashMap<>()); + + map.put(permissible, true); + } + + @Override + public void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible) { + String name = permission.toLowerCase(java.util.Locale.ENGLISH); + Map map = this.permSubs().get(name); + + if (map != null) { + map.remove(permissible); + + if (map.isEmpty()) { + this.permSubs().remove(name); + } + } + } + + @Override + @NotNull + public Set getPermissionSubscriptions(@NotNull String permission) { + String name = permission.toLowerCase(java.util.Locale.ENGLISH); + Map map = this.permSubs().get(name); + + if (map == null) { + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(map.keySet()); + } + } + + @Override + public void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible) { + Map map = this.defSubs().computeIfAbsent(op, k -> new WeakHashMap<>()); + + map.put(permissible, true); + } + + @Override + public void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible) { + Map map = this.defSubs().get(op); + + if (map != null) { + map.remove(permissible); + + if (map.isEmpty()) { + this.defSubs().remove(op); + } + } + } + + @Override + @NotNull + public Set getDefaultPermSubscriptions(boolean op) { + Map map = this.defSubs().get(op); + + if (map == null) { + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(map.keySet()); + } + } + + @Override + @NotNull + public Set getPermissions() { + return new HashSet<>(this.permissions().values()); + } + + @Override + public void clearPermissions() { + this.permissions().clear(); + this.defaultPerms().get(true).clear(); + this.defaultPerms().get(false).clear(); + } + + + void dirtyPermissibles(boolean op) { + Set permissibles = this.getDefaultPermSubscriptions(op); + + for (Permissible p : permissibles) { + p.recalculatePermissions(); + } + } + + void dirtyPermissibles() { + this.dirtyPermissibles(true); + this.dirtyPermissibles(false); + } +}