This commit is contained in:
2025-07-11 21:33:16 +02:00
parent 36cd63941b
commit 84ffc409cb
5 changed files with 157 additions and 74 deletions

View File

@@ -1,7 +1,7 @@
# LitePermissions (Spigot / BungeeCord Plugin) # LitePermissions (Spigot / BungeeCord Plugin)
**LitePermissions** is a lightweight, hybrid permissions plugin designed for **Spigot and BungeeCord** servers. **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 ### Core Features
-**Custom Permissible Injection** (Spigot) -**Custom Permissible Injection** (Spigot)
- 🔄 **GroupsData** Group-based permission management - **Multi-world Permission Support** Define permissions per world
- 🔄 **UserData** Per-player permission storage and overrides - 🔄 **GroupsData** Group-based permission management with weights
- 🔄 **Reload Command** Reload permissions without restarting - 🔄 **UserData** Per-player permission overrides
- 🔄 **Multi-world Permission Support** - 🔄 **Reload Command** Reload permission data without restarting
### GUI & Web ### GUI & Web
- 🔄 **GUI Editor** In-game menus to manage permissions and groups - 🔄 **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 | 1. ✅ User's **world-specific** permission
| --------------- | ---------------- | ------------ | ------------ | 2. ✅ User's **global** permission
| `true` | `false` | ✅ `true` | `user` | 3. ✅ Groups **world-specific** permission (highest-weight group only)
| `false` | `true` | ❌ `false` | `user` | 4. ✅ Groups **global** permission (highest-weight group only)
| *(none)* | `true` | ✅ `true` | `group:name` | 5. ❌ If not found anywhere, permission is **denied by default**
| *(none)* | *(none)* | ❌ `false` | `none` |
---
### 🔍 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. > ⚠️ No public releases yet. Clone and build manually.
### Spigot ### Spigot Installation
```bash ```bash
git clone https://git.triler.eu/JernejTDO/LitePermissions.git git clone https://git.triler.eu/JernejTDO/LitePermissions.git

View File

