mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-24 03:25:19 +01:00
Implement new compressed json import/export format
The old "command list" style is now only supported for import.
This commit is contained in:
parent
7764a04d46
commit
4b0574710e
@ -29,10 +29,10 @@ import me.lucko.luckperms.bukkit.compat.CraftBukkitUtil;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
import net.kyori.text.adapter.bukkit.TextAdapter;
|
import net.kyori.text.adapter.bukkit.TextAdapter;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -82,7 +82,7 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
|||||||
TextAdapter.sendComponent(sender, message);
|
TextAdapter.sendComponent(sender, message);
|
||||||
} else {
|
} else {
|
||||||
// Fallback to legacy format
|
// Fallback to legacy format
|
||||||
sendMessage(sender, TextUtils.toLegacy(message));
|
sendMessage(sender, LegacyComponentSerializer.INSTANCE.serialize(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@ import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
import net.kyori.text.adapter.bungeecord.TextAdapter;
|
import net.kyori.text.adapter.bungeecord.TextAdapter;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
@ -62,7 +62,7 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void sendMessage(CommandSender sender, String s) {
|
protected void sendMessage(CommandSender sender, String s) {
|
||||||
sendMessage(sender, TextUtils.fromLegacy(s));
|
sendMessage(sender, LegacyComponentSerializer.INSTANCE.deserialize(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,32 +25,36 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.backup;
|
package me.lucko.luckperms.common.backup;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.locale.message.Message;
|
import me.lucko.luckperms.common.locale.message.Message;
|
||||||
import me.lucko.luckperms.common.model.Group;
|
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.Track;
|
||||||
import me.lucko.luckperms.common.model.User;
|
import me.lucko.luckperms.common.model.User;
|
||||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
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.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.storage.Storage;
|
import me.lucko.luckperms.common.storage.Storage;
|
||||||
import me.lucko.luckperms.common.util.ProgressLogger;
|
import me.lucko.luckperms.common.util.ProgressLogger;
|
||||||
|
import me.lucko.luckperms.common.util.gson.GsonProvider;
|
||||||
import net.luckperms.api.node.Node;
|
import me.lucko.luckperms.common.util.gson.JArray;
|
||||||
import net.luckperms.api.node.NodeType;
|
import me.lucko.luckperms.common.util.gson.JObject;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@ -60,9 +64,8 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
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.stream.Collectors;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles export operations
|
* Handles export operations
|
||||||
@ -70,15 +73,6 @@ import java.util.stream.Collectors;
|
|||||||
public class Exporter implements Runnable {
|
public class Exporter implements Runnable {
|
||||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
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 LuckPermsPlugin plugin;
|
||||||
private final Sender executor;
|
private final Sender executor;
|
||||||
private final Path filePath;
|
private final Path filePath;
|
||||||
@ -98,184 +92,128 @@ public class Exporter implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try (BufferedWriter writer = Files.newBufferedWriter(this.filePath, StandardCharsets.UTF_8)) {
|
JsonObject file = new JsonObject();
|
||||||
this.log.log("Starting.");
|
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");
|
this.log.log("Gathering group data...");
|
||||||
write(writer, "# Generated by " + this.executor.getNameWithLocation() + " at " + DATE_FORMAT.format(new Date(System.currentTimeMillis())));
|
file.add("groups", exportGroups());
|
||||||
write(writer, "");
|
|
||||||
|
|
||||||
// Export Groups
|
this.log.log("Gathering track data...");
|
||||||
this.log.log("Starting group export.");
|
file.add("tracks", exportTracks());
|
||||||
|
|
||||||
// Create the actual groups first
|
if (this.includeUsers) {
|
||||||
write(writer, "# Create groups");
|
this.log.log("Gathering user data...");
|
||||||
|
file.add("users", exportUsers());
|
||||||
|
}
|
||||||
|
|
||||||
AtomicInteger groupCount = new AtomicInteger(0);
|
this.log.log("Finished gathering data, writing file...");
|
||||||
|
|
||||||
List<? extends Group> groups = this.plugin.getGroupManager().getAll().values().stream()
|
try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(this.filePath)), StandardCharsets.UTF_8))) {
|
||||||
// export groups in order of weight
|
GsonProvider.prettyPrinting().toJson(file, out);
|
||||||
.sorted((o1, o2) -> {
|
} catch (IOException e) {
|
||||||
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<? extends Track> 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<UUID> 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<List<String>> 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<CompletableFuture<Void>> 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<String> 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<Void> 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) {
|
|
||||||
e.printStackTrace();
|
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<Group> 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<? extends Track> 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<UUID> 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<CompletableFuture<Void>> futures = new HashSet<>();
|
||||||
|
|
||||||
|
AtomicInteger userCount = new AtomicInteger(0);
|
||||||
|
Map<UUID, JsonObject> 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<Void> 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<UUID, JsonObject> entry : out.entrySet()) {
|
||||||
|
outJson.add(entry.getKey().toString(), entry.getValue());
|
||||||
|
}
|
||||||
|
return outJson;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,24 +25,31 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.backup;
|
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.ImmutableSet;
|
||||||
import com.google.common.collect.ListMultimap;
|
|
||||||
import com.google.common.collect.MultimapBuilder;
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
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.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 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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -50,35 +57,59 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles import operations
|
* Handles import operations
|
||||||
*/
|
*/
|
||||||
public class Importer implements Runnable {
|
public class Importer implements Runnable {
|
||||||
|
|
||||||
private final CommandManager commandManager;
|
private final LuckPermsPlugin plugin;
|
||||||
private final Set<Sender> notify;
|
private final Set<Sender> notify;
|
||||||
private final List<String> commandList;
|
private final JsonObject data;
|
||||||
private final List<ImportCommand> commands;
|
|
||||||
|
|
||||||
public Importer(CommandManager commandManager, Sender executor, List<String> commands) {
|
public Importer(LuckPermsPlugin plugin, Sender executor, JsonObject data) {
|
||||||
this.commandManager = commandManager;
|
this.plugin = plugin;
|
||||||
|
|
||||||
if (executor.isConsole()) {
|
if (executor.isConsole()) {
|
||||||
this.notify = ImmutableSet.of(executor);
|
this.notify = ImmutableSet.of(executor);
|
||||||
} else {
|
} else {
|
||||||
this.notify = ImmutableSet.of(executor, commandManager.getPlugin().getConsoleSender());
|
this.notify = ImmutableSet.of(executor, plugin.getConsoleSender());
|
||||||
}
|
}
|
||||||
this.commandList = commands.stream()
|
this.data = data;
|
||||||
.map(String::trim)
|
}
|
||||||
.filter(s -> !s.isEmpty())
|
|
||||||
.filter(s -> !s.startsWith("#"))
|
private static final class UserData {
|
||||||
.filter(s -> !s.startsWith("//"))
|
private final String username;
|
||||||
.map(s -> s.startsWith("/luckperms ") ? s.substring("/luckperms ".length()) : s)
|
private final String primaryGroup;
|
||||||
.map(s -> s.startsWith("/lp ") ? s.substring("/lp ".length()) : s)
|
private final Set<Node> nodes;
|
||||||
.collect(Collectors.toList());
|
|
||||||
this.commands = new ArrayList<>();
|
UserData(String username, String primaryGroup, Set<Node> nodes) {
|
||||||
|
this.username = username;
|
||||||
|
this.primaryGroup = primaryGroup;
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processGroup(String groupName, Set<Node> 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<String> 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
|
@Override
|
||||||
@ -87,28 +118,39 @@ public class Importer implements Runnable {
|
|||||||
this.notify.forEach(s -> Message.IMPORT_START.send(s));
|
this.notify.forEach(s -> Message.IMPORT_START.send(s));
|
||||||
|
|
||||||
// start an update task in the background - we'll #join this later
|
// start an update task in the background - we'll #join this later
|
||||||
CompletableFuture<Void> updateTask = CompletableFuture.runAsync(() -> this.commandManager.getPlugin().getSyncTaskBuffer().requestDirectly());
|
CompletableFuture<Void> 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
|
Map<String, Set<Node>> groups = new HashMap<>();
|
||||||
int index = 1;
|
Map<String, List<String>> tracks = new HashMap<>();
|
||||||
for (String command : this.commandList) {
|
Map<UUID, UserData> users = new HashMap<>();
|
||||||
ImportCommand cmd = new ImportCommand(this.commandManager, index, command);
|
|
||||||
this.commands.add(cmd);
|
|
||||||
|
|
||||||
if (cmd.getCommand().startsWith("creategroup ") || cmd.getCommand().startsWith("createtrack ")) {
|
for (Map.Entry<String, JsonElement> group : this.data.get("groups").getAsJsonObject().entrySet()) {
|
||||||
cmd.process(); // process immediately
|
groups.put(group.getKey(), NodeJsonSerializer.deserializeNodes(group.getValue().getAsJsonObject().get("nodes").getAsJsonArray()));
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, JsonElement> track : this.data.get("tracks").getAsJsonObject().entrySet()) {
|
||||||
|
JsonArray trackGroups = track.getValue().getAsJsonObject().get("groups").getAsJsonArray();
|
||||||
|
List<String> trackGroupsList = new ArrayList<>();
|
||||||
|
trackGroups.forEach(g -> trackGroupsList.add(g.getAsString()));
|
||||||
|
tracks.put(track.getKey(), trackGroupsList);
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, JsonElement> 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<Node> 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++;
|
users.put(uuid, new UserData(username, primaryGroup, nodes));
|
||||||
}
|
|
||||||
|
|
||||||
// split data up into sections for each holder
|
|
||||||
// holder id --> commands
|
|
||||||
ListMultimap<String, ImportCommand> 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..."));
|
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
|
// join the update task future before scheduling command executions
|
||||||
updateTask.join();
|
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
|
// 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.
|
// A set of futures, which are really just the processes we need to wait for.
|
||||||
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
AtomicInteger processedCount = new AtomicInteger(0);
|
AtomicInteger processedCount = new AtomicInteger(0);
|
||||||
|
|
||||||
// iterate through each user sublist.
|
for (Map.Entry<String, Set<Node>> group : groups.entrySet()) {
|
||||||
for (Collection<ImportCommand> subList : sections.asMap().values()) {
|
futures.add(CompletableFuture.completedFuture(group).thenAcceptAsync(ent -> {
|
||||||
|
processGroup(ent.getKey(), ent.getValue());
|
||||||
// register and start a new thread to process the sublist
|
processedCount.incrementAndGet();
|
||||||
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));
|
}, executor));
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, List<String>> track : tracks.entrySet()) {
|
||||||
|
futures.add(CompletableFuture.completedFuture(track).thenAcceptAsync(ent -> {
|
||||||
|
processTrack(ent.getKey(), ent.getValue());
|
||||||
|
processedCount.incrementAndGet();
|
||||||
|
}, executor));
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
for (Map.Entry<UUID, UserData> 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
|
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
||||||
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
CompletableFuture<Void> 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) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
@ -154,7 +205,7 @@ public class Importer implements Runnable {
|
|||||||
break;
|
break;
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
// still executing - send a progress report and continue waiting
|
// still executing - send a progress report and continue waiting
|
||||||
sendProgress(processedCount.get());
|
sendProgress(processedCount.get(), total);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,166 +218,12 @@ public class Importer implements Runnable {
|
|||||||
long endTime = System.currentTimeMillis();
|
long endTime = System.currentTimeMillis();
|
||||||
double seconds = (endTime - startTime) / 1000.0;
|
double seconds = (endTime - startTime) / 1000.0;
|
||||||
|
|
||||||
int errors = (int) this.commands.stream().filter(v -> v.getResult().wasFailure()).count();
|
this.notify.forEach(s -> Message.IMPORT_END_COMPLETE.send(s, seconds));
|
||||||
|
|
||||||
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) {
|
private void sendProgress(int processedCount, int total) {
|
||||||
int percent = (processedCount * 100) / this.commandList.size();
|
int percent = (processedCount * 100) / total;
|
||||||
int errors = (int) this.commands.stream().filter(v -> v.isCompleted() && v.getResult().wasFailure()).count();
|
this.notify.forEach(s -> Message.IMPORT_PROGRESS.send(s, percent, processedCount, total, 0));
|
||||||
|
|
||||||
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<String> 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<String> 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<String> 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of LuckPerms, licensed under the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||||
|
* 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<Sender> notify;
|
||||||
|
private final List<String> commandList;
|
||||||
|
private final List<ImportCommand> commands;
|
||||||
|
|
||||||
|
public LegacyImporter(CommandManager commandManager, Sender executor, List<String> 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<Void> 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<String, ImportCommand> 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<CompletableFuture<Void>> futures = new HashSet<>();
|
||||||
|
|
||||||
|
AtomicInteger processedCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
// iterate through each user sublist.
|
||||||
|
for (Collection<ImportCommand> 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<Void> 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<String> 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<String> 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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -61,11 +61,11 @@ import me.lucko.luckperms.common.locale.message.Message;
|
|||||||
import me.lucko.luckperms.common.model.Group;
|
import me.lucko.luckperms.common.model.Group;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.query.QueryOptions;
|
import net.luckperms.api.query.QueryOptions;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -276,16 +276,9 @@ public class CommandManager {
|
|||||||
.forEach(c -> {
|
.forEach(c -> {
|
||||||
String permission = c.getPermission().map(CommandPermission::getPermission).orElse("None");
|
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 -> {
|
.toBuilder().applyDeep(comp -> {
|
||||||
comp.hoverEvent(HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
|
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)));
|
||||||
"&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)));
|
comp.clickEvent(ClickEvent.suggestCommand(String.format(c.getUsage(), label)));
|
||||||
}).build();
|
}).build();
|
||||||
sender.sendMessage(component);
|
sender.sendMessage(component);
|
||||||
|
@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataMutateResult;
|
import net.luckperms.api.model.DataMutateResult;
|
||||||
import net.luckperms.api.model.DataType;
|
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);
|
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()) {
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
import net.luckperms.api.model.TemporaryDataMutateResult;
|
import net.luckperms.api.model.TemporaryDataMutateResult;
|
||||||
@ -99,10 +99,7 @@ public class MetaAddTempChatMeta extends SharedSubCommand {
|
|||||||
duration = ret.getMergedNode().getExpiry().getEpochSecond();
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -43,12 +43,12 @@ import me.lucko.luckperms.common.node.factory.NodeCommandFactory;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.ComponentBuilder;
|
import net.kyori.text.ComponentBuilder;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Node;
|
import net.luckperms.api.node.Node;
|
||||||
import net.luckperms.api.node.NodeType;
|
import net.luckperms.api.node.NodeType;
|
||||||
import net.luckperms.api.node.metadata.types.InheritanceOriginMetadata;
|
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(
|
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()), '¥'));
|
||||||
"¥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();
|
String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName();
|
||||||
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
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(
|
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()), '¥'));
|
||||||
"¥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();
|
String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName();
|
||||||
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
||||||
|
@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.ImmutableContextSet;
|
import net.luckperms.api.context.ImmutableContextSet;
|
||||||
import net.luckperms.api.model.DataMutateResult;
|
import net.luckperms.api.model.DataMutateResult;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
@ -107,10 +107,7 @@ public class MetaRemoveChatMeta extends SharedSubCommand {
|
|||||||
|
|
||||||
if (result.wasSuccessful()) {
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -45,10 +45,10 @@ import me.lucko.luckperms.common.node.types.Suffix;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.ImmutableContextSet;
|
import net.luckperms.api.context.ImmutableContextSet;
|
||||||
import net.luckperms.api.model.DataMutateResult;
|
import net.luckperms.api.model.DataMutateResult;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
@ -107,10 +107,7 @@ public class MetaRemoveTempChatMeta extends SharedSubCommand {
|
|||||||
|
|
||||||
if (result.wasSuccessful()) {
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -44,10 +44,10 @@ import me.lucko.luckperms.common.node.types.Meta;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
import net.luckperms.api.node.Node;
|
import net.luckperms.api.node.Node;
|
||||||
@ -90,10 +90,7 @@ public class MetaSet extends SharedSubCommand {
|
|||||||
holder.setNode(DataType.NORMAL, node, true);
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), '¥'));
|
||||||
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ import me.lucko.luckperms.common.node.types.Suffix;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataMutateResult;
|
import net.luckperms.api.model.DataMutateResult;
|
||||||
import net.luckperms.api.model.DataType;
|
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);
|
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()) {
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -46,10 +46,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
import net.luckperms.api.model.TemporaryMergeBehaviour;
|
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();
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", "¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value), '¥'));
|
||||||
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -49,10 +49,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.context.MutableContextSet;
|
import net.luckperms.api.context.MutableContextSet;
|
||||||
import net.luckperms.api.model.DataType;
|
import net.luckperms.api.model.DataType;
|
||||||
import net.luckperms.api.model.TemporaryDataMutateResult;
|
import net.luckperms.api.model.TemporaryDataMutateResult;
|
||||||
@ -139,10 +139,7 @@ public class MetaSetTempChatMeta extends SharedSubCommand {
|
|||||||
duration = ret.getMergedNode().getExpiry().getEpochSecond();
|
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();
|
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(
|
HoverEvent event = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize("¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta, '¥'));
|
||||||
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
|
|
||||||
'¥'
|
|
||||||
));
|
|
||||||
builder.applyDeep(c -> c.hoverEvent(event));
|
builder.applyDeep(c -> c.hoverEvent(event));
|
||||||
sender.sendMessage(builder.build());
|
sender.sendMessage(builder.build());
|
||||||
|
|
||||||
|
@ -46,12 +46,12 @@ import me.lucko.luckperms.common.sender.Sender;
|
|||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Iterators;
|
import me.lucko.luckperms.common.util.Iterators;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.ComponentBuilder;
|
import net.kyori.text.ComponentBuilder;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.types.InheritanceNode;
|
import net.luckperms.api.node.types.InheritanceNode;
|
||||||
import net.luckperms.api.query.QueryOptions;
|
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());
|
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);
|
sender.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +137,7 @@ public class ParentInfo extends SharedSubCommand {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static Consumer<ComponentBuilder<? ,?>> makeFancy(PermissionHolder holder, String label, InheritanceNode node) {
|
private static Consumer<ComponentBuilder<? ,?>> makeFancy(PermissionHolder holder, String label, InheritanceNode node) {
|
||||||
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
|
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));
|
||||||
"&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();
|
String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName();
|
||||||
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
||||||
|
@ -46,12 +46,12 @@ import me.lucko.luckperms.common.sender.Sender;
|
|||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Iterators;
|
import me.lucko.luckperms.common.util.Iterators;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.ComponentBuilder;
|
import net.kyori.text.ComponentBuilder;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Node;
|
import net.luckperms.api.node.Node;
|
||||||
import net.luckperms.api.node.NodeType;
|
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());
|
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);
|
sender.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +137,8 @@ public class PermissionInfo extends SharedSubCommand {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static Consumer<ComponentBuilder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
|
private static Consumer<ComponentBuilder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
|
||||||
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
|
String[] strings = new String[]{"¥3> " + (node.getValue() ? "¥a" : "¥c") + node.getKey(), " ", "¥7Click to remove this node from " + holder.getFormattedDisplayName()};
|
||||||
"¥3> " + (node.getValue() ? "¥a" : "¥c") + node.getKey(),
|
HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", strings), '¥'));
|
||||||
" ",
|
|
||||||
"¥7Click to remove this node from " + holder.getFormattedDisplayName()
|
|
||||||
), '¥'));
|
|
||||||
|
|
||||||
String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName();
|
String id = holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName();
|
||||||
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
boolean explicitGlobalContext = !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
||||||
|
@ -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.locale.message.Message;
|
||||||
import me.lucko.luckperms.common.model.Group;
|
import me.lucko.luckperms.common.model.Group;
|
||||||
import me.lucko.luckperms.common.model.HolderType;
|
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.factory.NodeCommandFactory;
|
||||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
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.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Iterators;
|
import me.lucko.luckperms.common.util.Iterators;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.ComponentBuilder;
|
import net.kyori.text.ComponentBuilder;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.HeldNode;
|
import net.luckperms.api.node.HeldNode;
|
||||||
import net.luckperms.api.node.Node;
|
import net.luckperms.api.node.Node;
|
||||||
import net.luckperms.api.node.types.InheritanceNode;
|
import net.luckperms.api.node.types.InheritanceNode;
|
||||||
@ -127,7 +127,7 @@ public class GroupListMembers extends SubCommand<Group> {
|
|||||||
|
|
||||||
private static <T extends Comparable<T>> void sendResult(Sender sender, List<HeldNode<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
|
private static <T extends Comparable<T>> void sendResult(Sender sender, List<HeldNode<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
|
||||||
results = new ArrayList<>(results);
|
results = new ArrayList<>(results);
|
||||||
results.sort(HeldPermissionComparator.normal());
|
results.sort(HeldNodeComparator.normal());
|
||||||
|
|
||||||
int pageIndex = page - 1;
|
int pageIndex = page - 1;
|
||||||
List<List<HeldNode<T>>> pages = Iterators.divideIterable(results, 15);
|
List<List<HeldNode<T>>> pages = Iterators.divideIterable(results, 15);
|
||||||
@ -148,7 +148,7 @@ public class GroupListMembers extends SubCommand<Group> {
|
|||||||
|
|
||||||
for (Map.Entry<String, HeldNode<T>> ent : mappedContent) {
|
for (Map.Entry<String, HeldNode<T>> ent : mappedContent) {
|
||||||
String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().getNode()) + MessageUtils.getAppendableNodeContextString(sender.getPlugin().getLocaleManager(), ent.getValue().getNode());
|
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);
|
sender.sendMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,11 +162,7 @@ public class GroupListMembers extends SubCommand<Group> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Consumer<ComponentBuilder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldNode<?> perm, LuckPermsPlugin plugin) {
|
private static Consumer<ComponentBuilder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldNode<?> perm, LuckPermsPlugin plugin) {
|
||||||
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
|
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));
|
||||||
"&3> &b" + ((InheritanceNode) perm.getNode()).getGroupName(),
|
|
||||||
" ",
|
|
||||||
"&7Click to remove this parent from " + holderName
|
|
||||||
), CommandManager.AMPERSAND_CHAR));
|
|
||||||
|
|
||||||
boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
||||||
String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext);
|
String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext);
|
||||||
|
@ -44,6 +44,7 @@ import me.lucko.luckperms.common.model.Group;
|
|||||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||||
import me.lucko.luckperms.common.model.Track;
|
import me.lucko.luckperms.common.model.Track;
|
||||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
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.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
@ -162,7 +163,7 @@ public class ApplyEditsCommand extends SingleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Set<Node> before = new HashSet<>(holder.normalData().immutable().values());
|
Set<Node> before = new HashSet<>(holder.normalData().immutable().values());
|
||||||
Set<Node> after = new HashSet<>(WebEditor.deserializePermissions(data.getAsJsonArray("nodes")));
|
Set<Node> after = new HashSet<>(NodeJsonSerializer.deserializeNodes(data.getAsJsonArray("nodes")));
|
||||||
|
|
||||||
Map.Entry<Set<Node>, Set<Node>> diff = diff(before, after);
|
Map.Entry<Set<Node>, Set<Node>> diff = diff(before, after);
|
||||||
Set<Node> diffAdded = diff.getKey();
|
Set<Node> diffAdded = diff.getKey();
|
||||||
|
@ -57,9 +57,9 @@ public class ExportCommand extends SingleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Path dataDirectory = plugin.getBootstrap().getDataDirectory();
|
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());
|
Message.FILE_NOT_WITHIN_DIRECTORY.send(sender, path.toString());
|
||||||
return CommandResult.INVALID_ARGS;
|
return CommandResult.INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,10 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.commands.misc;
|
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.Importer;
|
||||||
|
import me.lucko.luckperms.common.backup.LegacyImporter;
|
||||||
import me.lucko.luckperms.common.command.CommandResult;
|
import me.lucko.luckperms.common.command.CommandResult;
|
||||||
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
|
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
|
||||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
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.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
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.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
public class ImportCommand extends SingleCommand {
|
public class ImportCommand extends SingleCommand {
|
||||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||||
@ -57,8 +64,13 @@ public class ImportCommand extends SingleCommand {
|
|||||||
return CommandResult.STATE_ERROR;
|
return CommandResult.STATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String fileName = args.get(0);
|
||||||
|
if (!fileName.contains(".")) {
|
||||||
|
fileName += ".json.gz";
|
||||||
|
}
|
||||||
|
|
||||||
Path dataDirectory = plugin.getBootstrap().getDataDirectory();
|
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")) {
|
if (!path.getParent().equals(dataDirectory) || path.getFileName().toString().equals("config.yml")) {
|
||||||
Message.FILE_NOT_WITHIN_DIRECTORY.send(sender, path.toString());
|
Message.FILE_NOT_WITHIN_DIRECTORY.send(sender, path.toString());
|
||||||
@ -66,40 +78,68 @@ public class ImportCommand extends SingleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Files.exists(path)) {
|
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;
|
return CommandResult.INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Files.isReadable(path)) {
|
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;
|
return CommandResult.FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> commands;
|
if (!fileName.endsWith(".json.gz")) {
|
||||||
|
// legacy
|
||||||
try {
|
List<String> commands;
|
||||||
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(() -> {
|
|
||||||
try {
|
try {
|
||||||
importer.run();
|
commands = Files.readAllLines(path, StandardCharsets.UTF_8);
|
||||||
} finally {
|
} catch (IOException e) {
|
||||||
this.running.set(false);
|
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;
|
return CommandResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -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.command.CommandSpec;
|
||||||
import me.lucko.luckperms.common.locale.message.Message;
|
import me.lucko.luckperms.common.locale.message.Message;
|
||||||
import me.lucko.luckperms.common.model.HolderType;
|
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.factory.NodeCommandFactory;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.Iterators;
|
import me.lucko.luckperms.common.util.Iterators;
|
||||||
import me.lucko.luckperms.common.util.Predicates;
|
import me.lucko.luckperms.common.util.Predicates;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.ComponentBuilder;
|
import net.kyori.text.ComponentBuilder;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.event.ClickEvent;
|
import net.kyori.text.event.ClickEvent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.HeldNode;
|
import net.luckperms.api.node.HeldNode;
|
||||||
import net.luckperms.api.node.Node;
|
import net.luckperms.api.node.Node;
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ public class SearchCommand extends SingleCommand {
|
|||||||
|
|
||||||
private static <T extends Comparable<T>> void sendResult(Sender sender, List<HeldNode<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page, Comparison comparison) {
|
private static <T extends Comparable<T>> void sendResult(Sender sender, List<HeldNode<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page, Comparison comparison) {
|
||||||
results = new ArrayList<>(results);
|
results = new ArrayList<>(results);
|
||||||
results.sort(HeldPermissionComparator.normal());
|
results.sort(HeldNodeComparator.normal());
|
||||||
|
|
||||||
int pageIndex = page - 1;
|
int pageIndex = page - 1;
|
||||||
List<List<HeldNode<T>>> pages = Iterators.divideIterable(results, 15);
|
List<List<HeldNode<T>>> 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());
|
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);
|
sender.sendMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,11 +170,8 @@ public class SearchCommand extends SingleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Consumer<ComponentBuilder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldNode<?> perm, LuckPermsPlugin plugin) {
|
private static Consumer<ComponentBuilder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldNode<?> perm, LuckPermsPlugin plugin) {
|
||||||
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
|
String[] strings = new String[]{"&3> " + (perm.getNode().getValue() ? "&a" : "&c") + perm.getNode().getKey(), " ", "&7Click to remove this node from " + holderName};
|
||||||
"&3> " + (perm.getNode().getValue() ? "&a" : "&c") + perm.getNode().getKey(),
|
HoverEvent hoverEvent = HoverEvent.showText(LegacyComponentSerializer.INSTANCE.deserialize(String.join("\n", strings), CommandManager.AMPERSAND_CHAR));
|
||||||
" ",
|
|
||||||
"&7Click to remove this node from " + holderName
|
|
||||||
), CommandManager.AMPERSAND_CHAR));
|
|
||||||
|
|
||||||
boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
boolean explicitGlobalContext = !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty();
|
||||||
String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext);
|
String command = "/" + label + " " + NodeCommandFactory.generateCommand(perm.getNode(), holderName, holderType, false, explicitGlobalContext);
|
||||||
|
@ -28,9 +28,9 @@ package me.lucko.luckperms.common.locale.message;
|
|||||||
import me.lucko.luckperms.common.command.CommandManager;
|
import me.lucko.luckperms.common.command.CommandManager;
|
||||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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),
|
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),
|
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),
|
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_FILE_DOESNT_EXIST("&cError: File &4{}&c does not exist.", true),
|
||||||
IMPORT_LOG_NOT_READABLE("&cError: File &4{}&c is not readable.", true),
|
IMPORT_FILE_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_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("&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),
|
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) {
|
Message(String message, boolean showPrefix) {
|
||||||
// rewrite hardcoded placeholders according to their position
|
// rewrite hardcoded placeholders according to their position
|
||||||
this.message = TextUtils.rewritePlaceholders(message);
|
this.message = rewritePlaceholders(message);
|
||||||
this.showPrefix = showPrefix;
|
this.showPrefix = showPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String rewritePlaceholders(String input) {
|
||||||
|
int i = 0;
|
||||||
|
while (input.contains("{}")) {
|
||||||
|
input = input.replaceFirst("\\{\\}", "{" + i++ + "}");
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return this.message;
|
return this.message;
|
||||||
}
|
}
|
||||||
@ -517,7 +525,7 @@ public enum Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextComponent asComponent(@Nullable LocaleManager localeManager, Object... objects) {
|
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) {
|
public void send(Sender sender, Object... objects) {
|
||||||
|
@ -29,14 +29,14 @@ import net.luckperms.api.node.HeldNode;
|
|||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class HeldPermissionComparator<T extends Comparable<T>> implements Comparator<HeldNode<T>> {
|
public class HeldNodeComparator<T extends Comparable<T>> implements Comparator<HeldNode<T>> {
|
||||||
|
|
||||||
public static <T extends Comparable<T>> Comparator<? super HeldNode<T>> normal() {
|
public static <T extends Comparable<T>> Comparator<? super HeldNode<T>> normal() {
|
||||||
return new HeldPermissionComparator<>();
|
return new HeldNodeComparator<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Comparable<T>> Comparator<? super HeldNode<T>> reverse() {
|
public static <T extends Comparable<T>> Comparator<? super HeldNode<T>> reverse() {
|
||||||
return HeldPermissionComparator.<T>normal().reversed();
|
return HeldNodeComparator.<T>normal().reversed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -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<Node> 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<Node> deserializeNodes(JsonArray arr) {
|
||||||
|
Set<Node> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -28,9 +28,9 @@ package me.lucko.luckperms.common.sender;
|
|||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -93,7 +93,7 @@ public final class AbstractSender<T> implements Sender {
|
|||||||
@Override
|
@Override
|
||||||
public void sendMessage(Component message) {
|
public void sendMessage(Component message) {
|
||||||
if (isConsole()) {
|
if (isConsole()) {
|
||||||
sendMessage(TextUtils.toLegacy(message));
|
sendMessage(LegacyComponentSerializer.INSTANCE.serialize(message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
package me.lucko.luckperms.common.sender;
|
package me.lucko.luckperms.common.sender;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -58,7 +58,7 @@ public abstract class DummySender implements Sender {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Component message) {
|
public void sendMessage(Component message) {
|
||||||
consumeMessage(TextUtils.toLegacy(message));
|
consumeMessage(LegacyComponentSerializer.INSTANCE.serialize(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of LuckPerms, licensed under the MIT License.
|
|
||||||
*
|
|
||||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
|
||||||
* 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<String> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ import me.lucko.luckperms.common.locale.message.Message;
|
|||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.DurationFormatter;
|
import me.lucko.luckperms.common.util.DurationFormatter;
|
||||||
import me.lucko.luckperms.common.util.StackTracePrinter;
|
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.GsonProvider;
|
||||||
import me.lucko.luckperms.common.util.gson.JArray;
|
import me.lucko.luckperms.common.util.gson.JArray;
|
||||||
import me.lucko.luckperms.common.util.gson.JObject;
|
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.TextComponent;
|
||||||
import net.kyori.text.event.HoverEvent;
|
import net.kyori.text.event.HoverEvent;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
import net.luckperms.api.query.QueryMode;
|
import net.luckperms.api.query.QueryMode;
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -232,7 +233,7 @@ public class VerboseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send the message
|
// 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();
|
TextComponent text = textComponent.toBuilder().applyDeep(comp -> comp.hoverEvent(hoverEvent)).build();
|
||||||
this.notifiedSender.sendMessage(text);
|
this.notifiedSender.sendMessage(text);
|
||||||
}
|
}
|
||||||
|
@ -26,23 +26,18 @@
|
|||||||
package me.lucko.luckperms.common.web;
|
package me.lucko.luckperms.common.web;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.context.ContextSetJsonSerializer;
|
import me.lucko.luckperms.common.context.ContextSetJsonSerializer;
|
||||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||||
import me.lucko.luckperms.common.model.Track;
|
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.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.util.gson.GsonProvider;
|
import me.lucko.luckperms.common.util.gson.GsonProvider;
|
||||||
import me.lucko.luckperms.common.util.gson.JArray;
|
import me.lucko.luckperms.common.util.gson.JArray;
|
||||||
import me.lucko.luckperms.common.util.gson.JObject;
|
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.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
@ -52,11 +47,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for interacting with the LuckPerms web permission editor.
|
* Utility methods for interacting with the LuckPerms web permission editor.
|
||||||
@ -69,7 +60,7 @@ public final class WebEditor {
|
|||||||
.add("type", holder.getType().toString())
|
.add("type", holder.getType().toString())
|
||||||
.add("id", holder.getObjectName())
|
.add("id", holder.getObjectName())
|
||||||
.add("displayName", holder.getPlainDisplayName())
|
.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) {
|
private static JObject writeData(Track track) {
|
||||||
@ -143,50 +134,4 @@ public final class WebEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonArray serializePermissions(Collection<Node> 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<Node> deserializePermissions(JsonArray arr) {
|
|
||||||
Set<Node> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ package me.lucko.luckperms.nukkit;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
|
|
||||||
import cn.nukkit.Player;
|
import cn.nukkit.Player;
|
||||||
@ -75,7 +75,7 @@ public class NukkitSenderFactory extends SenderFactory<CommandSender> {
|
|||||||
@Override
|
@Override
|
||||||
protected void sendMessage(CommandSender sender, Component message) {
|
protected void sendMessage(CommandSender sender, Component message) {
|
||||||
// Fallback to legacy format
|
// Fallback to legacy format
|
||||||
sendMessage(sender, TextUtils.toLegacy(message));
|
sendMessage(sender, LegacyComponentSerializer.INSTANCE.serialize(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,10 +31,10 @@ import com.velocitypowered.api.proxy.Player;
|
|||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.sender.Sender;
|
import me.lucko.luckperms.common.sender.Sender;
|
||||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||||
import me.lucko.luckperms.common.util.TextUtils;
|
|
||||||
import me.lucko.luckperms.velocity.service.CompatibilityUtil;
|
import me.lucko.luckperms.velocity.service.CompatibilityUtil;
|
||||||
|
|
||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.luckperms.api.node.Tristate;
|
import net.luckperms.api.node.Tristate;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -62,7 +62,7 @@ public class VelocitySenderFactory extends SenderFactory<CommandSource> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void sendMessage(CommandSource source, String s) {
|
protected void sendMessage(CommandSource source, String s) {
|
||||||
sendMessage(source, TextUtils.fromLegacy(s));
|
sendMessage(source, LegacyComponentSerializer.INSTANCE.deserialize(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user