-
-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Discussed in #93
Originally posted by TheMeinerLP November 7, 2024
Intro
In the past you could check in Minestom with Player#hasPermission(String) if the player or entity has the rights.
Problem
There have been discussions that some like to use enum values for permissions and others want to use int values and the next one a string again.
If you want to combine multiple permission systems, the current system is too static.
As a result, the upstream has decided to remove the Permission API (Minestom#2302)
This is a disadvantage for our community, even if it is small.
Solution
In order to solve this problem more technically, we came up with an idea.
We build a permission registry that can combine several permission systems into one. Each developer has the choice of how the best permission system looks from his definition.
Some want to have enum values, others with strings, or others with whole class structures or instances.
In order to realize this, I have prepared a mock-up, which you can view here:
public class ExampleUsage {
public static void main(String[] args) {
PermissionManager instance = PermissionManager.getInstance();
// Providers
instance.registerProvider(PermissionProvider.<String, StringPermissionAttachment>providerBuilder()
.permissionIdentifier(Key.key("example"))
.attachmentType(StringPermissionAttachment.class::isInstance)
.permissionChecker(ExampleUsage::hasPermission)
.senderType(ExampleEntity.class::isInstance)
.build());
// Tranformers
instance.registerTransformer(PermissionTransformerHolder.<EnumExampleAttachment, StringPermissionAttachment>builder()
.permissionTransformer(ExampleUsage::convertFromEnumToString)
.from(EnumExampleAttachment.class::isInstance)
.to(StringPermissionAttachment.class::isInstance)
.identifier(Key.key("example"))
.build());
ExampleEntity boss = new ExampleEntity();
ExampleEntity2 employee = new ExampleEntity2();
System.out.println(boss.hasPermission(EnumExampleAttachment.COOKIE_RIGHTS));
System.out.println(boss.hasPermission(EnumExampleAttachment.SODA_RIGHTS));
System.out.println(boss.hasPermission(StringPermissionAttachment.of("example")));
System.out.println(employee.hasPermission(StringPermissionAttachment.of("example")));
System.out.println("-------------------");
instance.unregisterProvider(Key.key("example"));
instance.registerProvider(PermissionProvider.<String, StringPermissionAttachment>providerBuilder()
.permissionIdentifier(Key.key("example"))
.attachmentType(StringPermissionAttachment.class::isInstance)
.permissionChecker(ExampleUsage::hasPermission)
.senderType(ExampleEntity2.class::isInstance)
.build());
System.out.println(boss.hasPermission(EnumExampleAttachment.COOKIE_RIGHTS));
System.out.println(boss.hasPermission(EnumExampleAttachment.SODA_RIGHTS));
System.out.println(boss.hasPermission(StringPermissionAttachment.of("example")));
System.out.println(employee.hasPermission(StringPermissionAttachment.of("example")));
}
private static StringPermissionAttachment convertFromEnumToString(EnumExampleAttachment enumExampleAttachment) {
return StringPermissionAttachment.of(enumExampleAttachment.name());
}
static class ExampleEntity implements CommandSender, Permissible {
@Override
public @NotNull Identity identity() {
return null;
}
@Override
public boolean hasPermission(PermissionAttachment<?> permission) {
return PermissionManager.getInstance().hasPermission(permission, this);
}
@Override
public @NotNull TagHandler tagHandler() {
return null;
}
@Override
public @NotNull Set<Permission> getAllPermissions() {
return Set.of();
}
}
static class ExampleEntity2 implements CommandSender, Permissible {
@Override
public @NotNull Identity identity() {
return null;
}
@Override
public boolean hasPermission(PermissionAttachment<?> permission) {
return PermissionManager.getInstance().hasPermission(permission, this);
}
@Override
public @NotNull TagHandler tagHandler() {
return null;
}
@Override
public @NotNull Set<Permission> getAllPermissions() {
return Set.of();
}
}
private static boolean hasPermission(PermissionAttachment<String> permission, CommandSender sender) {
if (permission.permissionValue().equals(EnumExampleAttachment.SODA_RIGHTS.name())) {
return true;
}
return permission.permissionValue().equals("example");
}
}The solution offers every developer the opportunity to integrate their own solution and even address different transmitters. In addition, the API is hardened and yet modularly expandable.
The goal ...
... was to offer a pure API that is intended as a framework in the server for checking permissions, and only the manager instance is addressed internally. The actual checks are then carried out by the developer, and only the internal interface interlocking is then used by the framework.
Current status/draft PR
Soon
Proposal / Future Changes / Missing features
- Another possibility to map data from system A to system B would be to add a possibility to the system to convert data using transformers, e.g.
- In the given mockup, for example, the possibility to completely replace a provider and replace it with its own is missing.
- A standard permission provider is not specified in the mockup, but will be included in the finalization for a basic system, which can optionally be turned on or off with a ServerFlag to decide between RAW (no permission system) or Basic (string-based permission system).
Feedback
This introduction to the system is intended to stimulate discussion and lead to an exchange of opinions!