UTD
This commit is contained in:
39
README.md
39
README.md
@@ -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. ✅ Group’s **world-specific** permission (highest-weight group only)
|
||||||
| `false` | `true` | ❌ `false` | `user` |
|
4. ✅ Group’s **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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user