@@ -1,6 +1,7 @@
package si.jernejtdo.LitePermissions.Spigot.Permissible; package si.jernejtdo.LitePermissions.Spigot.Permissible;
import java.util.Comparator; import java.util.Comparator;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -41,20 +42,35 @@ public class CustomPermissible extends PermissibleBase {
boolean result = false; boolean result = false;
String source = "none"; String source = "none";
String world = player.getWorld().getName().toLowerCase();
if (user != null) { if (user != null) {
// 1. User-defined permission ALWAYS overrides Map<String, Boolean> userWorld = user.getWorldPermissions(world);
if (user.getPermissions().containsKey(inName)) { Map<String, Boolean> userGlobal = user.getGlobalPermissions();
result = user.getPermissions().get(inName); // true or false
source = "user"; if (userWorld.containsKey(inName)) {
result = userWorld.get(inName);
source = "user (world)";
} else if (userGlobal.containsKey(inName)) {
result = userGlobal.get(inName);
source = "user (global)";
} else { } else {
// 2. Find highest-weight group that defines it Optional<GroupData> groupMatch = user.getGroups().stream()
Optional<GroupData> groupWithPermission = user.getGroups().stream() .filter(g -> g.getWorldPermissions(world).containsKey(inName))
.filter(g -> g.getPermissions().containsKey(inName))
.max(Comparator.comparingInt(GroupData::getWeight)); .max(Comparator.comparingInt(GroupData::getWeight));
if (groupWithPermission.isPresent()) { if (groupMatch.isPresent()) {
result = groupWithPermission.get().getPermissions().get(inName); result = groupMatch.get().getWorldPermissions(world).get(inName);
source = "group:" + groupWithPermission.get().getName(); 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() { public Player getPlayer() {
return player; return player;
} }

View File

@@ -7,18 +7,45 @@ public class GroupData {
private String name; private String name;
private String prefix; private String prefix;
private String suffix; private String suffix;
private int weight = 0; // Default weight private int weight = 0;
private Map<String, Boolean> permissions = new HashMap<>();
private final Map<String, Boolean> globalPermissions = new HashMap<>();
private final Map<String, Map<String, Boolean>> worldPermissions = new HashMap<>();
public GroupData(String name) { public GroupData(String name) {
this.name = name; this.name = name;
} }
public boolean hasPermission(String permission) { // Global
return permissions.getOrDefault(permission, false); public void setPermission(String permission, boolean value) {
globalPermissions.put(permission.toLowerCase(), value);
} }
// --- Getters and setters --- public Map<String, Boolean> 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<String, Boolean> 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() { public int getWeight() {
return weight; return weight;
@@ -28,14 +55,6 @@ public class GroupData {
this.weight = weight; this.weight = weight;
} }
public Map<String, Boolean> getPermissions() {
return permissions;
}
public String getName() {
return name;
}
public String getPrefix() { public String getPrefix() {
return prefix; return prefix;
} }
@@ -51,8 +70,4 @@ public class GroupData {
public void setSuffix(String suffix) { public void setSuffix(String suffix) {
this.suffix = suffix; this.suffix = suffix;
} }
}
public void setPermission(String perm, boolean value) {
permissions.put(perm, value);
}
}

View File

@@ -1,26 +1,78 @@
package si.jernejtdo.LitePermissions.Spigot.data; package si.jernejtdo.LitePermissions.Spigot.data;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*; import java.util.*;
public class UserData { public class UserData {
private UUID uuid; private final UUID uuid;
private String prefix; private String prefix;
private String suffix; private String suffix;
private final Map<String, Boolean> permissions = new HashMap<>();
private final Map<String, Boolean> globalPermissions = new HashMap<>();
private final Map<String, Map<String, Boolean>> worldPermissions = new HashMap<>();
private final Set<GroupData> groups = new HashSet<>(); private final Set<GroupData> groups = new HashSet<>();
public UserData(UUID uuid) { public UserData(UUID uuid) {
this.uuid = uuid; this.uuid = uuid;
} }
// --- Permission Management ---
public void setPermission(String permission, boolean value) {
globalPermissions.put(permission.toLowerCase(), value);
}
public Map<String, Boolean> 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<String, Boolean> 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<GroupData> 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 --- // --- Group Management ---
public void addGroup(GroupData group) { public void addGroup(GroupData group) {
groups.add(group); if (group != null) groups.add(group);
} }
public void removeGroup(GroupData group) { public void removeGroup(GroupData group) {
@@ -28,7 +80,7 @@ public class UserData {
} }
public Set<GroupData> getGroups() { public Set<GroupData> getGroups() {
return groups; return Collections.unmodifiableSet(groups);
} }
public GroupData getPrimaryGroup() { public GroupData getPrimaryGroup() {
@@ -37,23 +89,7 @@ public class UserData {
.orElse(null); .orElse(null);
} }
// --- Permission Logic --- // --- Prefix / Suffix ---
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 ---
public String getPrefix() { public String getPrefix() {
return prefix != null ? prefix : getPrimaryGroupPrefix(); return prefix != null ? prefix : getPrimaryGroupPrefix();
@@ -65,21 +101,25 @@ public class UserData {
private String getPrimaryGroupPrefix() { private String getPrimaryGroupPrefix() {
GroupData primary = getPrimaryGroup(); GroupData primary = getPrimaryGroup();
return primary != null ? primary.getPrefix() : ""; return primary != null && primary.getPrefix() != null ? primary.getPrefix() : "";
} }
private String getPrimaryGroupSuffix() { private String getPrimaryGroupSuffix() {
GroupData primary = getPrimaryGroup(); GroupData primary = getPrimaryGroup();
return primary != null ? primary.getSuffix() : ""; return primary != null && primary.getSuffix() != null ? primary.getSuffix() : "";
} }
// --- Permission Map Access --- // --- Setters / Misc ---
public Map<String, Boolean> getPermissions() { public void setPrefix(String prefix) {
return permissions; this.prefix = prefix;
} }
public void setPermission(String permission, boolean value) { public void setSuffix(String suffix) {
permissions.put(permission, value); this.suffix = suffix;
}
public UUID getUuid() {
return uuid;
} }
} }