UTD
This commit is contained in:
39
README.md
39
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
|
||||
|
||||
@@ -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<String, Boolean> userWorld = user.getWorldPermissions(world);
|
||||
Map<String, Boolean> 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<GroupData> groupWithPermission = user.getGroups().stream()
|
||||
.filter(g -> g.getPermissions().containsKey(inName))
|
||||
Optional<GroupData> 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;
|
||||
}
|
||||
|
||||
@@ -7,18 +7,45 @@ public class GroupData {
|
||||
private String name;
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
private int weight = 0; // Default weight
|
||||
private Map<String, Boolean> permissions = new HashMap<>();
|
||||
private int weight = 0;
|
||||
|
||||
private final Map<String, Boolean> globalPermissions = new HashMap<>();
|
||||
private final Map<String, Map<String, Boolean>> 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<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() {
|
||||
return weight;
|
||||
@@ -28,14 +55,6 @@ public class GroupData {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<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<>();
|
||||
|
||||
public UserData(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 ---
|
||||
|
||||
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<GroupData> 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<String, Boolean> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user