- Баллы
- 173
Многие задавались вопросом, как же можно сделать проверку группы permissions в своем плагине прав через обычный player().hasPermission("permissions.args.*"));. Я опишу как такое можно сделать используя магию рефлексии.
Будет полезно тем, кто пишет свой плагин permissions.
Создаем класс. PermissibleBaseEx
Создаем класс. PermissibleInjector
Создаем класс. FieldReplacer
Остается нам добавить игроков в наш PermissibleBaseEx, используем к примеру PlayerJoinEvent.
Будет полезно тем, кто пишет свой плагин permissions.
Создаем класс. PermissibleBaseEx
Java:
package Example;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bukkit.Bukkit;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.permissions.ServerOperator;;
public class PermissibleBaseEx extends PermissibleBase {
private static FieldReplacer<PermissibleBase, Map> PERMISSIONS_FIELD;
private static FieldReplacer<PermissibleBase, List> ATTACHMENTS_FIELD;
private static Method CALC_CHILD_PERMS_METH;
private static final AtomicBoolean LAST_CALL_ERRORED;
private List<PermissionAttachment> attachments;
private Map<String, PermissionAttachmentInfo> permissions;
public PermissibleBaseEx(ServerOperator opable) {
super(opable);
this.permissions = new LinkedHashMap<String, PermissionAttachmentInfo>() {
private static final long serialVersionUID = 1L;
@Override
public PermissionAttachmentInfo put(String k, PermissionAttachmentInfo v) {
PermissionAttachmentInfo existing = this.get(k);
if (existing != null) {
return existing;
}
return super.put(k, v);
}
};
PERMISSIONS_FIELD.set(this, permissions);
attachments = (List)ATTACHMENTS_FIELD.get(this);
recalculatePermissions();
}
@Override
public boolean hasPermission(String inName) {
if (inName == null) {
throw new IllegalArgumentException("Permission name cannot be null");
}
String name = inName.toLowerCase(Locale.ENGLISH);
/**
* Тут пример кастомной проверки со звездочкой.
*/
if(name.endsWith("*") && name.length()>1) {
for(String list : this.permissions.keySet()) {
if(list.startsWith(name.toLowerCase(Locale.ENGLISH).replace("*", ""))) {
return list.replace("*", "").contains(name.replace("*", ""));
}
}
}
if (isPermissionSet(name)) {
return ((PermissionAttachmentInfo)this.permissions.get(name)).getValue();
}
Permission perm = Bukkit.getServer().getPluginManager().getPermission(name);
if (perm != null) {
return perm.getDefault().getValue(isOp());
}
return Permission.DEFAULT_PERMISSION.getValue(isOp());
}
@Override
public boolean hasPermission(Permission perm) {
if (perm == null) {
throw new IllegalArgumentException("Permission cannot be null");
}
String name = perm.getName().toLowerCase(Locale.ENGLISH);
if (isPermissionSet(name)) {
return ((PermissionAttachmentInfo)this.permissions.get(name)).getValue();
}
return perm.getDefault().getValue(isOp());
}
@Override
public boolean isPermissionSet(String name) {
if (name == null) {
throw new IllegalArgumentException("Permission name cannot be null");
}
return this.permissions.containsKey(name.toLowerCase(Locale.ENGLISH));
}
@Override
public boolean isPermissionSet(Permission perm) {
if (perm == null) {
throw new IllegalArgumentException("Permission cannot be null");
}
return isPermissionSet(perm.getName());
}
static {
PERMISSIONS_FIELD = new FieldReplacer<PermissibleBase, Map>(PermissibleBase.class, "permissions", Map.class);
ATTACHMENTS_FIELD = new FieldReplacer<PermissibleBase, List>(PermissibleBase.class, "attachments", List.class);
try {
CALC_CHILD_PERMS_METH = PermissibleBase.class.getDeclaredMethod("calculateChildPermissions", Map.class, Boolean.TYPE, PermissionAttachment.class);
}
catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
PermissibleBaseEx.CALC_CHILD_PERMS_METH.setAccessible(true);
LAST_CALL_ERRORED = new AtomicBoolean(false);
}
}
Создаем класс. PermissibleInjector
Java:
package Example;
import java.lang.reflect.Field;
import java.util.List;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.PermissibleBase;
public class PermissibleInjector {
static Class<?> humanEntity;
public Permissible inject(Player player, Permissible permissible) throws Exception {
Field permField = getPermissibleField(player);
if (permField == null) {
return null;
}
Permissible oldPerm = (Permissible)permField.get(player);
PermissibleBase newBase = (PermissibleBase)permissible;
PermissibleBase oldBase = (PermissibleBase)oldPerm;
copyValues(oldBase, newBase);
permField.set(player, permissible);
return oldPerm;
}
public Permissible getPermissible(Player player) throws Exception {
return (Permissible)getPermissibleField(player).get(player);
}
private Field getPermissibleField(Player player) throws Exception {
if(humanEntity==null) {
return null;
}
if (!humanEntity.isAssignableFrom(player.getClass())) {
return null;
}
Field permField = humanEntity.getDeclaredField("perm");
permField.setAccessible(true);
return permField;
}
private void copyValues(PermissibleBase old, PermissibleBase newPerm) throws Exception {
Field attachmentField = PermissibleBase.class.getDeclaredField("attachments");
attachmentField.setAccessible(true);
List<Object> attachmentPerms = (List)attachmentField.get(newPerm);
attachmentPerms.clear();
attachmentPerms.addAll((List)attachmentField.get(old));
newPerm.recalculatePermissions();
}
static {
String version = org.bukkit.Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
try {
humanEntity = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftHumanEntity");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Создаем класс. FieldReplacer
Java:
package Example;
import java.lang.reflect.Field;
public class FieldReplacer<Instance, Type> {
private final Class<Type> requiredType;
private final Field field;
public FieldReplacer(Class<? extends Instance> clazz, String fieldName, Class<Type> requiredType) {
this.requiredType = requiredType;
this.field = getField(clazz, fieldName);
if (this.field == null) {
throw new ExceptionInInitializerError("No such field " + fieldName + " in class " + clazz);
}
this.field.setAccessible(true);
if (!requiredType.isAssignableFrom(this.field.getType())) {
throw new ExceptionInInitializerError("Field of wrong type");
}
}
public Type get(Instance instance) {
try {
return (Type)this.requiredType.cast(this.field.get(instance));
}
catch (IllegalAccessException e) {
throw new Error(e);
}
}
public void set(Instance instance, Type newValue) {
try {
this.field.set(instance, newValue);
}
catch (IllegalAccessException e) {
throw new Error(e);
}
}
private static Field getField(Class<?> clazz, String fieldName) {
while ((clazz != null) && (clazz != Object.class)) {
try
{
return clazz.getDeclaredField(fieldName);
}
catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
return null;
}
}
Остается нам добавить игроков в наш PermissibleBaseEx, используем к примеру PlayerJoinEvent.
Java:
@EventHandler
public void on(PlayerJoinEvent e) throws Exception {
PermissibleInjector inj = new PermissibleInjector();
inj.inject(e.getPlayer(), new PermissibleBaseEx(e.getPlayer()));
}
Последнее редактирование: