diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java index b1b57ec95..79841d4fa 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java @@ -29,10 +29,10 @@ import me.lucko.luckperms.bukkit.compat.CraftBukkitUtil; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.sender.SenderFactory; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.Component; import net.kyori.text.adapter.bukkit.TextAdapter; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import org.bukkit.command.CommandSender; @@ -82,7 +82,7 @@ public class BukkitSenderFactory extends SenderFactory { TextAdapter.sendComponent(sender, message); } else { // Fallback to legacy format - sendMessage(sender, TextUtils.toLegacy(message)); + sendMessage(sender, LegacyComponentSerializer.INSTANCE.serialize(message)); } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java index 25ad54c2e..c3579cce4 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java @@ -29,10 +29,10 @@ import me.lucko.luckperms.bungee.event.TristateCheckEvent; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.sender.SenderFactory; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.Component; import net.kyori.text.adapter.bungeecord.TextAdapter; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -62,7 +62,7 @@ public class BungeeSenderFactory extends SenderFactory { @Override protected void sendMessage(CommandSender sender, String s) { - sendMessage(sender, TextUtils.fromLegacy(s)); + sendMessage(sender, LegacyComponentSerializer.INSTANCE.deserialize(s)); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/backup/Exporter.java b/common/src/main/java/me/lucko/luckperms/common/backup/Exporter.java index 129ffa579..c95776d4c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/backup/Exporter.java +++ b/common/src/main/java/me/lucko/luckperms/common/backup/Exporter.java @@ -25,32 +25,36 @@ package me.lucko.luckperms.common.backup; +import com.google.gson.JsonObject; + import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.Group; -import me.lucko.luckperms.common.model.HolderType; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.manager.group.GroupManager; -import me.lucko.luckperms.common.node.factory.NodeCommandFactory; +import me.lucko.luckperms.common.node.utils.NodeJsonSerializer; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.storage.Storage; import me.lucko.luckperms.common.util.ProgressLogger; - -import net.luckperms.api.node.Node; -import net.luckperms.api.node.NodeType; +import me.lucko.luckperms.common.util.gson.GsonProvider; +import me.lucko.luckperms.common.util.gson.JArray; +import me.lucko.luckperms.common.util.gson.JObject; import java.io.BufferedWriter; import java.io.IOException; +import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -60,9 +64,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; /** * Handles export operations @@ -70,15 +73,6 @@ import java.util.stream.Collectors; public class Exporter implements Runnable { private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - private static void write(BufferedWriter writer, String s) { - try { - writer.write(s); - writer.newLine(); - } catch (IOException e) { - e.printStackTrace(); - } - } - private final LuckPermsPlugin plugin; private final Sender executor; private final Path filePath; @@ -98,184 +92,128 @@ public class Exporter implements Runnable { @Override public void run() { - try (BufferedWriter writer = Files.newBufferedWriter(this.filePath, StandardCharsets.UTF_8)) { - this.log.log("Starting."); + JsonObject file = new JsonObject(); + file.add("metadata", new JObject() + .add("generatedBy", this.executor.getNameWithLocation()) + .add("generatedAt", DATE_FORMAT.format(new Date(System.currentTimeMillis()))) + .toJson()); - write(writer, "# LuckPerms Export File"); - write(writer, "# Generated by " + this.executor.getNameWithLocation() + " at " + DATE_FORMAT.format(new Date(System.currentTimeMillis()))); - write(writer, ""); + this.log.log("Gathering group data..."); + file.add("groups", exportGroups()); - // Export Groups - this.log.log("Starting group export."); + this.log.log("Gathering track data..."); + file.add("tracks", exportTracks()); - // Create the actual groups first - write(writer, "# Create groups"); + if (this.includeUsers) { + this.log.log("Gathering user data..."); + file.add("users", exportUsers()); + } - AtomicInteger groupCount = new AtomicInteger(0); + this.log.log("Finished gathering data, writing file..."); - List groups = this.plugin.getGroupManager().getAll().values().stream() - // export groups in order of weight - .sorted((o1, o2) -> { - int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0)); - return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName()); - }).collect(Collectors.toList()); - - for (Group group : groups) { - if (!group.getName().equals(GroupManager.DEFAULT_GROUP_NAME)) { - write(writer, "/lp creategroup " + group.getName()); - } - } - - for (Group group : groups) { - if (groupCount.get() == 0) { - write(writer, ""); - } - - write(writer, "# Export group: " + group.getName()); - for (Node node : group.normalData().immutable().values()) { - write(writer, "/lp " + NodeCommandFactory.generateCommand(node, group.getName(), HolderType.GROUP, true, false)); - } - write(writer, ""); - this.log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet()); - } - - this.log.log("Exported " + groupCount.get() + " groups."); - - write(writer, ""); - write(writer, ""); - - // Export tracks - this.log.log("Starting track export."); - - Collection tracks = this.plugin.getTrackManager().getAll().values(); - if (!tracks.isEmpty()) { - - // Create the actual tracks first - write(writer, "# Create tracks"); - for (Track track : tracks) { - write(writer, "/lp createtrack " + track.getName()); - } - - write(writer, ""); - - AtomicInteger trackCount = new AtomicInteger(0); - for (Track track : this.plugin.getTrackManager().getAll().values()) { - write(writer, "# Export track: " + track.getName()); - for (String group : track.getGroups()) { - write(writer, "/lp track " + track.getName() + " append " + group); - } - write(writer, ""); - this.log.logAllProgress("Exported {} tracks so far.", trackCount.incrementAndGet()); - } - - write(writer, ""); - write(writer, ""); - } - - this.log.log("Exported " + tracks.size() + " tracks."); - - if (this.includeUsers) { - // Users are migrated in separate threads. - // This is because there are likely to be a lot of them, and because we can. - // It's a big speed improvement, since the database/files are split up and can handle concurrent reads. - - this.log.log("Starting user export. Finding a list of unique users to export."); - - // Find all of the unique users we need to export - Storage ds = this.plugin.getStorage(); - Set users = ds.getUniqueUsers().join(); - this.log.log("Found " + users.size() + " unique users to export."); - - write(writer, "# Export users"); - - // create a threadpool to process the users concurrently - ExecutorService executor = Executors.newFixedThreadPool(32); - - // Setup a file writing lock. We don't want multiple threads writing at the same time. - // The write function accepts a list of strings, as we want a user's data to be grouped together. - // This means it can be processed and added in one go. - ReentrantLock lock = new ReentrantLock(); - Consumer> writeFunction = strings -> { - lock.lock(); - try { - for (String s : strings) { - write(writer, s); - } - } finally { - lock.unlock(); - } - }; - - // A set of futures, which are really just the processes we need to wait for. - Set> futures = new HashSet<>(); - - AtomicInteger userCount = new AtomicInteger(0); - - // iterate through each user. - for (UUID uuid : users) { - // register a task for the user, and schedule it's execution with the pool - futures.add(CompletableFuture.runAsync(() -> { - // actually export the user. this output will be fed to the writing function when we have all of the user's data. - List output = new ArrayList<>(); - - User user = this.plugin.getStorage().loadUser(uuid, null).join(); - output.add("# Export user: " + user.getUniqueId().toString() + " - " + user.getUsername().orElse("unknown username")); - - boolean inDefault = false; - for (Node node : user.normalData().immutable().values()) { - if (NodeType.INHERITANCE.tryCast(node).map(n -> n.getGroupName().equalsIgnoreCase(GroupManager.DEFAULT_GROUP_NAME)).orElse(false)) { - inDefault = true; - continue; - } - - output.add("/lp " + NodeCommandFactory.generateCommand(node, user.getUniqueId().toString(), HolderType.USER, true, false)); - } - - if (!user.getPrimaryGroup().getStoredValue().orElse(GroupManager.DEFAULT_GROUP_NAME).equalsIgnoreCase(GroupManager.DEFAULT_GROUP_NAME)) { - output.add("/lp user " + user.getUniqueId().toString() + " switchprimarygroup " + user.getPrimaryGroup().getStoredValue().get()); - } - - if (!inDefault) { - output.add("/lp user " + user.getUniqueId().toString() + " parent remove default"); - } - - this.plugin.getUserManager().cleanup(user); - writeFunction.accept(output); - - userCount.incrementAndGet(); - }, executor)); - } - - // all of the threads have been scheduled now and are running. we just need to wait for them all to complete - CompletableFuture overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); - - while (true) { - try { - overallFuture.get(5, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException e) { - // abnormal error - just break - e.printStackTrace(); - break; - } catch (TimeoutException e) { - // still executing - send a progress report and continue waiting - this.log.logAllProgress("Exported {} users so far.", userCount.get()); - continue; - } - - // process is complete - break; - } - - executor.shutdown(); - this.log.log("Exported " + userCount.get() + " users."); - } - - - writer.flush(); - this.log.getListeners().forEach(l -> Message.LOG_EXPORT_SUCCESS.send(l, this.filePath.toFile().getAbsolutePath())); - - } catch (Exception e) { + try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(this.filePath)), StandardCharsets.UTF_8))) { + GsonProvider.prettyPrinting().toJson(file, out); + } catch (IOException e) { e.printStackTrace(); } + + this.log.getListeners().forEach(l -> Message.LOG_EXPORT_SUCCESS.send(l, this.filePath.toFile().getAbsolutePath())); + } + + private JsonObject exportGroups() { + JsonObject out = new JsonObject(); + List groups = this.plugin.getGroupManager().getAll().values().stream() + .sorted((o1, o2) -> { + int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0)); + return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName()); + }).collect(Collectors.toList()); + + for (Group group : groups) { + out.add(group.getName(), new JObject() + .add("nodes", NodeJsonSerializer.serializeNodes(group.normalData().asSet())) + .toJson()); + } + return out; + } + + private JsonObject exportTracks() { + JsonObject out = new JsonObject(); + Collection tracks = this.plugin.getTrackManager().getAll().values(); + + for (Track track : tracks) { + out.add(track.getName(), new JObject() + .add("groups", new JArray().consume(arr -> track.getGroups().forEach(arr::add))) + .toJson()); + } + return out; + } + + private JsonObject exportUsers() { + // Users are migrated in separate threads. + // This is because there are likely to be a lot of them, and because we can. + // It's a big speed improvement, since the database/files are split up and can handle concurrent reads. + + this.log.log("Finding a list of unique users to export."); + + // Find all of the unique users we need to export + Storage ds = this.plugin.getStorage(); + Set users = ds.getUniqueUsers().join(); + this.log.log("Found " + users.size() + " unique users to export."); + + // create a threadpool to process the users concurrently + ExecutorService executor = Executors.newFixedThreadPool(32); + + // A set of futures, which are really just the processes we need to wait for. + Set> futures = new HashSet<>(); + + AtomicInteger userCount = new AtomicInteger(0); + Map out = Collections.synchronizedMap(new HashMap<>()); + + // iterate through each user. + for (UUID uuid : users) { + // register a task for the user, and schedule it's execution with the pool + futures.add(CompletableFuture.runAsync(() -> { + User user = this.plugin.getStorage().loadUser(uuid, null).join(); + out.put(user.getUniqueId(), new JObject() + .consume(obj -> { + user.getUsername().ifPresent(username -> obj.add("username", username)); + if (!user.getPrimaryGroup().getStoredValue().orElse(GroupManager.DEFAULT_GROUP_NAME).equalsIgnoreCase(GroupManager.DEFAULT_GROUP_NAME)) { + obj.add("primaryGroup", user.getPrimaryGroup().getStoredValue().get()); + } + }) + .add("nodes", NodeJsonSerializer.serializeNodes(user.normalData().asSet())) + .toJson()); + this.plugin.getUserManager().cleanup(user); + userCount.incrementAndGet(); + }, executor)); + } + + // all of the threads have been scheduled now and are running. we just need to wait for them all to complete + CompletableFuture overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + + while (true) { + try { + overallFuture.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException e) { + // abnormal error - just break + e.printStackTrace(); + break; + } catch (TimeoutException e) { + // still executing - send a progress report and continue waiting + this.log.logAllProgress("Exported {} users so far.", userCount.get()); + continue; + } + + // process is complete + break; + } + + executor.shutdown(); + + JsonObject outJson = new JsonObject(); + for (Map.Entry entry : out.entrySet()) { + outJson.add(entry.getKey().toString(), entry.getValue()); + } + return outJson; } } diff --git a/common/src/main/java/me/lucko/luckperms/common/backup/Importer.java b/common/src/main/java/me/lucko/luckperms/common/backup/Importer.java index 2c5ff2a4c..21e0fb0b2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/backup/Importer.java +++ b/common/src/main/java/me/lucko/luckperms/common/backup/Importer.java @@ -25,24 +25,31 @@ package me.lucko.luckperms.common.backup; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.MultimapBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; -import me.lucko.luckperms.common.command.CommandManager; -import me.lucko.luckperms.common.command.CommandResult; import me.lucko.luckperms.common.locale.message.Message; -import me.lucko.luckperms.common.sender.DummySender; +import me.lucko.luckperms.common.model.Group; +import me.lucko.luckperms.common.model.Track; +import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.node.utils.NodeJsonSerializer; +import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; +import net.luckperms.api.event.cause.CreationCause; +import net.luckperms.api.model.DataType; +import net.luckperms.api.node.Node; + import java.util.ArrayList; -import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -50,35 +57,59 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; /** * Handles import operations */ public class Importer implements Runnable { - private final CommandManager commandManager; + private final LuckPermsPlugin plugin; private final Set notify; - private final List commandList; - private final List commands; + private final JsonObject data; - public Importer(CommandManager commandManager, Sender executor, List commands) { - this.commandManager = commandManager; + public Importer(LuckPermsPlugin plugin, Sender executor, JsonObject data) { + this.plugin = plugin; if (executor.isConsole()) { this.notify = ImmutableSet.of(executor); } else { - this.notify = ImmutableSet.of(executor, commandManager.getPlugin().getConsoleSender()); + this.notify = ImmutableSet.of(executor, plugin.getConsoleSender()); } - this.commandList = commands.stream() - .map(String::trim) - .filter(s -> !s.isEmpty()) - .filter(s -> !s.startsWith("#")) - .filter(s -> !s.startsWith("//")) - .map(s -> s.startsWith("/luckperms ") ? s.substring("/luckperms ".length()) : s) - .map(s -> s.startsWith("/lp ") ? s.substring("/lp ".length()) : s) - .collect(Collectors.toList()); - this.commands = new ArrayList<>(); + this.data = data; + } + + private static final class UserData { + private final String username; + private final String primaryGroup; + private final Set nodes; + + UserData(String username, String primaryGroup, Set nodes) { + this.username = username; + this.primaryGroup = primaryGroup; + this.nodes = nodes; + } + } + + private void processGroup(String groupName, Set nodes) { + Group group = this.plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join(); + group.setNodes(DataType.NORMAL, nodes); + this.plugin.getStorage().saveGroup(group); + } + + private void processTrack(String trackName, List groups) { + Track track = this.plugin.getStorage().createAndLoadTrack(trackName, CreationCause.INTERNAL).join(); + track.setGroups(groups); + this.plugin.getStorage().saveTrack(track).join(); + } + + private void processUser(UUID uuid, UserData userData) { + User user = this.plugin.getStorage().loadUser(uuid, userData.username).join(); + if (userData.primaryGroup != null) { + user.getPrimaryGroup().setStoredValue(userData.primaryGroup); + } + user.setNodes(DataType.NORMAL, userData.nodes); + this.plugin.getStorage().saveUser(user).join(); + this.plugin.getUserManager().cleanup(user); } @Override @@ -87,28 +118,39 @@ public class Importer implements Runnable { this.notify.forEach(s -> Message.IMPORT_START.send(s)); // start an update task in the background - we'll #join this later - CompletableFuture updateTask = CompletableFuture.runAsync(() -> this.commandManager.getPlugin().getSyncTaskBuffer().requestDirectly()); + CompletableFuture updateTask = CompletableFuture.runAsync(() -> this.plugin.getSyncTaskBuffer().requestDirectly()); - this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Processing commands...")); + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Reading data...")); - // form instances for all commands, and register them - int index = 1; - for (String command : this.commandList) { - ImportCommand cmd = new ImportCommand(this.commandManager, index, command); - this.commands.add(cmd); + Map> groups = new HashMap<>(); + Map> tracks = new HashMap<>(); + Map users = new HashMap<>(); - if (cmd.getCommand().startsWith("creategroup ") || cmd.getCommand().startsWith("createtrack ")) { - cmd.process(); // process immediately + for (Map.Entry group : this.data.get("groups").getAsJsonObject().entrySet()) { + groups.put(group.getKey(), NodeJsonSerializer.deserializeNodes(group.getValue().getAsJsonObject().get("nodes").getAsJsonArray())); + } + for (Map.Entry track : this.data.get("tracks").getAsJsonObject().entrySet()) { + JsonArray trackGroups = track.getValue().getAsJsonObject().get("groups").getAsJsonArray(); + List trackGroupsList = new ArrayList<>(); + trackGroups.forEach(g -> trackGroupsList.add(g.getAsString())); + tracks.put(track.getKey(), trackGroupsList); + } + for (Map.Entry user : this.data.get("users").getAsJsonObject().entrySet()) { + JsonObject jsonData = user.getValue().getAsJsonObject(); + + UUID uuid = UUID.fromString(user.getKey()); + String username = null; + String primaryGroup = null; + Set nodes = NodeJsonSerializer.deserializeNodes(jsonData.get("nodes").getAsJsonArray()); + + if (jsonData.has("username")) { + username = jsonData.get("username").getAsString(); + } + if (jsonData.has("primaryGroup")) { + primaryGroup = jsonData.get("primaryGroup").getAsString(); } - index++; - } - - // split data up into sections for each holder - // holder id --> commands - ListMultimap sections = MultimapBuilder.linkedHashKeys().arrayListValues().build(); - for (ImportCommand cmd : this.commands) { - sections.put(Strings.nullToEmpty(cmd.getTarget()), cmd); + users.put(uuid, new UserData(username, primaryGroup, nodes)); } this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Waiting for initial update task to complete...")); @@ -116,34 +158,43 @@ public class Importer implements Runnable { // join the update task future before scheduling command executions updateTask.join(); - this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Setting up command executor...")); + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Setting up data processor...")); // create a threadpool for the processing - ExecutorService executor = Executors.newFixedThreadPool(128, new ThreadFactoryBuilder().setNameFormat("luckperms-importer-%d").build()); + ExecutorService executor = Executors.newFixedThreadPool(16, new ThreadFactoryBuilder().setNameFormat("luckperms-importer-%d").build()); // A set of futures, which are really just the processes we need to wait for. Set> futures = new HashSet<>(); + int total = 0; AtomicInteger processedCount = new AtomicInteger(0); - // iterate through each user sublist. - for (Collection subList : sections.asMap().values()) { - - // register and start a new thread to process the sublist - futures.add(CompletableFuture.completedFuture(subList).thenAcceptAsync(sl -> { - - // iterate through each user in the sublist, and grab their data. - for (ImportCommand cmd : sl) { - cmd.process(); - processedCount.incrementAndGet(); - } + for (Map.Entry> group : groups.entrySet()) { + futures.add(CompletableFuture.completedFuture(group).thenAcceptAsync(ent -> { + processGroup(ent.getKey(), ent.getValue()); + processedCount.incrementAndGet(); }, executor)); + total++; + } + for (Map.Entry> track : tracks.entrySet()) { + futures.add(CompletableFuture.completedFuture(track).thenAcceptAsync(ent -> { + processTrack(ent.getKey(), ent.getValue()); + processedCount.incrementAndGet(); + }, executor)); + total++; + } + for (Map.Entry user : users.entrySet()) { + futures.add(CompletableFuture.completedFuture(user).thenAcceptAsync(ent -> { + processUser(ent.getKey(), ent.getValue()); + processedCount.incrementAndGet(); + }, executor)); + total++; } // all of the threads have been scheduled now and are running. we just need to wait for them all to complete CompletableFuture overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); - this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "All commands have been processed and scheduled - now waiting for the execution to complete.")); + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "All data entries have been processed and scheduled for import - now waiting for the execution to complete.")); while (true) { try { @@ -154,7 +205,7 @@ public class Importer implements Runnable { break; } catch (TimeoutException e) { // still executing - send a progress report and continue waiting - sendProgress(processedCount.get()); + sendProgress(processedCount.get(), total); continue; } @@ -167,166 +218,12 @@ public class Importer implements Runnable { long endTime = System.currentTimeMillis(); double seconds = (endTime - startTime) / 1000.0; - int errors = (int) this.commands.stream().filter(v -> v.getResult().wasFailure()).count(); - - switch (errors) { - case 0: - this.notify.forEach(s -> Message.IMPORT_END_COMPLETE.send(s, seconds)); - break; - case 1: - this.notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR_SIN.send(s, seconds, errors)); - break; - default: - this.notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR.send(s, seconds, errors)); - break; - } - - AtomicInteger errIndex = new AtomicInteger(1); - for (ImportCommand e : this.commands) { - if (e.getResult() != null && e.getResult().wasFailure()) { - for (Sender s : this.notify) { - Message.IMPORT_END_ERROR_HEADER.send(s, errIndex.get(), e.getId(), e.getCommand(), e.getResult().toString()); - e.getOutput().forEach(out -> Message.IMPORT_END_ERROR_CONTENT.send(s, out)); - Message.IMPORT_END_ERROR_FOOTER.send(s); - } - - errIndex.incrementAndGet(); - } - } + this.notify.forEach(s -> Message.IMPORT_END_COMPLETE.send(s, seconds)); } - private void sendProgress(int processedCount) { - int percent = (processedCount * 100) / this.commandList.size(); - int errors = (int) this.commands.stream().filter(v -> v.isCompleted() && v.getResult().wasFailure()).count(); - - if (errors == 1) { - this.notify.forEach(s -> Message.IMPORT_PROGRESS_SIN.send(s, percent, processedCount, this.commands.size(), errors)); - } else { - this.notify.forEach(s -> Message.IMPORT_PROGRESS.send(s, percent, processedCount, this.commands.size(), errors)); - } - } - - private static class ImportCommand extends DummySender { - private static final Splitter ARGUMENT_SPLITTER = Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings(); - private static final Splitter SPACE_SPLITTER = Splitter.on(" "); - - private final CommandManager commandManager; - private final int id; - private final String command; - - private final String target; - - private boolean completed = false; - - private final List output = new ArrayList<>(); - - private CommandResult result = CommandResult.FAILURE; - - ImportCommand(CommandManager commandManager, int id, String command) { - super(commandManager.getPlugin()); - this.commandManager = commandManager; - this.id = id; - this.command = command; - this.target = determineTarget(command); - } - - @Override - protected void consumeMessage(String s) { - this.output.add(s); - } - - public void process() { - if (isCompleted()) { - return; - } - - try { - List args = CommandManager.stripQuotes(ARGUMENT_SPLITTER.splitToList(getCommand())); - CommandResult result = this.commandManager.onCommand(this, "lp", args, Runnable::run).get(); - setResult(result); - } catch (Exception e) { - setResult(CommandResult.FAILURE); - e.printStackTrace(); - } - - setCompleted(true); - } - - private static String determineTarget(String command) { - if (command.startsWith("user ") && command.length() > "user ".length()) { - String subCmd = command.substring("user ".length()); - if (!subCmd.contains(" ")) { - return null; - } - - String targetUser = SPACE_SPLITTER.split(subCmd).iterator().next(); - return "u:" + targetUser; - } - - if (command.startsWith("group ") && command.length() > "group ".length()) { - String subCmd = command.substring("group ".length()); - if (!subCmd.contains(" ")) { - return null; - } - - String targetGroup = SPACE_SPLITTER.split(subCmd).iterator().next(); - return "g:" + targetGroup; - } - - if (command.startsWith("track ") && command.length() > "track ".length()) { - String subCmd = command.substring("track ".length()); - if (!subCmd.contains(" ")) { - return null; - } - - String targetTrack = SPACE_SPLITTER.split(subCmd).iterator().next(); - return "t:" + targetTrack; - } - - if (command.startsWith("creategroup ") && command.length() > "creategroup ".length()) { - String targetGroup = command.substring("creategroup ".length()); - return "g:" + targetGroup; - } - - if (command.startsWith("createtrack ") && command.length() > "createtrack ".length()) { - String targetTrack = command.substring("createtrack ".length()); - return "t:" + targetTrack; - } - - return null; - } - - public int getId() { - return this.id; - } - - public String getCommand() { - return this.command; - } - - public String getTarget() { - return this.target; - } - - public boolean isCompleted() { - return this.completed; - } - - public List getOutput() { - return this.output; - } - - public CommandResult getResult() { - return this.result; - } - - public void setCompleted(boolean completed) { - this.completed = completed; - } - - public void setResult(CommandResult result) { - this.result = result; - } + private void sendProgress(int processedCount, int total) { + int percent = (processedCount * 100) / total; + this.notify.forEach(s -> Message.IMPORT_PROGRESS.send(s, percent, processedCount, total, 0)); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/backup/LegacyImporter.java b/common/src/main/java/me/lucko/luckperms/common/backup/LegacyImporter.java new file mode 100644 index 000000000..d56fafb35 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/backup/LegacyImporter.java @@ -0,0 +1,332 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.backup; + +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.MultimapBuilder; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import me.lucko.luckperms.common.command.CommandManager; +import me.lucko.luckperms.common.command.CommandResult; +import me.lucko.luckperms.common.locale.message.Message; +import me.lucko.luckperms.common.sender.DummySender; +import me.lucko.luckperms.common.sender.Sender; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * Handles import operations + */ +public class LegacyImporter implements Runnable { + + private final CommandManager commandManager; + private final Set notify; + private final List commandList; + private final List commands; + + public LegacyImporter(CommandManager commandManager, Sender executor, List commands) { + this.commandManager = commandManager; + + if (executor.isConsole()) { + this.notify = ImmutableSet.of(executor); + } else { + this.notify = ImmutableSet.of(executor, commandManager.getPlugin().getConsoleSender()); + } + this.commandList = commands.stream() + .map(String::trim) + .filter(s -> !s.isEmpty()) + .filter(s -> !s.startsWith("#")) + .filter(s -> !s.startsWith("//")) + .map(s -> s.startsWith("/luckperms ") ? s.substring("/luckperms ".length()) : s) + .map(s -> s.startsWith("/lp ") ? s.substring("/lp ".length()) : s) + .collect(Collectors.toList()); + this.commands = new ArrayList<>(); + } + + @Override + public void run() { + long startTime = System.currentTimeMillis(); + this.notify.forEach(s -> Message.IMPORT_START.send(s)); + + // start an update task in the background - we'll #join this later + CompletableFuture updateTask = CompletableFuture.runAsync(() -> this.commandManager.getPlugin().getSyncTaskBuffer().requestDirectly()); + + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Processing commands...")); + + // form instances for all commands, and register them + int index = 1; + for (String command : this.commandList) { + ImportCommand cmd = new ImportCommand(this.commandManager, index, command); + this.commands.add(cmd); + + if (cmd.getCommand().startsWith("creategroup ") || cmd.getCommand().startsWith("createtrack ")) { + cmd.process(); // process immediately + } + + index++; + } + + // split data up into sections for each holder + // holder id --> commands + ListMultimap sections = MultimapBuilder.linkedHashKeys().arrayListValues().build(); + for (ImportCommand cmd : this.commands) { + sections.put(Strings.nullToEmpty(cmd.getTarget()), cmd); + } + + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Waiting for initial update task to complete...")); + + // join the update task future before scheduling command executions + updateTask.join(); + + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "Setting up command executor...")); + + // create a threadpool for the processing + ExecutorService executor = Executors.newFixedThreadPool(128, new ThreadFactoryBuilder().setNameFormat("luckperms-importer-%d").build()); + + // A set of futures, which are really just the processes we need to wait for. + Set> futures = new HashSet<>(); + + AtomicInteger processedCount = new AtomicInteger(0); + + // iterate through each user sublist. + for (Collection subList : sections.asMap().values()) { + + // register and start a new thread to process the sublist + futures.add(CompletableFuture.completedFuture(subList).thenAcceptAsync(sl -> { + + // iterate through each user in the sublist, and grab their data. + for (ImportCommand cmd : sl) { + cmd.process(); + processedCount.incrementAndGet(); + } + }, executor)); + } + + // all of the threads have been scheduled now and are running. we just need to wait for them all to complete + CompletableFuture overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + + this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "All commands have been processed and scheduled - now waiting for the execution to complete.")); + + while (true) { + try { + overallFuture.get(2, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException e) { + // abnormal error - just break + e.printStackTrace(); + break; + } catch (TimeoutException e) { + // still executing - send a progress report and continue waiting + sendProgress(processedCount.get()); + continue; + } + + // process is complete + break; + } + + executor.shutdown(); + + long endTime = System.currentTimeMillis(); + double seconds = (endTime - startTime) / 1000.0; + + int errors = (int) this.commands.stream().filter(v -> v.getResult().wasFailure()).count(); + + switch (errors) { + case 0: + this.notify.forEach(s -> Message.IMPORT_END_COMPLETE.send(s, seconds)); + break; + case 1: + this.notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR_SIN.send(s, seconds, errors)); + break; + default: + this.notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR.send(s, seconds, errors)); + break; + } + + AtomicInteger errIndex = new AtomicInteger(1); + for (ImportCommand e : this.commands) { + if (e.getResult() != null && e.getResult().wasFailure()) { + for (Sender s : this.notify) { + Message.IMPORT_END_ERROR_HEADER.send(s, errIndex.get(), e.getId(), e.getCommand(), e.getResult().toString()); + e.getOutput().forEach(out -> Message.IMPORT_END_ERROR_CONTENT.send(s, out)); + Message.IMPORT_END_ERROR_FOOTER.send(s); + } + + errIndex.incrementAndGet(); + } + } + } + + private void sendProgress(int processedCount) { + int percent = (processedCount * 100) / this.commandList.size(); + int errors = (int) this.commands.stream().filter(v -> v.isCompleted() && v.getResult().wasFailure()).count(); + + if (errors == 1) { + this.notify.forEach(s -> Message.IMPORT_PROGRESS_SIN.send(s, percent, processedCount, this.commands.size(), errors)); + } else { + this.notify.forEach(s -> Message.IMPORT_PROGRESS.send(s, percent, processedCount, this.commands.size(), errors)); + } + } + + private static class ImportCommand extends DummySender { + private static final Splitter ARGUMENT_SPLITTER = Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings(); + private static final Splitter SPACE_SPLITTER = Splitter.on(" "); + + private final CommandManager commandManager; + private final int id; + private final String command; + + private final String target; + + private boolean completed = false; + + private final List output = new ArrayList<>(); + + private CommandResult result = CommandResult.FAILURE; + + ImportCommand(CommandManager commandManager, int id, String command) { + super(commandManager.getPlugin()); + this.commandManager = commandManager; + this.id = id; + this.command = command; + this.target = determineTarget(command); + } + + @Override + protected void consumeMessage(String s) { + this.output.add(s); + } + + public void process() { + if (isCompleted()) { + return; + } + + try { + List args = CommandManager.stripQuotes(ARGUMENT_SPLITTER.splitToList(getCommand())); + CommandResult result = this.commandManager.onCommand(this, "lp", args, Runnable::run).get(); + setResult(result); + } catch (Exception e) { + setResult(CommandResult.FAILURE); + e.printStackTrace(); + } + + setCompleted(true); + } + + private static String determineTarget(String command) { + if (command.startsWith("user ") && command.length() > "user ".length()) { + String subCmd = command.substring("user ".length()); + if (!subCmd.contains(" ")) { + return null; + } + + String targetUser = SPACE_SPLITTER.split(subCmd).iterator().next(); + return "u:" + targetUser; + } + + if (command.startsWith("group ") && command.length() > "group ".length()) { + String subCmd = command.substring("group ".length()); + if (!subCmd.contains(" ")) { + return null; + } + + String targetGroup = SPACE_SPLITTER.split(subCmd).iterator().next(); + return "g:" + targetGroup; + } + + if (command.startsWith("track ") && command.length() > "track ".length()) { + String subCmd = command.substring("track ".length()); + if (!subCmd.contains(" ")) { + return null; + } + + String targetTrack = SPACE_SPLITTER.split(subCmd).iterator().next(); + return "t:" + targetTrack; + } + + if (command.startsWith("creategroup ") && command.length() > "creategroup ".length()) { + String targetGroup = command.substring("creategroup ".length()); + return "g:" + targetGroup; + } + + if (command.startsWith("createtrack ") && command.length() > "createtrack ".length()) { + String targetTrack = command.substring("createtrack ".length()); + return "t:" + targetTrack; + } + + return null; + } + + public int getId() { + return this.id; + } + + public String getCommand() { + return this.command; + } + + public String getTarget() { + return this.target; + } + + public boolean isCompleted() { + return this.completed; + } + + public List getOutput() { + return this.output; + } + + public CommandResult getResult() { + return this.result; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + public void setResult(CommandResult result) { + this.result = result; + } + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java b/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java index f0385648e..be0f552de 100644 --- a/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java @@ -61,11 +61,11 @@ import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.query.QueryOptions; import java.util.ArrayList; @@ -276,16 +276,9 @@ public class CommandManager { .forEach(c -> { String permission = c.getPermission().map(CommandPermission::getPermission).orElse("None"); - TextComponent component = TextUtils.fromLegacy("&3> &a" + String.format(c.getUsage(), label), AMPERSAND_CHAR) + TextComponent component = LegacyComponentSerializer.INSTANCE.deserialize("&3> &a" + String.format(c.getUsage(), label), AMPERSAND_CHAR) .toBuilder().applyDeep(comp -> { - comp.hoverEvent(HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "&bCommand: &2" + c.getName(), - "&bDescription: &2" + c.getDescription(), - "&bUsage: &2" + String.format(c.getUsage(), label), - "&bPermission: &2" + permission, - " ", - "&7Click to auto-complete." - ), AMPERSAND_CHAR))); + comp.hoverEvent(HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "&bCommand: &2" + c.getName(), "&bDescription: &2" + c.getDescription(), "&bUsage: &2" + String.format(c.getUsage(), label), "&bPermission: &2" + permission, " ", "&7Click to auto-complete."), AMPERSAND_CHAR))); comp.clickEvent(ClickEvent.suggestCommand(String.format(c.getUsage(), label))); }).build(); sender.sendMessage(component); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddChatMeta.java index a004b73b2..938af2418 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddChatMeta.java @@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataMutateResult; import net.luckperms.api.model.DataType; @@ -90,10 +90,7 @@ public class MetaAddChatMeta extends SharedSubCommand { DataMutateResult result = holder.setNode(DataType.NORMAL, ((this.type == ChatMetaType.PREFIX ? Prefix.builder(priority, meta) : Suffix.builder(priority, meta))).withContext(context).build(), true); if (result.wasSuccessful()) { TextComponent.Builder builder = Message.ADD_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddTempChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddTempChatMeta.java index 8a9a6c901..99cb257b7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddTempChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaAddTempChatMeta.java @@ -47,10 +47,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataType; import net.luckperms.api.model.TemporaryDataMutateResult; @@ -99,10 +99,7 @@ public class MetaAddTempChatMeta extends SharedSubCommand { duration = ret.getMergedNode().getExpiry().getEpochSecond(); TextComponent.Builder builder = Message.ADD_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaInfo.java index 83c313ab8..d016028ca 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaInfo.java @@ -43,12 +43,12 @@ import me.lucko.luckperms.common.node.factory.NodeCommandFactory; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Node; import net.luckperms.api.node.NodeType; import net.luckperms.api.node.metadata.types.InheritanceOriginMetadata; @@ -171,11 +171,7 @@ public class MetaInfo extends SharedSubCommand { } } - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "¥3> ¥a" + node.getPriority() + " ¥7- ¥r" + node.getMetaValue(), - " ", - "¥7Click to remove this " + node.getMetaType().name().toLowerCase() + " from " + holder.getFormattedDisplayName() - ), '¥')); + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3> ¥a" + node.getPriority() + " ¥7- ¥r" + node.getMetaValue(), " ", "¥7Click to remove this " + node.getMetaType().name().toLowerCase() + " from " + holder.getFormattedDisplayName()), '¥')); String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(); boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); @@ -198,11 +194,7 @@ public class MetaInfo extends SharedSubCommand { } } - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "¥3> ¥r" + node.getMetaKey() + " ¥7- ¥r" + node.getMetaValue(), - " ", - "¥7Click to remove this meta pair from " + holder.getFormattedDisplayName() - ), '¥')); + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3> ¥r" + node.getMetaKey() + " ¥7- ¥r" + node.getMetaValue(), " ", "¥7Click to remove this meta pair from " + holder.getFormattedDisplayName()), '¥')); String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(); boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveChatMeta.java index 51341b928..a33016592 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveChatMeta.java @@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.ImmutableContextSet; import net.luckperms.api.model.DataMutateResult; import net.luckperms.api.model.DataType; @@ -107,10 +107,7 @@ public class MetaRemoveChatMeta extends SharedSubCommand { if (result.wasSuccessful()) { TextComponent.Builder builder = Message.REMOVE_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveTempChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveTempChatMeta.java index 592bc2c66..51555c8c6 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveTempChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaRemoveTempChatMeta.java @@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.ImmutableContextSet; import net.luckperms.api.model.DataMutateResult; import net.luckperms.api.model.DataType; @@ -107,10 +107,7 @@ public class MetaRemoveTempChatMeta extends SharedSubCommand { if (result.wasSuccessful()) { TextComponent.Builder builder = Message.REMOVE_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSet.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSet.java index 663006e21..655d1dcb7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSet.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSet.java @@ -44,10 +44,10 @@ import me.lucko.luckperms.common.node.types.Meta; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataType; import net.luckperms.api.node.Node; @@ -90,10 +90,7 @@ public class MetaSet extends SharedSubCommand { holder.setNode(DataType.NORMAL, node, true); TextComponent.Builder builder = Message.SET_META_SUCCESS.asComponent(plugin.getLocaleManager(), key, value, holder.getFormattedDisplayName(), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetChatMeta.java index 8aaac2781..06d7d629d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetChatMeta.java @@ -47,10 +47,10 @@ import me.lucko.luckperms.common.node.types.Suffix; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataMutateResult; import net.luckperms.api.model.DataType; @@ -126,10 +126,7 @@ public class MetaSetChatMeta extends SharedSubCommand { DataMutateResult result = holder.setNode(DataType.NORMAL, ((this.type == ChatMetaType.PREFIX ? Prefix.builder(priority, meta) : Suffix.builder(priority, meta))).withContext(context).build(), true); if (result.wasSuccessful()) { TextComponent.Builder builder = Message.ADD_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTemp.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTemp.java index 720e3f238..6a4cf2a0b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTemp.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTemp.java @@ -46,10 +46,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataType; import net.luckperms.api.model.TemporaryMergeBehaviour; @@ -95,10 +95,7 @@ public class MetaSetTemp extends SharedSubCommand { duration = holder.setNode(DataType.NORMAL, node, modifier).getMergedNode().getExpiry().getEpochSecond(); TextComponent.Builder builder = Message.SET_META_TEMP_SUCCESS.asComponent(plugin.getLocaleManager(), key, value, holder.getFormattedDisplayName(), DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTempChatMeta.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTempChatMeta.java index e6ff0d15f..35ee77a5d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTempChatMeta.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/meta/MetaSetTempChatMeta.java @@ -49,10 +49,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.DataType; import net.luckperms.api.model.TemporaryDataMutateResult; @@ -139,10 +139,7 @@ public class MetaSetTempChatMeta extends SharedSubCommand { duration = ret.getMergedNode().getExpiry().getEpochSecond(); TextComponent.Builder builder = Message.ADD_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder(); - HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy( - "¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, - '¥' - )); + HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥')); builder.applyDeep(c -> c.hoverEvent(event)); sender.sendMessage(builder.build()); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java index d1f6965eb..7bf4d8add 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java @@ -46,12 +46,12 @@ import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.types.InheritanceNode; import net.luckperms.api.query.QueryOptions; @@ -119,7 +119,7 @@ public class ParentInfo extends SharedSubCommand { s += "\n&2 expires in " + DurationFormatter.LONG.formatDateDiff(node.getExpiry().getEpochSecond()); } - TextComponent message = TextUtils.fromLegacy(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build(); + TextComponent message = LegacyComponentSerializer.INSTANCE.deserialize(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build(); sender.sendMessage(message); } @@ -137,11 +137,7 @@ public class ParentInfo extends SharedSubCommand { }; private static Consumer> makeFancy(PermissionHolder holder, String label, InheritanceNode node) { - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "&3> &f" + node.getGroupName(), - " ", - "&7Click to remove this parent from " + holder.getFormattedDisplayName() - ), CommandManager.AMPERSAND_CHAR)); + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "&3> &f" + node.getGroupName(), " ", "&7Click to remove this parent from " + holder.getFormattedDisplayName()), CommandManager.AMPERSAND_CHAR)); String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(); boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java index 54cdd9dc6..98d46ccc4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java @@ -46,12 +46,12 @@ import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Node; import net.luckperms.api.node.NodeType; @@ -119,7 +119,7 @@ public class PermissionInfo extends SharedSubCommand { s += "\n&2- expires in " + DurationFormatter.LONG.formatDateDiff(node.getExpiry().getEpochSecond()); } - TextComponent message = TextUtils.fromLegacy(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build(); + TextComponent message = LegacyComponentSerializer.INSTANCE.deserialize(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build(); sender.sendMessage(message); } @@ -137,11 +137,8 @@ public class PermissionInfo extends SharedSubCommand { }; private static Consumer> makeFancy(PermissionHolder holder, String label, Node node) { - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "¥3> " + (node.getValue() ? "¥a" : "¥c") + node.getKey(), - " ", - "¥7Click to remove this node from " + holder.getFormattedDisplayName() - ), '¥')); + String[] strings = new String[]{"¥3> " + (node.getValue() ? "¥a" : "¥c") + node.getKey(), " ", "¥7Click to remove this node from " + holder.getFormattedDisplayName()}; + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", strings), '¥')); String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(); boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java index f6bc259d0..b28319ad8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java @@ -43,7 +43,7 @@ import me.lucko.luckperms.common.locale.command.CommandSpec; import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.HolderType; -import me.lucko.luckperms.common.node.comparator.HeldPermissionComparator; +import me.lucko.luckperms.common.node.comparator.HeldNodeComparator; import me.lucko.luckperms.common.node.factory.NodeCommandFactory; import me.lucko.luckperms.common.node.types.Inheritance; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; @@ -51,12 +51,12 @@ import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import net.luckperms.api.node.types.InheritanceNode; @@ -127,7 +127,7 @@ public class GroupListMembers extends SubCommand { private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page) { results = new ArrayList<>(results); - results.sort(HeldPermissionComparator.normal()); + results.sort(HeldNodeComparator.normal()); int pageIndex = page - 1; List>> pages = Iterators.divideIterable(results, 15); @@ -148,7 +148,7 @@ public class GroupListMembers extends SubCommand { for (Map.Entry> ent : mappedContent) { String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().getNode()) + MessageUtils.getAppendableNodeContextString(sender.getPlugin().getLocaleManager(), ent.getValue().getNode()); - TextComponent message = TextUtils.fromLegacy(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue(), sender.getPlugin())).build(); + TextComponent message = LegacyComponentSerializer.INSTANCE.deserialize(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue(), sender.getPlugin())).build(); sender.sendMessage(message); } } @@ -162,11 +162,7 @@ public class GroupListMembers extends SubCommand { } private static Consumer> makeFancy(String holderName, HolderType holderType, String label, HeldNode perm, LuckPermsPlugin plugin) { - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "&3> &b" + ((InheritanceNode) perm.getNode()).getGroupName(), - " ", - "&7Click to remove this parent from " + holderName - ), CommandManager.AMPERSAND_CHAR)); + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "&3> &b" + ((InheritanceNode) perm.getNode()).getGroupName(), " ", "&7Click to remove this parent from " + holderName), CommandManager.AMPERSAND_CHAR)); boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ApplyEditsCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ApplyEditsCommand.java index 97e5fb126..34c1579d1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ApplyEditsCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ApplyEditsCommand.java @@ -44,6 +44,7 @@ import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.manager.group.GroupManager; +import me.lucko.luckperms.common.node.utils.NodeJsonSerializer; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; @@ -162,7 +163,7 @@ public class ApplyEditsCommand extends SingleCommand { } Set before = new HashSet<>(holder.normalData().immutable().values()); - Set after = new HashSet<>(WebEditor.deserializePermissions(data.getAsJsonArray("nodes"))); + Set after = new HashSet<>(NodeJsonSerializer.deserializeNodes(data.getAsJsonArray("nodes"))); Map.Entry, Set> diff = diff(before, after); Set diffAdded = diff.getKey(); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java index 875894307..03a041025 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java @@ -57,9 +57,9 @@ public class ExportCommand extends SingleCommand { } Path dataDirectory = plugin.getBootstrap().getDataDirectory(); - Path path = dataDirectory.resolve(args.get(0)); + Path path = dataDirectory.resolve(args.get(0) + ".json.gz"); - if (!path.getParent().equals(dataDirectory) || path.getFileName().toString().equals("config.yml")) { + if (!path.getParent().equals(dataDirectory)) { Message.FILE_NOT_WITHIN_DIRECTORY.send(sender, path.toString()); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java index 598848b9e..3fa5d00c3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java @@ -25,7 +25,10 @@ package me.lucko.luckperms.common.commands.misc; +import com.google.gson.JsonObject; + import me.lucko.luckperms.common.backup.Importer; +import me.lucko.luckperms.common.backup.LegacyImporter; import me.lucko.luckperms.common.command.CommandResult; import me.lucko.luckperms.common.command.abstraction.SingleCommand; import me.lucko.luckperms.common.command.access.CommandPermission; @@ -35,13 +38,17 @@ import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.Predicates; +import me.lucko.luckperms.common.util.gson.GsonProvider; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.GZIPInputStream; public class ImportCommand extends SingleCommand { private final AtomicBoolean running = new AtomicBoolean(false); @@ -57,8 +64,13 @@ public class ImportCommand extends SingleCommand { return CommandResult.STATE_ERROR; } + String fileName = args.get(0); + if (!fileName.contains(".")) { + fileName += ".json.gz"; + } + Path dataDirectory = plugin.getBootstrap().getDataDirectory(); - Path path = dataDirectory.resolve(args.get(0)); + Path path = dataDirectory.resolve(fileName); if (!path.getParent().equals(dataDirectory) || path.getFileName().toString().equals("config.yml")) { Message.FILE_NOT_WITHIN_DIRECTORY.send(sender, path.toString()); @@ -66,40 +78,68 @@ public class ImportCommand extends SingleCommand { } if (!Files.exists(path)) { - Message.IMPORT_LOG_DOESNT_EXIST.send(sender, path.toString()); + Message.IMPORT_FILE_DOESNT_EXIST.send(sender, path.toString()); return CommandResult.INVALID_ARGS; } if (!Files.isReadable(path)) { - Message.IMPORT_LOG_NOT_READABLE.send(sender, path.toString()); + Message.IMPORT_FILE_NOT_READABLE.send(sender, path.toString()); return CommandResult.FAILURE; } - List commands; - - try { - commands = Files.readAllLines(path, StandardCharsets.UTF_8); - } catch (IOException e) { - e.printStackTrace(); - Message.IMPORT_LOG_FAILURE.send(sender); - return CommandResult.FAILURE; - } - - if (!this.running.compareAndSet(false, true)) { - Message.IMPORT_ALREADY_RUNNING.send(sender); - return CommandResult.STATE_ERROR; - } - - Importer importer = new Importer(plugin.getCommandManager(), sender, commands); - - // Run the importer in its own thread. - plugin.getBootstrap().getScheduler().executeAsync(() -> { + if (!fileName.endsWith(".json.gz")) { + // legacy + List commands; try { - importer.run(); - } finally { - this.running.set(false); + commands = Files.readAllLines(path, StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + Message.IMPORT_FILE_READ_FAILURE.send(sender); + return CommandResult.FAILURE; } - }); + + if (!this.running.compareAndSet(false, true)) { + Message.IMPORT_ALREADY_RUNNING.send(sender); + return CommandResult.STATE_ERROR; + } + + LegacyImporter importer = new LegacyImporter(plugin.getCommandManager(), sender, commands); + + // Run the importer in its own thread. + plugin.getBootstrap().getScheduler().executeAsync(() -> { + try { + importer.run(); + } finally { + this.running.set(false); + } + }); + } else { + // modern + JsonObject data; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(Files.newInputStream(path)), StandardCharsets.UTF_8))) { + data = GsonProvider.normal().fromJson(reader, JsonObject.class);; + } catch (IOException e) { + e.printStackTrace(); + Message.IMPORT_FILE_READ_FAILURE.send(sender); + return CommandResult.FAILURE; + } + + if (!this.running.compareAndSet(false, true)) { + Message.IMPORT_ALREADY_RUNNING.send(sender); + return CommandResult.STATE_ERROR; + } + + Importer importer = new Importer(plugin, sender, data); + + // Run the importer in its own thread. + plugin.getBootstrap().getScheduler().executeAsync(() -> { + try { + importer.run(); + } finally { + this.running.set(false); + } + }); + } return CommandResult.SUCCESS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java index 93ec1396d..7450093d5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java @@ -44,19 +44,19 @@ import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.command.CommandSpec; import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.HolderType; -import me.lucko.luckperms.common.node.comparator.HeldPermissionComparator; +import me.lucko.luckperms.common.node.comparator.HeldNodeComparator; import me.lucko.luckperms.common.node.factory.NodeCommandFactory; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; @@ -129,7 +129,7 @@ public class SearchCommand extends SingleCommand { private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page, Comparison comparison) { results = new ArrayList<>(results); - results.sort(HeldPermissionComparator.normal()); + results.sort(HeldNodeComparator.normal()); int pageIndex = page - 1; List>> pages = Iterators.divideIterable(results, 15); @@ -156,7 +156,7 @@ public class SearchCommand extends SingleCommand { } String s = "&3> &b" + ent.getKey() + permission + "&7 - " + (ent.getValue().getNode().getValue() ? "&a" : "&c") + ent.getValue().getNode().getValue() + getNodeExpiryString(ent.getValue().getNode()) + MessageUtils.getAppendableNodeContextString(sender.getPlugin().getLocaleManager(), ent.getValue().getNode()); - TextComponent message = TextUtils.fromLegacy(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue(), sender.getPlugin())).build(); + TextComponent message = LegacyComponentSerializer.INSTANCE.deserialize(s, CommandManager.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue(), sender.getPlugin())).build(); sender.sendMessage(message); } } @@ -170,11 +170,8 @@ public class SearchCommand extends SingleCommand { } private static Consumer> makeFancy(String holderName, HolderType holderType, String label, HeldNode perm, LuckPermsPlugin plugin) { - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( - "&3> " + (perm.getNode().getValue() ? "&a" : "&c") + perm.getNode().getKey(), - " ", - "&7Click to remove this node from " + holderName - ), CommandManager.AMPERSAND_CHAR)); + String[] strings = new String[]{"&3> " + (perm.getNode().getValue() ? "&a" : "&c") + perm.getNode().getKey(), " ", "&7Click to remove this node from " + holderName}; + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", strings), CommandManager.AMPERSAND_CHAR)); boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty(); String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext); diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java b/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java index 6503709c8..62fbd7449 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java @@ -28,9 +28,9 @@ package me.lucko.luckperms.common.locale.message; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.sender.Sender; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.TextComponent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.Nullable; @@ -453,9 +453,9 @@ public enum Message { IMPORT_ALREADY_RUNNING("&cAnother import process is already running. Please wait for it to finish and try again.", true), EXPORT_ALREADY_RUNNING("&cAnother export process is already running. Please wait for it to finish and try again.", true), FILE_NOT_WITHIN_DIRECTORY("&cError: File &4{}&c must be a direct child of the data directory.", true), - IMPORT_LOG_DOESNT_EXIST("&cError: File &4{}&c does not exist.", true), - IMPORT_LOG_NOT_READABLE("&cError: File &4{}&c is not readable.", true), - IMPORT_LOG_FAILURE("&cAn unexpected error occured whilst reading from the log file.", true), + IMPORT_FILE_DOESNT_EXIST("&cError: File &4{}&c does not exist.", true), + IMPORT_FILE_NOT_READABLE("&cError: File &4{}&c is not readable.", true), + IMPORT_FILE_READ_FAILURE("&cAn unexpected error occured whilst reading from the import file.", true), IMPORT_PROGRESS("&b(Import) &b-> &f{}&f% complete &7- &b{}&f/&b{} &foperations complete with &c{} &ferrors.", true), IMPORT_PROGRESS_SIN("&b(Import) &b-> &f{}&f% complete &7- &b{}&f/&b{} &foperations complete with &c{} &ferror.", true), @@ -482,10 +482,18 @@ public enum Message { Message(String message, boolean showPrefix) { // rewrite hardcoded placeholders according to their position - this.message = TextUtils.rewritePlaceholders(message); + this.message = rewritePlaceholders(message); this.showPrefix = showPrefix; } + private static String rewritePlaceholders(String input) { + int i = 0; + while (input.contains("{}")) { + input = input.replaceFirst("\\{\\}", "{" + i++ + "}"); + } + return input; + } + public String getMessage() { return this.message; } @@ -517,7 +525,7 @@ public enum Message { } public TextComponent asComponent(@Nullable LocaleManager localeManager, Object... objects) { - return TextUtils.fromLegacy(format(localeManager, objects), CommandManager.AMPERSAND_CHAR); + return LegacyComponentSerializer.INSTANCE.deserialize(format(localeManager, objects), CommandManager.AMPERSAND_CHAR); } public void send(Sender sender, Object... objects) { diff --git a/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldPermissionComparator.java b/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java similarity index 89% rename from common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldPermissionComparator.java rename to common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java index 2df46f9b3..ea350a884 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldPermissionComparator.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java @@ -29,14 +29,14 @@ import net.luckperms.api.node.HeldNode; import java.util.Comparator; -public class HeldPermissionComparator> implements Comparator> { +public class HeldNodeComparator> implements Comparator> { public static > Comparator> normal() { - return new HeldPermissionComparator<>(); + return new HeldNodeComparator<>(); } public static > Comparator> reverse() { - return HeldPermissionComparator.normal().reversed(); + return HeldNodeComparator.normal().reversed(); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeJsonSerializer.java b/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeJsonSerializer.java new file mode 100644 index 000000000..96e08618b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeJsonSerializer.java @@ -0,0 +1,69 @@ +package me.lucko.luckperms.common.node.utils; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import me.lucko.luckperms.common.context.ContextSetJsonSerializer; +import me.lucko.luckperms.common.node.factory.NodeBuilders; + +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeBuilder; + +import java.time.Instant; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class NodeJsonSerializer { + + private NodeJsonSerializer() { + + } + + public static JsonArray serializeNodes(Collection nodes) { + JsonArray arr = new JsonArray(); + for (Node node : nodes) { + JsonObject attributes = new JsonObject(); + + attributes.addProperty("type", node.getType().name().toLowerCase()); + attributes.addProperty("key", node.getKey()); + attributes.addProperty("value", node.getValue()); + + Instant expiry = node.getExpiry(); + if (expiry != null) { + attributes.addProperty("expiry", expiry.getEpochSecond()); + } + + if (!node.getContexts().isEmpty()) { + attributes.add("context", ContextSetJsonSerializer.serializeContextSet(node.getContexts())); + } + + arr.add(attributes); + } + return arr; + } + + public static Set deserializeNodes(JsonArray arr) { + Set nodes = new HashSet<>(); + for (JsonElement ent : arr) { + JsonObject attributes = ent.getAsJsonObject(); + + String key = attributes.get("key").getAsString(); + boolean value = attributes.get("value").getAsBoolean(); + + NodeBuilder builder = NodeBuilders.determineMostApplicable(key).value(value); + + if (attributes.has("expiry")) { + builder.expiry(attributes.get("expiry").getAsLong()); + } + + if (attributes.has("context")) { + builder.context(ContextSetJsonSerializer.deserializeContextSet(attributes.get("context"))); + } + + nodes.add(builder.build()); + } + return nodes; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java index c2e6bd3b7..7bc0d5e41 100644 --- a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java +++ b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java @@ -28,9 +28,9 @@ package me.lucko.luckperms.common.sender; import com.google.common.base.Splitter; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.Component; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import java.lang.ref.WeakReference; @@ -93,7 +93,7 @@ public final class AbstractSender implements Sender { @Override public void sendMessage(Component message) { if (isConsole()) { - sendMessage(TextUtils.toLegacy(message)); + sendMessage(LegacyComponentSerializer.INSTANCE.serialize(message)); return; } diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/DummySender.java b/common/src/main/java/me/lucko/luckperms/common/sender/DummySender.java index 6842c3199..3339718f7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/sender/DummySender.java +++ b/common/src/main/java/me/lucko/luckperms/common/sender/DummySender.java @@ -26,9 +26,9 @@ package me.lucko.luckperms.common.sender; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.Component; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import java.util.UUID; @@ -58,7 +58,7 @@ public abstract class DummySender implements Sender { @Override public void sendMessage(Component message) { - consumeMessage(TextUtils.toLegacy(message)); + consumeMessage(LegacyComponentSerializer.INSTANCE.serialize(message)); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/util/TextUtils.java b/common/src/main/java/me/lucko/luckperms/common/util/TextUtils.java deleted file mode 100644 index 34e3a0e33..000000000 --- a/common/src/main/java/me/lucko/luckperms/common/util/TextUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.util; - -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.serializer.legacy.LegacyComponentSerializer; - -import java.util.Arrays; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class TextUtils { - private TextUtils() {} - - public static String joinNewline(String... strings) { - return joinNewline(Arrays.stream(strings)); - } - - public static String joinNewline(Stream strings) { - return strings.collect(Collectors.joining("\n")); - } - - public static TextComponent fromLegacy(String input, char character) { - return LegacyComponentSerializer.INSTANCE.deserialize(input, character); - } - - public static TextComponent fromLegacy(String input) { - return LegacyComponentSerializer.INSTANCE.deserialize(input); - } - - public static String toLegacy(Component component, char character) { - return LegacyComponentSerializer.INSTANCE.serialize(component, character); - } - - public static String toLegacy(Component component) { - return LegacyComponentSerializer.INSTANCE.serialize(component); - } - - public static String rewritePlaceholders(String input) { - int i = 0; - while (input.contains("{}")) { - input = input.replaceFirst("\\{\\}", "{" + i++ + "}"); - } - return input; - } - -} diff --git a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java index 9eb4b3a29..1fd02432d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java +++ b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java @@ -34,7 +34,6 @@ import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.StackTracePrinter; -import me.lucko.luckperms.common.util.TextUtils; import me.lucko.luckperms.common.util.gson.GsonProvider; import me.lucko.luckperms.common.util.gson.JArray; import me.lucko.luckperms.common.util.gson.JObject; @@ -46,6 +45,7 @@ import me.lucko.luckperms.common.web.BytebinClient; import net.kyori.text.TextComponent; import net.kyori.text.event.HoverEvent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import net.luckperms.api.query.QueryMode; @@ -60,6 +60,7 @@ import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.zip.GZIPOutputStream; /** @@ -232,7 +233,7 @@ public class VerboseListener { } // send the message - HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(hover.stream()), CommandManager.AMPERSAND_CHAR)); + HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(hover.stream().collect(Collectors.joining("\n")), CommandManager.AMPERSAND_CHAR)); TextComponent text = textComponent.toBuilder().applyDeep(comp -> comp.hoverEvent(hoverEvent)).build(); this.notifiedSender.sendMessage(text); } diff --git a/common/src/main/java/me/lucko/luckperms/common/web/WebEditor.java b/common/src/main/java/me/lucko/luckperms/common/web/WebEditor.java index b74736498..3f454d08e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/web/WebEditor.java +++ b/common/src/main/java/me/lucko/luckperms/common/web/WebEditor.java @@ -26,23 +26,18 @@ package me.lucko.luckperms.common.web; import com.google.common.base.Preconditions; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import me.lucko.luckperms.common.context.ContextSetJsonSerializer; import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.Track; -import me.lucko.luckperms.common.node.factory.NodeBuilders; +import me.lucko.luckperms.common.node.utils.NodeJsonSerializer; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.util.gson.GsonProvider; import me.lucko.luckperms.common.util.gson.JArray; import me.lucko.luckperms.common.util.gson.JObject; -import net.luckperms.api.node.Node; -import net.luckperms.api.node.NodeBuilder; - import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; @@ -52,11 +47,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Collection; -import java.util.HashSet; import java.util.List; -import java.util.Set; /** * Utility methods for interacting with the LuckPerms web permission editor. @@ -69,7 +60,7 @@ public final class WebEditor { .add("type", holder.getType().toString()) .add("id", holder.getObjectName()) .add("displayName", holder.getPlainDisplayName()) - .add("nodes", serializePermissions(holder.normalData().immutable().values())); + .add("nodes", NodeJsonSerializer.serializeNodes(holder.normalData().immutable().values())); } private static JObject writeData(Track track) { @@ -143,50 +134,4 @@ public final class WebEditor { } } - private static JsonArray serializePermissions(Collection nodes) { - JsonArray arr = new JsonArray(); - for (Node node : nodes) { - JsonObject attributes = new JsonObject(); - - attributes.addProperty("type", node.getType().name().toLowerCase()); - attributes.addProperty("key", node.getKey()); - attributes.addProperty("value", node.getValue()); - - Instant expiry = node.getExpiry(); - if (expiry != null) { - attributes.addProperty("expiry", expiry.getEpochSecond()); - } - - if (!node.getContexts().isEmpty()) { - attributes.add("context", ContextSetJsonSerializer.serializeContextSet(node.getContexts())); - } - - arr.add(attributes); - } - return arr; - } - - public static Set deserializePermissions(JsonArray arr) { - Set nodes = new HashSet<>(); - for (JsonElement ent : arr) { - JsonObject attributes = ent.getAsJsonObject(); - - String key = attributes.get("key").getAsString(); - boolean value = attributes.get("value").getAsBoolean(); - - NodeBuilder builder = NodeBuilders.determineMostApplicable(key).value(value); - - if (attributes.has("expiry")) { - builder.expiry(attributes.get("expiry").getAsLong()); - } - - if (attributes.has("context")) { - builder.context(ContextSetJsonSerializer.deserializeContextSet(attributes.get("context"))); - } - - nodes.add(builder.build()); - } - return nodes; - } - } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java index d555af16d..71775096b 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java @@ -28,9 +28,9 @@ package me.lucko.luckperms.nukkit; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.sender.SenderFactory; -import me.lucko.luckperms.common.util.TextUtils; import net.kyori.text.Component; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import cn.nukkit.Player; @@ -75,7 +75,7 @@ public class NukkitSenderFactory extends SenderFactory { @Override protected void sendMessage(CommandSender sender, Component message) { // Fallback to legacy format - sendMessage(sender, TextUtils.toLegacy(message)); + sendMessage(sender, LegacyComponentSerializer.INSTANCE.serialize(message)); } @Override diff --git a/velocity/src/main/java/me/lucko/luckperms/velocity/VelocitySenderFactory.java b/velocity/src/main/java/me/lucko/luckperms/velocity/VelocitySenderFactory.java index f303f2bf6..88668783d 100644 --- a/velocity/src/main/java/me/lucko/luckperms/velocity/VelocitySenderFactory.java +++ b/velocity/src/main/java/me/lucko/luckperms/velocity/VelocitySenderFactory.java @@ -31,10 +31,10 @@ import com.velocitypowered.api.proxy.Player; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.sender.SenderFactory; -import me.lucko.luckperms.common.util.TextUtils; import me.lucko.luckperms.velocity.service.CompatibilityUtil; import net.kyori.text.Component; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.node.Tristate; import java.util.UUID; @@ -62,7 +62,7 @@ public class VelocitySenderFactory extends SenderFactory { @Override protected void sendMessage(CommandSource source, String s) { - sendMessage(source, TextUtils.fromLegacy(s)); + sendMessage(source, LegacyComponentSerializer.INSTANCE.deserialize(s)); } @Override