diff --git a/common/src/main/java/me/lucko/luckperms/common/core/NodeModel.java b/common/src/main/java/me/lucko/luckperms/common/core/NodeModel.java index 4ad72d819..fb0f4d5d6 100644 --- a/common/src/main/java/me/lucko/luckperms/common/core/NodeModel.java +++ b/common/src/main/java/me/lucko/luckperms/common/core/NodeModel.java @@ -28,6 +28,7 @@ package me.lucko.luckperms.common.core; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NonNull; import lombok.ToString; import com.google.common.base.Preconditions; @@ -76,11 +77,17 @@ public final class NodeModel { return of(permission, value, server, world, expiry, deserializeContextSet(context).makeImmutable()); } + @NonNull private final String permission; + @NonNull private final boolean value; + @NonNull private final String server; + @NonNull private final String world; + @NonNull private final long expiry; + @NonNull private final ImmutableContextSet contexts; public String serializeContext() { diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java index 544ad3924..11e939a63 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java @@ -195,7 +195,7 @@ public class StandardStackElements { } } - @ToString + @ToString(of = "trackName") @RequiredArgsConstructor @EqualsAndHashCode(of = "trackName") private static final class HighestPriorityTrack implements MetaStackElement { @@ -213,7 +213,7 @@ public class StandardStackElements { } } - @ToString + @ToString(of = "trackName") @RequiredArgsConstructor @EqualsAndHashCode(of = "trackName") private static final class HighestPriorityNotOnTrack implements MetaStackElement { @@ -261,7 +261,7 @@ public class StandardStackElements { } } - @ToString + @ToString(of = "trackName") @RequiredArgsConstructor @EqualsAndHashCode(of = "trackName") private static final class LowestPriorityTrack implements MetaStackElement { @@ -279,7 +279,7 @@ public class StandardStackElements { } } - @ToString + @ToString(of = "trackName") @RequiredArgsConstructor @EqualsAndHashCode(of = "trackName") private static final class LowestPriorityNotOnTrack implements MetaStackElement { diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java index 08de77ccd..e59e65417 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java @@ -504,6 +504,12 @@ public class JSONBacking extends FlatfileBacking { Set nodes = new HashSet<>(); for (JsonElement ent : permissionsSection) { + if (ent.isJsonPrimitive() && ent.getAsJsonPrimitive().isString()) { + String permission = ent.getAsJsonPrimitive().getAsString(); + nodes.add(NodeModel.of(permission, true, "global", "global", 0L, ImmutableContextSet.empty())); + continue; + } + if (!ent.isJsonObject()) { continue; } @@ -552,6 +558,19 @@ public class JSONBacking extends FlatfileBacking { JsonArray arr = new JsonArray(); for (NodeModel node : nodes) { + // just a raw, default node. + boolean single = node.isValue() && + node.getServer().equalsIgnoreCase("global") && + node.getWorld().equalsIgnoreCase("global") && + node.getExpiry() == 0L && + node.getContexts().isEmpty(); + + // just add a string to the list. + if (single) { + arr.add(new JsonPrimitive(node.getPermission())); + continue; + } + JsonObject attributes = new JsonObject(); attributes.addProperty("value", node.isValue()); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java index f87f66b5f..9964dea0f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java @@ -487,18 +487,30 @@ public class YAMLBacking extends FlatfileBacking { Set nodes = new HashSet<>(); for (Object perm : permissionsSection) { + // each object in the permission list is either a String or Map. + // just a permission with no extra context. + if (perm instanceof String) { + String permission = (String) perm; + nodes.add(NodeModel.of(permission, true, "global", "global", 0L, ImmutableContextSet.empty())); + continue; + } + + // it must be a map at this point. if (!(perm instanceof Map)) { continue; } - Map data = (Map) perm; - Map.Entry entry = Iterables.getFirst(data.entrySet(), null); - - if (entry == null) { + if (((Map) perm).isEmpty()) { continue; } + // the permission object, should only contain one entry. + Map data = (Map) perm; + + // get the only entry in the map. the key is the permission, the object is the attributes associated with it. + Map.Entry entry = Iterables.getFirst(data.entrySet(), null); + String permission = entry.getKey(); if (entry.getValue() != null && entry.getValue() instanceof Map) { @@ -551,10 +563,43 @@ public class YAMLBacking extends FlatfileBacking { return nodes; } - public static List> serializePermissions(Set nodes) { - List> data = new ArrayList<>(); + /** + * Serializes a set of nodes to a format which can be serialised by SnakeYAML. + * (Maps, Lists and raw types) + * + * Returns a list of objects. + * + * Each object is either instanceof String, just a raw permission node with value=true and default context + * + * OR + * + * Is a Map of String to Map. The map contains only one entry, where the key is the permission string, and the value + * is a map containing the attributes of the node. + * + * @param nodes the nodes to serialize + * @return a SnakeYAML friendly representation of the map + */ + public static List serializePermissions(Set nodes) { + List data = new ArrayList<>(); for (NodeModel node : nodes) { + // just a raw, default node. + boolean single = node.isValue() && + node.getServer().equalsIgnoreCase("global") && + node.getWorld().equalsIgnoreCase("global") && + node.getExpiry() == 0L && + node.getContexts().isEmpty(); + + // just add a string to the list. + if (single) { + data.add(node.getPermission()); + continue; + } + + // otherwise, this node has some other special context which needs to be saved. + // we serialise this way so it gets represented nicely in YAML. + + // create a map of node attributes Map attributes = new LinkedHashMap<>(); attributes.put("value", node.isValue()); @@ -588,8 +633,14 @@ public class YAMLBacking extends FlatfileBacking { attributes.put("context", context); } + // create a new map to represent this entry in the list + // the map will only contain one entry. (the permission --> attributes) Map perm = new HashMap<>(); + + // add the node to the map perm.put(node.getPermission(), attributes); + + // add the map to the object list, and continue data.add(perm); }