From 84ffc409cbf12d250871b27ecfe144692a517698 Mon Sep 17 00:00:00 2001 From: JernejTDO Date: Fri, 11 Jul 2025 21:33:16 +0200 Subject: [PATCH] UTD --- README.md | 39 ++++--- .../Spigot/Permissible/CustomPermissible.java | 37 +++++-- .../Spigot/data/GroupData.java | 51 ++++++--- .../LitePermissions/Spigot/data/UserData.java | 104 ++++++++++++------ .../Permissible/CustomPermissible.class | Bin 4675 -> 5587 bytes 5 files changed, 157 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 7daf90c..a660c9d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # LitePermissions (Spigot / BungeeCord Plugin) **LitePermissions** is a lightweight, hybrid permissions plugin designed for **Spigot and BungeeCord** servers. -It aims to offer clean, fast, and flexible permission management across single or multi-server networks, with future support for web and GUI configuration. +It aims to offer clean, fast, and flexible permission management across single or multi-server networks, with full support for **multi-world** and **per-user overrides**. --- @@ -16,10 +16,10 @@ This plugin is currently in **active development**. Major features are being imp ### Core Features - βœ… **Custom Permissible Injection** (Spigot) -- πŸ”„ **GroupsData** – Group-based permission management -- πŸ”„ **UserData** – Per-player permission storage and overrides -- πŸ”„ **Reload Command** – Reload permissions without restarting -- πŸ”„ **Multi-world Permission Support** +- βœ… **Multi-world Permission Support** – Define permissions per world +- πŸ”„ **GroupsData** – Group-based permission management with weights +- πŸ”„ **UserData** – Per-player permission overrides +- πŸ”„ **Reload Command** – Reload permission data without restarting ### GUI & Web - πŸ”„ **GUI Editor** – In-game menus to manage permissions and groups @@ -32,16 +32,27 @@ This plugin is currently in **active development**. Major features are being imp --- -## πŸ“Š Permission Resolution Logic +## πŸ“Š How Permissions Are Decided -When checking permissions, **user-defined permissions always override group-defined ones**, and groups are sorted by weight: +LitePermissions checks permissions in this priority order: -| User Permission | Group Permission | Final Result | Source | -| --------------- | ---------------- | ------------ | ------------ | -| `true` | `false` | βœ… `true` | `user` | -| `false` | `true` | ❌ `false` | `user` | -| *(none)* | `true` | βœ… `true` | `group:name` | -| *(none)* | *(none)* | ❌ `false` | `none` | +1. βœ… User's **world-specific** permission +2. βœ… User's **global** permission +3. βœ… Group’s **world-specific** permission (highest-weight group only) +4. βœ… Group’s **global** permission (highest-weight group only) +5. ❌ If not found anywhere, permission is **denied by default** + +--- + +### πŸ” Examples + +| Where is it set? | User Value | Group Value | Final Result | Why? | +|---------------------|------------|-------------|--------------|----------------------------| +| In world settings | `true` | `false` | βœ… `true` | User's world setting wins | +| In world settings | `false` | `true` | ❌ `false` | User's world setting wins | +| Global (not world) | `true` | `false` | βœ… `true` | User's global setting wins | +| Not set for user | *(none)* | `true` | βœ… `true` | Comes from group | +| Not set anywhere | *(none)* | *(none)* | ❌ `false` | Denied by default | --- @@ -49,6 +60,6 @@ When checking permissions, **user-defined permissions always override group-defi > ⚠️ No public releases yet. Clone and build manually. -### Spigot +### Spigot Installation ```bash git clone https://git.triler.eu/JernejTDO/LitePermissions.git diff --git a/src/main/java/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.java b/src/main/java/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.java index 1093d73..63b64a1 100644 --- a/src/main/java/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.java +++ b/src/main/java/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.java @@ -1,6 +1,7 @@ package si.jernejtdo.LitePermissions.Spigot.Permissible; import java.util.Comparator; +import java.util.Map; import java.util.Optional; import org.bukkit.entity.Player; @@ -41,20 +42,35 @@ public class CustomPermissible extends PermissibleBase { boolean result = false; String source = "none"; + String world = player.getWorld().getName().toLowerCase(); + if (user != null) { - // 1. User-defined permission ALWAYS overrides - if (user.getPermissions().containsKey(inName)) { - result = user.getPermissions().get(inName); // true or false - source = "user"; + Map userWorld = user.getWorldPermissions(world); + Map userGlobal = user.getGlobalPermissions(); + + if (userWorld.containsKey(inName)) { + result = userWorld.get(inName); + source = "user (world)"; + } else if (userGlobal.containsKey(inName)) { + result = userGlobal.get(inName); + source = "user (global)"; } else { - // 2. Find highest-weight group that defines it - Optional groupWithPermission = user.getGroups().stream() - .filter(g -> g.getPermissions().containsKey(inName)) + Optional groupMatch = user.getGroups().stream() + .filter(g -> g.getWorldPermissions(world).containsKey(inName)) .max(Comparator.comparingInt(GroupData::getWeight)); - if (groupWithPermission.isPresent()) { - result = groupWithPermission.get().getPermissions().get(inName); - source = "group:" + groupWithPermission.get().getName(); + if (groupMatch.isPresent()) { + result = groupMatch.get().getWorldPermissions(world).get(inName); + source = "group:" + groupMatch.get().getName() + " (world)"; + } else { + groupMatch = user.getGroups().stream() + .filter(g -> g.getGlobalPermissions().containsKey(inName)) + .max(Comparator.comparingInt(GroupData::getWeight)); + + if (groupMatch.isPresent()) { + result = groupMatch.get().getGlobalPermissions().get(inName); + source = "group:" + groupMatch.get().getName() + " (global)"; + } } } } @@ -67,6 +83,7 @@ public class CustomPermissible extends PermissibleBase { + public Player getPlayer() { return player; } diff --git a/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/GroupData.java b/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/GroupData.java index fe74903..c53b661 100644 --- a/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/GroupData.java +++ b/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/GroupData.java @@ -7,18 +7,45 @@ public class GroupData { private String name; private String prefix; private String suffix; - private int weight = 0; // Default weight - private Map permissions = new HashMap<>(); + private int weight = 0; + + private final Map globalPermissions = new HashMap<>(); + private final Map> worldPermissions = new HashMap<>(); public GroupData(String name) { this.name = name; } - public boolean hasPermission(String permission) { - return permissions.getOrDefault(permission, false); + // Global + public void setPermission(String permission, boolean value) { + globalPermissions.put(permission.toLowerCase(), value); } - // --- Getters and setters --- + public Map getGlobalPermissions() { + return globalPermissions; + } + + // World-specific + public void setWorldPermission(String world, String permission, boolean value) { + worldPermissions + .computeIfAbsent(world.toLowerCase(), k -> new HashMap<>()) + .put(permission.toLowerCase(), value); + } + + public Map getWorldPermissions(String world) { + return worldPermissions.getOrDefault(world.toLowerCase(), new HashMap<>()); + } + + public boolean hasPermission(String permission, String world) { + return getWorldPermissions(world).getOrDefault(permission.toLowerCase(), + globalPermissions.getOrDefault(permission.toLowerCase(), false)); + } + + // Getters and setters... + + public String getName() { + return name; + } public int getWeight() { return weight; @@ -28,14 +55,6 @@ public class GroupData { this.weight = weight; } - public Map getPermissions() { - return permissions; - } - - public String getName() { - return name; - } - public String getPrefix() { return prefix; } @@ -51,8 +70,4 @@ public class GroupData { public void setSuffix(String suffix) { this.suffix = suffix; } - - public void setPermission(String perm, boolean value) { - permissions.put(perm, value); - } -} \ No newline at end of file +} diff --git a/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/UserData.java b/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/UserData.java index 30b60f1..29b1857 100644 --- a/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/UserData.java +++ b/src/main/java/si/jernejtdo/LitePermissions/Spigot/data/UserData.java @@ -1,26 +1,78 @@ package si.jernejtdo.LitePermissions.Spigot.data; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - import java.util.*; public class UserData { - private UUID uuid; + private final UUID uuid; private String prefix; private String suffix; - private final Map permissions = new HashMap<>(); + + private final Map globalPermissions = new HashMap<>(); + private final Map> worldPermissions = new HashMap<>(); private final Set groups = new HashSet<>(); public UserData(UUID uuid) { this.uuid = uuid; } + // --- Permission Management --- + + public void setPermission(String permission, boolean value) { + globalPermissions.put(permission.toLowerCase(), value); + } + + public Map getGlobalPermissions() { + return Collections.unmodifiableMap(globalPermissions); + } + + public void setWorldPermission(String world, String permission, boolean value) { + worldPermissions + .computeIfAbsent(world.toLowerCase(), k -> new HashMap<>()) + .put(permission.toLowerCase(), value); + } + + public Map getWorldPermissions(String world) { + return worldPermissions.getOrDefault(world.toLowerCase(), Collections.emptyMap()); + } + + public boolean hasPermission(String rawPermission, String rawWorld) { + final String permission = rawPermission.toLowerCase(); // βœ… FIXED + final String world = rawWorld.toLowerCase(); // βœ… FIXED + + // 1. User world-specific + Boolean userWorld = getWorldPermissions(world).get(permission); + if (userWorld != null) return userWorld; + + // 2. User global + Boolean userGlobal = globalPermissions.get(permission); + if (userGlobal != null) return userGlobal; + + // 3. Group world-specific + Optional groupMatch = groups.stream() + .filter(g -> g.getWorldPermissions(world).containsKey(permission)) + .max(Comparator.comparingInt(GroupData::getWeight)); + + if (groupMatch.isPresent()) { + return groupMatch.get().getWorldPermissions(world).get(permission); + } + + // 4. Group global + groupMatch = groups.stream() + .filter(g -> g.getGlobalPermissions().containsKey(permission)) + .max(Comparator.comparingInt(GroupData::getWeight)); + + if (groupMatch.isPresent()) { + return groupMatch.get().getGlobalPermissions().get(permission); + } + + // 5. Default deny + return false; + } + // --- Group Management --- public void addGroup(GroupData group) { - groups.add(group); + if (group != null) groups.add(group); } public void removeGroup(GroupData group) { @@ -28,7 +80,7 @@ public class UserData { } public Set getGroups() { - return groups; + return Collections.unmodifiableSet(groups); } public GroupData getPrimaryGroup() { @@ -37,23 +89,7 @@ public class UserData { .orElse(null); } - // --- Permission Logic --- - - public boolean hasPermission(String permission) { - // 1. User override - if (permissions.containsKey(permission)) { - return permissions.get(permission); - } - - // 2. Highest-weight group that defines the permission - return groups.stream() - .filter(g -> g.getPermissions().containsKey(permission)) - .max(Comparator.comparingInt(GroupData::getWeight)) - .map(g -> g.getPermissions().get(permission)) - .orElse(false); // default deny - } - - // --- Prefix/Suffix from Primary Group --- + // --- Prefix / Suffix --- public String getPrefix() { return prefix != null ? prefix : getPrimaryGroupPrefix(); @@ -65,21 +101,25 @@ public class UserData { private String getPrimaryGroupPrefix() { GroupData primary = getPrimaryGroup(); - return primary != null ? primary.getPrefix() : ""; + return primary != null && primary.getPrefix() != null ? primary.getPrefix() : ""; } private String getPrimaryGroupSuffix() { GroupData primary = getPrimaryGroup(); - return primary != null ? primary.getSuffix() : ""; + return primary != null && primary.getSuffix() != null ? primary.getSuffix() : ""; } - // --- Permission Map Access --- + // --- Setters / Misc --- - public Map getPermissions() { - return permissions; + public void setPrefix(String prefix) { + this.prefix = prefix; } - public void setPermission(String permission, boolean value) { - permissions.put(permission, value); + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public UUID getUuid() { + return uuid; } } diff --git a/target/classes/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.class b/target/classes/si/jernejtdo/LitePermissions/Spigot/Permissible/CustomPermissible.class index 4bf023fd56f64d180a0964bcb09076295ef37c60..918612c82872e091356bfe11792f27831a6ae2a1 100644 GIT binary patch delta 2076 zcmZuyX>=1+7`-n|GLy-)Nh1})b|@4`o7S?}0tvDOErpgADiq2hQwSk#+SDWk5iyDi zDvRPPY7xN=QA7d7NQxE|MFj;F7gPk?5JiP^{GsQ#eluyC!tqSb%zNLv-+lL6-pj$P z<4)=DKP{~QhT-CFX@fp$hK#W?#=*lN`n-|KU?{MFp^GECBpCALS2xzy`Xl+8)osSL za0KII_=1{P)f#OZ464dZh21}11ZWPdPiS!C@L`Dc+g!@I0WJ3xbRYTj% z#~2IjDx|^&J(|^?C9nZcs^F*iK5?r4X&Kvix~a;fSCh*yv?SSBCceegZInT)00~q9 zZEbG3tbZ6Jbv4m8H1VmmC{-f!7x5#eA=bi6;UoEev6s}=3hq&E{->#w&y|L=Sy~0Q zOJS23Q0l4|C|N^zlQfz4GLJC6i9-V3;IQ{Kiqe5Lt}?VuI2Brv=uqXqjcMjYW6 zkf5kGQk+GzGOFHg(S z|H{ytUody&yUYULl-838Jf2pR(S^#9L3OzjUC@=DZpcJ;o?)58dh@VlBJ0OnEe=Vy zlVB3S%J@Z#J({xzX>p8Uh+{lM3`H(u-XSLD*^M!jxP-hIrn*GC;EZEBbq2a?!`V6< zz`Pi$3-z{zF2gpQu!~8AI_!*Cq#|O(R1-%%gWc$CK?JnnO*%wda4WDEE8@6Y2bali zieXJNhN|E72hgO-c<@rb_N5peYQe*R%09D$owzr(asNN{RZ0IX&Um!5(&P#;Kc+J0 zCergbgEK>KH?-ghP>!}{=y%Zlt*0D=j%8nZ52Tp`HsnwRoUkJgxyZ*LdWK^#Mqwz5 zaW!V50CP}?TDtp}(MlB25m*5iR>Mu9jKo$NZzK3ljK*P%!AXq8Y5He42M>Nz3xsh@ zN4LL(BGwNRSOHz&qfy3+>05#+RB~WpqPiraJI$!h=#K%^+Ilt#&)``);5K#*w&OWE z+Zj>j!VWx7>g}u$FA&gxT%z7dBO@vN8@sR@0!jKEFVaXPdF${J_P~UfiM6$hPU;-ux7%ZSPF|yOFl72wuUzjam?H`y%TK6K(SEXk~XJ`@0 zWC01&BC<;A2_=h(Y=sm}3Vr3=oJ5~cld7fBX{9l0e(p{jGG4`N&=CinxHgUgLhH!K z?2KVcj@IYx6m_5^sC#=lahNp@I`(u1)SX_(8}uDQ$al$h81LhlHu?~s;sj2S|7mUh ZHNM05+Wf5cK8K&kPrY=`;}=|j{Xdi+@}U3# delta 1340 zcmY+DTX0iV6o$W@Cg-HdX`6%w2v8Y1MS1~BDHI5Is+X=(Q`;GF++qlc*&i~!KF`Biw zn~1(_)cEePxECRDW}}&`Vy;fQrs{SxXvBz{?9{u>DFwUOtq+WtRD8G-4 zNm@~Q%}`^ivn!I0WK(I2EZw@!-R6#Qzr_PQsC(QC!uxpG#pV%b;$ zhivRwC3T%@PS=w>)z0TFUeL{+t&aNEvHle5Up*5`$HmgA?yin_c4vDu-5JkhM2W8V z&eeV1HRDZQSNN`VVPiHOPsa3L-i7*t)v9yWV(l+lWc2f)$p^Zci$Z@#ABI9!xU!GiKXo(b}sMo2IAZ&PKu*S}ho>&yPi zoa&V{Q^x+xAamBvtUgQe5Dkg}!fgc&&cL#;Yt}__vj$jEGsG~9{`v4mx zZFAVw&lWkjZHPM*HN$L&A$B+zCIN$V4Y9{T*a#T|?CoW?9dje(_7Cuc5MReNb|ME) z4)YX*U1O>a3UAOEat-qgqVKt&^MvSjiZR$ACgDce%^*OPn64(oOv;!ot6G*YhZWS( zNIk90ql5YKBI?QQkoTTsAw4V-Ys+|t<(!oGi9E20LfL$^I6^i_c2Xv$%Qfs8IP&E&@}JGS zj>0Rd-xjn$9NSs%@}9(U(SAa(lj8r={OYW9@e9rqQhXyp@hul6(VqS9_<